diff options
963 files changed, 13108 insertions, 6995 deletions
diff --git a/Cargo.lock b/Cargo.lock index 04bb96be369..77653530925 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ dependencies = [ "cfg-if", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -567,7 +567,7 @@ dependencies = [ "termize", "tokio", "toml 0.7.8", - "ui_test", + "ui_test 0.26.5", "walkdir", ] @@ -1442,7 +1442,19 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", ] [[package]] @@ -2342,18 +2354,18 @@ dependencies = [ "chrono-tz", "colored", "directories", - "getrandom", + "getrandom 0.3.1", "libc", "libffi", "libloading", "measureme", - "rand", + "rand 0.9.0", "regex", "rustc_version", "smallvec", "tempfile", "tikv-jemalloc-sys", - "ui_test", + "ui_test 0.28.0", "windows-sys 0.52.0", ] @@ -2782,7 +2794,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" dependencies = [ "phf_shared 0.10.0", - "rand", + "rand 0.8.5", ] [[package]] @@ -2792,7 +2804,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared 0.11.3", - "rand", + "rand 0.8.5", ] [[package]] @@ -2860,7 +2872,7 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -2978,8 +2990,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.0", + "zerocopy 0.8.14", ] [[package]] @@ -2989,7 +3012,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.0", ] [[package]] @@ -2998,7 +3031,17 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", +] + +[[package]] +name = "rand_core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" +dependencies = [ + "getrandom 0.3.1", + "zerocopy 0.8.14", ] [[package]] @@ -3007,7 +3050,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" dependencies = [ - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -3045,7 +3088,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom", + "getrandom 0.2.15", "libredox", "thiserror 1.0.69", ] @@ -3283,7 +3326,7 @@ name = "rustc_abi" version = "0.0.0" dependencies = [ "bitflags", - "rand", + "rand 0.8.5", "rand_xoshiro", "rustc_data_structures", "rustc_feature", @@ -3897,7 +3940,7 @@ dependencies = [ name = "rustc_incremental" version = "0.0.0" dependencies = [ - "rand", + "rand 0.8.5", "rustc_ast", "rustc_data_structures", "rustc_errors", @@ -4234,6 +4277,7 @@ name = "rustc_monomorphize" version = "0.0.0" dependencies = [ "rustc_abi", + "rustc_ast", "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", @@ -4243,6 +4287,7 @@ dependencies = [ "rustc_middle", "rustc_session", "rustc_span", + "rustc_symbol_mangling", "rustc_target", "serde", "serde_json", @@ -5216,7 +5261,7 @@ checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if", "fastrand", - "getrandom", + "getrandom 0.2.15", "once_cell", "rustix", "windows-sys 0.59.0", @@ -5279,8 +5324,8 @@ version = "0.1.0" dependencies = [ "indicatif", "num", - "rand", - "rand_chacha", + "rand 0.8.5", + "rand_chacha 0.3.1", "rayon", ] @@ -5600,7 +5645,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", - "rand", + "rand 0.8.5", "static_assertions", ] @@ -5661,6 +5706,32 @@ dependencies = [ ] [[package]] +name = "ui_test" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7484683d60d50ca1d1b6433c3dbf6c5ad71d20387acdcfb16fe79573f3fba576" +dependencies = [ + "annotate-snippets 0.11.5", + "anyhow", + "bstr", + "cargo-platform", + "cargo_metadata 0.18.1", + "color-eyre", + "colored", + "comma", + "crossbeam-channel", + "indicatif", + "levenshtein", + "prettydiff", + "regex", + "rustc_version", + "rustfix", + "serde", + "serde_json", + "spanned", +] + +[[package]] name = "unic-langid" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5841,7 +5912,7 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "744018581f9a3454a9e15beb8a33b017183f1e7c0cd170232a2d1453b23a51c4" dependencies = [ - "getrandom", + "getrandom 0.2.15", ] [[package]] @@ -5879,6 +5950,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] name = "wasi-preview1-component-adapter-provider" version = "29.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6474,6 +6554,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ab703352da6a72f35c39a533526393725640575bb211f61987a2748323ad956" [[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags", +] + +[[package]] name = "wit-component" version = "0.223.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6582,7 +6671,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a367f292d93d4eab890745e75a778da40909cab4d6ff8173693812f79c4a2468" +dependencies = [ + "zerocopy-derive 0.8.14", ] [[package]] @@ -6597,6 +6695,17 @@ dependencies = [ ] [[package]] +name = "zerocopy-derive" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3931cb58c62c13adec22e38686b559c86a30565e16ad6e8510a337cedc611e1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] name = "zerofrom" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/RELEASES.md b/RELEASES.md index 2da6ed3f100..1dd3fbea613 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,8 +1,22 @@ +Version 1.84.1 (2025-01-30) +========================== + +<a id="1.84.1"></a> + +- [Fix ICE 132920 in duplicate-crate diagnostics.](https://github.com/rust-lang/rust/pull/133304/) +- [Fix errors for overlapping impls in incremental rebuilds.](https://github.com/rust-lang/rust/pull/133828/) +- [Fix slow compilation related to the next-generation trait solver.](https://github.com/rust-lang/rust/pull/135618/) +- [Fix debuginfo when LLVM's location discriminator value limit is exceeded.](https://github.com/rust-lang/rust/pull/135643/) +- Fixes for building Rust from source: + - [Only try to distribute `llvm-objcopy` if llvm tools are enabled.](https://github.com/rust-lang/rust/pull/134240/) + - [Add Profile Override for Non-Git Sources.](https://github.com/rust-lang/rust/pull/135433/) + - [Resolve symlinks of LLVM tool binaries before copying them.](https://github.com/rust-lang/rust/pull/135585/) + - [Make it possible to use ci-rustc on tarball sources.](https://github.com/rust-lang/rust/pull/135722/) + Version 1.84.0 (2025-01-09) ========================== -<a id=" -Language"></a> +<a id="1.84.0-Language"></a> Language -------- diff --git a/REUSE.toml b/REUSE.toml index 6b16d97ed80..9e873e94eff 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -92,7 +92,7 @@ SPDX-FileCopyrightText = "2015 Anders Kaseorg <andersk@mit.edu>" SPDX-License-Identifier = "MIT" [[annotations]] -path = "src/librustdoc/html/static/fonts/FiraSans**" +path = "src/librustdoc/html/static/fonts/Fira**" precedence = "override" SPDX-FileCopyrightText = ["2014, Mozilla Foundation", "2014, Telefonica S.A."] SPDX-License-Identifier = "OFL-1.1" diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index ad942e9b494..b6f331d316c 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1657,7 +1657,7 @@ impl GenBlockKind { } /// Whether we're unwrapping or wrapping an unsafe binder -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(Encodable, Decodable, HashStable_Generic)] pub enum UnsafeBinderCastKind { // e.g. `&i32` -> `unsafe<'a> &'a i32` diff --git a/compiler/rustc_ast/src/expand/autodiff_attrs.rs b/compiler/rustc_ast/src/expand/autodiff_attrs.rs index 7ef8bc17973..ecc522ec39d 100644 --- a/compiler/rustc_ast/src/expand/autodiff_attrs.rs +++ b/compiler/rustc_ast/src/expand/autodiff_attrs.rs @@ -79,6 +79,7 @@ pub struct AutoDiffItem { pub target: String, pub attrs: AutoDiffAttrs, } + #[derive(Clone, Eq, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub struct AutoDiffAttrs { /// Conceptually either forward or reverse mode AD, as described in various autodiff papers and @@ -231,7 +232,7 @@ impl AutoDiffAttrs { self.ret_activity == DiffActivity::ActiveOnly } - pub fn error() -> Self { + pub const fn error() -> Self { AutoDiffAttrs { mode: DiffMode::Error, ret_activity: DiffActivity::None, diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 3b7367d1ee2..100f664a89f 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -527,13 +527,13 @@ impl TokenKind { /// Returns tokens that are likely to be typed accidentally instead of the current token. /// Enables better error recovery when the wrong token is found. - pub fn similar_tokens(&self) -> Option<Vec<TokenKind>> { - match *self { - Comma => Some(vec![Dot, Lt, Semi]), - Semi => Some(vec![Colon, Comma]), - Colon => Some(vec![Semi]), - FatArrow => Some(vec![Eq, RArrow, Ge, Gt]), - _ => None, + pub fn similar_tokens(&self) -> &[TokenKind] { + match self { + Comma => &[Dot, Lt, Semi], + Semi => &[Colon, Comma], + Colon => &[Semi], + FatArrow => &[Eq, RArrow, Ge, Gt], + _ => &[], } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index b9f1a4220b8..893da930855 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -418,10 +418,10 @@ fn compute_hir_hash( pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> { let sess = tcx.sess; // Queries that borrow `resolver_for_lowering`. - tcx.ensure_with_value().output_filenames(()); - tcx.ensure_with_value().early_lint_checks(()); - tcx.ensure_with_value().debugger_visualizers(LOCAL_CRATE); - tcx.ensure_with_value().get_lang_items(()); + tcx.ensure_done().output_filenames(()); + tcx.ensure_done().early_lint_checks(()); + tcx.ensure_done().debugger_visualizers(LOCAL_CRATE); + tcx.ensure_done().get_lang_items(()); let (mut resolver, krate) = tcx.resolver_for_lowering().steal(); let ast_index = index_crate(&resolver.node_id_to_def_id, &krate); diff --git a/compiler/rustc_attr_data_structures/src/stability.rs b/compiler/rustc_attr_data_structures/src/stability.rs index dfda04387ec..c2213fc9ed8 100644 --- a/compiler/rustc_attr_data_structures/src/stability.rs +++ b/compiler/rustc_attr_data_structures/src/stability.rs @@ -101,16 +101,6 @@ impl PartialConstStability { } } -#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] -#[derive(HashStable_Generic)] -pub enum AllowedThroughUnstableModules { - /// This does not get a deprecation warning. We still generally would prefer people to use the - /// fully stable path, and a warning will likely be emitted in the future. - WithoutDeprecation, - /// Emit the given deprecation warning. - WithDeprecation(Symbol), -} - /// The available stability levels. #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] #[derive(HashStable_Generic)] @@ -147,8 +137,9 @@ pub enum StabilityLevel { Stable { /// Rust release which stabilized this feature. since: StableSince, - /// This is `Some` if this item allowed to be referred to on stable via unstable modules. - allowed_through_unstable_modules: Option<AllowedThroughUnstableModules>, + /// This is `Some` if this item allowed to be referred to on stable via unstable modules; + /// the `Symbol` is the deprecation message printed in that case. + allowed_through_unstable_modules: Option<Symbol>, }, } diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index bfbe51b27d8..454b8b5de82 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -6,12 +6,12 @@ use rustc_ast::MetaItem; use rustc_ast::attr::AttributeExt; use rustc_ast_pretty::pprust; use rustc_attr_data_structures::{ - AllowedThroughUnstableModules, ConstStability, DefaultBodyStability, Stability, StabilityLevel, - StableSince, UnstableReason, VERSION_PLACEHOLDER, + ConstStability, DefaultBodyStability, Stability, StabilityLevel, StableSince, UnstableReason, + VERSION_PLACEHOLDER, }; use rustc_errors::ErrorGuaranteed; use rustc_session::Session; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol, kw, sym}; use crate::attributes::util::UnsupportedLiteralReason; use crate::{parse_version, session_diagnostics}; @@ -29,10 +29,14 @@ pub fn find_stability( for attr in attrs { match attr.name_or_empty() { sym::rustc_allowed_through_unstable_modules => { - allowed_through_unstable_modules = Some(match attr.value_str() { - Some(msg) => AllowedThroughUnstableModules::WithDeprecation(msg), - None => AllowedThroughUnstableModules::WithoutDeprecation, - }) + // The value is mandatory, but avoid ICEs in case such code reaches this function. + allowed_through_unstable_modules = Some(attr.value_str().unwrap_or_else(|| { + sess.dcx().span_delayed_bug( + item_sp, + "`#[rustc_allowed_through_unstable_modules]` without deprecation message", + ); + kw::Empty + })) } sym::unstable => { if stab.is_some() { diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl index c00e6dde919..ada20e5c614 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -92,9 +92,6 @@ borrowck_lifetime_constraints_error = borrowck_limitations_implies_static = due to current limitations in the borrow checker, this implies a `'static` lifetime -borrowck_long_type_consider_verbose = consider using `--verbose` to print the full type name to the console -borrowck_long_type_full_path = the full type name has been written to '{$path}' - borrowck_move_closure_suggestion = consider adding 'move' keyword before the nested closure diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 07dcbba019a..dc4e49972ca 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -289,8 +289,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { None => "value".to_owned(), }; if needs_note { - let mut path = None; - let ty = self.infcx.tcx.short_ty_string(ty, &mut path); + let ty = self.infcx.tcx.short_string(ty, err.long_ty_path()); if let Some(local) = place.as_local() { let span = self.body.local_decls[local].source_info.span; err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { @@ -306,11 +305,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { place: ¬e_msg, }); }; - if let Some(path) = path { - err.subdiagnostic(crate::session_diagnostics::LongTypePath { - path: path.display().to_string(), - }); - } } if let UseSpans::FnSelfUse { @@ -3777,7 +3771,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let tcx = self.infcx.tcx; if let Some(Terminator { kind: TerminatorKind::Call { call_source, fn_span, .. }, .. }) = &self.body[loan.reserve_location.block].terminator - && let Some((method_did, method_args)) = rustc_middle::util::find_self_call( + && let Some((method_did, method_args)) = mir::find_self_call( tcx, self.body, loan.assigned_place.local, @@ -3915,7 +3909,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Subtype(_) - | ProjectionElem::Index(_) => kind, + | ProjectionElem::Index(_) + | ProjectionElem::UnwrapUnsafeBinder(_) => kind, }, place_ty.projection_ty(tcx, elem), ) diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 2656e0bb6a4..841cb782bc3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -248,7 +248,98 @@ impl<'tcx> BorrowExplanation<'tcx> { ); err.span_label(body.source_info(drop_loc).span, message); - if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() { + struct FindLetExpr<'hir> { + span: Span, + result: Option<(Span, &'hir hir::Pat<'hir>, &'hir hir::Expr<'hir>)>, + tcx: TyCtxt<'hir>, + } + + impl<'hir> rustc_hir::intravisit::Visitor<'hir> for FindLetExpr<'hir> { + type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies; + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() + } + fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { + if let hir::ExprKind::If(cond, _conseq, _alt) + | hir::ExprKind::Loop( + hir::Block { + expr: + Some(&hir::Expr { + kind: hir::ExprKind::If(cond, _conseq, _alt), + .. + }), + .. + }, + _, + hir::LoopSource::While, + _, + ) = expr.kind + && let hir::ExprKind::Let(hir::LetExpr { + init: let_expr_init, + span: let_expr_span, + pat: let_expr_pat, + .. + }) = cond.kind + && let_expr_init.span.contains(self.span) + { + self.result = + Some((*let_expr_span, let_expr_pat, let_expr_init)) + } else { + hir::intravisit::walk_expr(self, expr); + } + } + } + + if let &LocalInfo::IfThenRescopeTemp { if_then } = local_decl.local_info() + && let hir::Node::Expr(expr) = tcx.hir_node(if_then) + && let hir::ExprKind::If(cond, conseq, alt) = expr.kind + && let hir::ExprKind::Let(&hir::LetExpr { + span: _, + pat, + init, + // FIXME(#101728): enable rewrite when type ascription is + // stabilized again. + ty: None, + recovered: _, + }) = cond.kind + && pat.span.can_be_used_for_suggestions() + && let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span) + { + suggest_rewrite_if_let(tcx, expr, &pat, init, conseq, alt, err); + } else if let Some((old, new)) = multiple_borrow_span + && let def_id = body.source.def_id() + && let Some(node) = tcx.hir().get_if_local(def_id) + && let Some(body_id) = node.body_id() + && let hir_body = tcx.hir().body(body_id) + && let mut expr_finder = (FindLetExpr { span: old, result: None, tcx }) + && let Some((let_expr_span, let_expr_pat, let_expr_init)) = { + expr_finder.visit_expr(hir_body.value); + expr_finder.result + } + && !let_expr_span.contains(new) + { + // #133941: The `old` expression is at the conditional part of an + // if/while let expression. Adding a semicolon won't work. + // Instead, try suggesting the `matches!` macro or a temporary. + if let_expr_pat + .walk_short(|pat| !matches!(pat.kind, hir::PatKind::Binding(..))) + { + if let Ok(pat_snippet) = + tcx.sess.source_map().span_to_snippet(let_expr_pat.span) + && let Ok(init_snippet) = + tcx.sess.source_map().span_to_snippet(let_expr_init.span) + { + err.span_suggestion_verbose( + let_expr_span, + "consider using the `matches!` macro", + format!("matches!({init_snippet}, {pat_snippet})"), + Applicability::MaybeIncorrect, + ); + } else { + err.note("consider using the `matches!` macro"); + } + } + } else if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() { if info.tail_result_is_ignored { // #85581: If the first mutable borrow's scope contains // the second borrow, this suggestion isn't helpful. @@ -281,23 +372,6 @@ impl<'tcx> BorrowExplanation<'tcx> { Applicability::MaybeIncorrect, ); }; - } else if let &LocalInfo::IfThenRescopeTemp { if_then } = - local_decl.local_info() - && let hir::Node::Expr(expr) = tcx.hir_node(if_then) - && let hir::ExprKind::If(cond, conseq, alt) = expr.kind - && let hir::ExprKind::Let(&hir::LetExpr { - span: _, - pat, - init, - // FIXME(#101728): enable rewrite when type ascription is - // stabilized again. - ty: None, - recovered: _, - }) = cond.kind - && pat.span.can_be_used_for_suggestions() - && let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span) - { - suggest_rewrite_if_let(tcx, expr, &pat, init, conseq, alt, err); } } } diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index bd6f77156ca..01ed0464c8a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -4,7 +4,7 @@ use std::collections::BTreeMap; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan}; +use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, listify}; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::{self as hir, CoroutineKind, LangItem}; use rustc_index::IndexSlice; @@ -17,7 +17,7 @@ use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ AggregateKind, CallSource, ConstOperand, ConstraintCategory, FakeReadCause, Local, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, - StatementKind, Terminator, TerminatorKind, + StatementKind, Terminator, TerminatorKind, find_self_call, }; use rustc_middle::ty::print::Print; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -29,7 +29,7 @@ use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::traits::call_kind::{CallDesugaringKind, call_kind}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{ - FulfillmentErrorCode, type_known_to_meet_bound_modulo_regions, + FulfillmentError, FulfillmentErrorCode, type_known_to_meet_bound_modulo_regions, }; use tracing::debug; @@ -370,6 +370,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ProjectionElem::Downcast(..) => (), ProjectionElem::OpaqueCast(..) => (), ProjectionElem::Subtype(..) => (), + ProjectionElem::UnwrapUnsafeBinder(_) => (), ProjectionElem::Field(field, _ty) => { // FIXME(project-rfc_2229#36): print capture precisely here. if let Some(field) = self.is_upvar_field_projection(PlaceRef { @@ -450,9 +451,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx) } ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx), - ProjectionElem::Subtype(ty) | ProjectionElem::OpaqueCast(ty) => { - PlaceTy::from_ty(*ty) - } + ProjectionElem::Subtype(ty) + | ProjectionElem::OpaqueCast(ty) + | ProjectionElem::UnwrapUnsafeBinder(ty) => PlaceTy::from_ty(*ty), ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type), }, }; @@ -1016,12 +1017,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { kind: TerminatorKind::Call { fn_span, call_source, .. }, .. }) = &self.body[location.block].terminator { - let Some((method_did, method_args)) = rustc_middle::util::find_self_call( - self.infcx.tcx, - self.body, - target_temp, - location.block, - ) else { + let Some((method_did, method_args)) = + find_self_call(self.infcx.tcx, self.body, target_temp, location.block) + else { return normal_ret; }; @@ -1436,17 +1434,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { error.obligation.predicate, ) } - [errors @ .., last] => { + _ => { format!( "you could `clone` the value and consume it, if the \ - following trait bounds could be satisfied: \ - {} and `{}`", - errors - .iter() - .map(|e| format!("`{}`", e.obligation.predicate)) - .collect::<Vec<_>>() - .join(", "), - last.obligation.predicate, + following trait bounds could be satisfied: {}", + listify(&errors, |e: &FulfillmentError<'tcx>| format!( + "`{}`", + e.obligation.predicate + )) + .unwrap(), ) } }; diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 14a900f38e9..58c5c2fd774 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -596,19 +596,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.suggest_cloning(err, place_ty, expr, None); } - let mut path = None; - let ty = self.infcx.tcx.short_ty_string(place_ty, &mut path); + let ty = self.infcx.tcx.short_string(place_ty, err.long_ty_path()); err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { is_partial_move: false, ty, place: &place_desc, span, }); - if let Some(path) = path { - err.subdiagnostic(crate::session_diagnostics::LongTypePath { - path: path.display().to_string(), - }); - } } else { binds_to.sort(); binds_to.dedup(); @@ -635,19 +629,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.suggest_cloning(err, place_ty, expr, Some(use_spans)); } - let mut path = None; - let ty = self.infcx.tcx.short_ty_string(place_ty, &mut path); + let ty = self.infcx.tcx.short_string(place_ty, err.long_ty_path()); err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { is_partial_move: false, ty, place: &place_desc, span: use_span, }); - if let Some(path) = path { - err.subdiagnostic(crate::session_diagnostics::LongTypePath { - path: path.display().to_string(), - }); - } use_spans.args_subdiag(err, |args_span| { crate::session_diagnostics::CaptureArgLabel::MoveOutPlace { @@ -845,19 +833,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.suggest_cloning(err, bind_to.ty, expr, None); } - let mut path = None; - let ty = self.infcx.tcx.short_ty_string(bind_to.ty, &mut path); + let ty = self.infcx.tcx.short_string(bind_to.ty, err.long_ty_path()); err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { is_partial_move: false, ty, place: place_desc, span: binding_span, }); - if let Some(path) = path { - err.subdiagnostic(crate::session_diagnostics::LongTypePath { - path: path.display().to_string(), - }); - } } } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index e841a5e4c94..706dd7135f7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -167,7 +167,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { | ProjectionElem::ConstantIndex { .. } | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Subslice { .. } - | ProjectionElem::Downcast(..), + | ProjectionElem::Downcast(..) + | ProjectionElem::UnwrapUnsafeBinder(_), ], } => bug!("Unexpected immutable place."), } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index decfab502bb..077d8f49df8 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1398,6 +1398,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { self.consume_operand(location, (operand, span), state); } } + + Rvalue::WrapUnsafeBinder(op, _) => { + self.consume_operand(location, (op, span), state); + } } } @@ -1770,7 +1774,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // So it's safe to skip these. ProjectionElem::OpaqueCast(_) | ProjectionElem::Subtype(_) - | ProjectionElem::Downcast(_, _) => (), + | ProjectionElem::Downcast(_, _) + | ProjectionElem::UnwrapUnsafeBinder(_) => (), } place_ty = place_ty.projection_ty(tcx, elem); @@ -2004,6 +2009,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // FIXME: is this true even if P is an adt with a dtor? { } + ProjectionElem::UnwrapUnsafeBinder(_) => { + check_parent_of_field(self, location, place_base, span, state); + } + // assigning to (*P) requires P to be initialized ProjectionElem::Deref => { self.check_if_full_path_is_moved( @@ -2384,7 +2393,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { | ProjectionElem::Subslice { .. } | ProjectionElem::Subtype(..) | ProjectionElem::OpaqueCast { .. } - | ProjectionElem::Downcast(..) => { + | ProjectionElem::Downcast(..) + | ProjectionElem::UnwrapUnsafeBinder(_) => { let upvar_field_projection = self.is_upvar_field_projection(place); if let Some(field) = upvar_field_projection { let upvar = &self.upvars[field.index()]; diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 679e111caa9..cf3e82426e8 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -250,7 +250,8 @@ fn place_components_conflict<'tcx>( | (ProjectionElem::Subslice { .. }, _, _) | (ProjectionElem::OpaqueCast { .. }, _, _) | (ProjectionElem::Subtype(_), _, _) - | (ProjectionElem::Downcast { .. }, _, _) => { + | (ProjectionElem::Downcast { .. }, _, _) + | (ProjectionElem::UnwrapUnsafeBinder(_), _, _) => { // Recursive case. This can still be disjoint on a // further iteration if this a shallow access and // there's a deref later on, e.g., a borrow @@ -519,5 +520,9 @@ fn place_projection_conflict<'tcx>( pi1_elem, pi2_elem ), + + (ProjectionElem::UnwrapUnsafeBinder(_), _) => { + todo!() + } } } diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs index f71e6f3e6f3..6d32ee17f4c 100644 --- a/compiler/rustc_borrowck/src/polonius/dump.rs +++ b/compiler/rustc_borrowck/src/polonius/dump.rs @@ -1,17 +1,19 @@ use std::io; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_index::IndexVec; use rustc_middle::mir::pretty::{ PassWhere, PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer, }; -use rustc_middle::mir::{Body, ClosureRegionRequirements}; +use rustc_middle::mir::{Body, ClosureRegionRequirements, Location}; use rustc_middle::ty::{RegionVid, TyCtxt}; +use rustc_mir_dataflow::points::PointIndex; use rustc_session::config::MirIncludeSpans; use crate::borrow_set::BorrowSet; use crate::constraints::OutlivesConstraint; use crate::polonius::{LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet}; +use crate::region_infer::values::LivenessValues; use crate::type_check::Locations; use crate::{BorrowckInferCtxt, RegionInferenceContext}; @@ -80,14 +82,27 @@ fn emit_polonius_dump<'tcx>( body, regioncx, borrow_set, - localized_outlives_constraints, + &localized_outlives_constraints, closure_region_requirements, out, )?; writeln!(out, "</code></pre>")?; writeln!(out, "</div>")?; - // Section 2: mermaid visualization of the CFG. + // Section 2: mermaid visualization of the polonius constraint graph. + writeln!(out, "<div>")?; + writeln!(out, "Polonius constraint graph")?; + writeln!(out, "<pre class='mermaid'>")?; + let edge_count = emit_mermaid_constraint_graph( + borrow_set, + regioncx.liveness_constraints(), + &localized_outlives_constraints, + out, + )?; + writeln!(out, "</pre>")?; + writeln!(out, "</div>")?; + + // Section 3: mermaid visualization of the CFG. writeln!(out, "<div>")?; writeln!(out, "Control-flow graph")?; writeln!(out, "<pre class='mermaid'>")?; @@ -95,7 +110,7 @@ fn emit_polonius_dump<'tcx>( writeln!(out, "</pre>")?; writeln!(out, "</div>")?; - // Section 3: mermaid visualization of the NLL region graph. + // Section 4: mermaid visualization of the NLL region graph. writeln!(out, "<div>")?; writeln!(out, "NLL regions")?; writeln!(out, "<pre class='mermaid'>")?; @@ -103,7 +118,7 @@ fn emit_polonius_dump<'tcx>( writeln!(out, "</pre>")?; writeln!(out, "</div>")?; - // Section 4: mermaid visualization of the NLL SCC graph. + // Section 5: mermaid visualization of the NLL SCC graph. writeln!(out, "<div>")?; writeln!(out, "NLL SCCs")?; writeln!(out, "<pre class='mermaid'>")?; @@ -117,7 +132,11 @@ fn emit_polonius_dump<'tcx>( "<script src='https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js'></script>" )?; writeln!(out, "<script>")?; - writeln!(out, "mermaid.initialize({{ startOnLoad: false, maxEdges: 100 }});")?; + writeln!( + out, + "mermaid.initialize({{ startOnLoad: false, maxEdges: {} }});", + edge_count.max(100), + )?; writeln!(out, "mermaid.run({{ querySelector: '.mermaid' }})")?; writeln!(out, "</script>")?; writeln!(out, "</body>")?; @@ -132,7 +151,7 @@ fn emit_html_mir<'tcx>( body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, borrow_set: &BorrowSet<'tcx>, - localized_outlives_constraints: LocalizedOutlivesConstraintSet, + localized_outlives_constraints: &LocalizedOutlivesConstraintSet, closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>, out: &mut dyn io::Write, ) -> io::Result<()> { @@ -160,7 +179,7 @@ fn emit_html_mir<'tcx>( regioncx, closure_region_requirements, borrow_set, - &localized_outlives_constraints, + localized_outlives_constraints, pass_where, out, ) @@ -392,3 +411,76 @@ fn emit_mermaid_nll_sccs<'tcx>( Ok(()) } + +/// Emits a mermaid flowchart of the polonius localized outlives constraints, with subgraphs per +/// region, and loan introductions. +fn emit_mermaid_constraint_graph<'tcx>( + borrow_set: &BorrowSet<'tcx>, + liveness: &LivenessValues, + localized_outlives_constraints: &LocalizedOutlivesConstraintSet, + out: &mut dyn io::Write, +) -> io::Result<usize> { + let location_name = |location: Location| { + // A MIR location looks like `bb5[2]`. As that is not a syntactically valid mermaid node id, + // transform it into `BB5_2`. + format!("BB{}_{}", location.block.index(), location.statement_index) + }; + let region_name = |region: RegionVid| format!("'{}", region.index()); + let node_name = |region: RegionVid, point: PointIndex| { + let location = liveness.location_from_point(point); + format!("{}_{}", region_name(region), location_name(location)) + }; + + // The mermaid chart type: a top-down flowchart, which supports subgraphs. + writeln!(out, "flowchart TD")?; + + // The loans subgraph: a node per loan. + writeln!(out, " subgraph \"Loans\"")?; + for loan_idx in 0..borrow_set.len() { + writeln!(out, " L{loan_idx}")?; + } + writeln!(out, " end\n")?; + + // And an edge from that loan node to where it enters the constraint graph. + for (loan_idx, loan) in borrow_set.iter_enumerated() { + writeln!( + out, + " L{} --> {}_{}", + loan_idx.index(), + region_name(loan.region), + location_name(loan.reserve_location), + )?; + } + writeln!(out, "")?; + + // The regions subgraphs containing the region/point nodes. + let mut points_per_region: FxIndexMap<RegionVid, FxIndexSet<PointIndex>> = + FxIndexMap::default(); + for constraint in &localized_outlives_constraints.outlives { + points_per_region.entry(constraint.source).or_default().insert(constraint.from); + points_per_region.entry(constraint.target).or_default().insert(constraint.to); + } + for (region, points) in points_per_region { + writeln!(out, " subgraph \"{}\"", region_name(region))?; + for point in points { + writeln!(out, " {}", node_name(region, point))?; + } + writeln!(out, " end\n")?; + } + + // The constraint graph edges. + for constraint in &localized_outlives_constraints.outlives { + // FIXME: add killed loans and constraint kind as edge labels. + writeln!( + out, + " {} --> {}", + node_name(constraint.source, constraint.from), + node_name(constraint.target, constraint.to), + )?; + } + + // Return the number of edges: this is the biggest graph in the dump and its edge count will be + // mermaid's max edge count to support. + let edge_count = borrow_set.len() + localized_outlives_constraints.outlives.len(); + Ok(edge_count) +} diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs index f79bcf5af55..0d1d8642bca 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs @@ -325,6 +325,10 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> { self.consume_operand(location, operand); } } + + Rvalue::WrapUnsafeBinder(op, _) => { + self.consume_operand(location, op); + } } } diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs index fc7e6e58641..83cca38a5c0 100644 --- a/compiler/rustc_borrowck/src/prefixes.rs +++ b/compiler/rustc_borrowck/src/prefixes.rs @@ -66,6 +66,10 @@ impl<'tcx> Iterator for Prefixes<'tcx> { self.next = Some(cursor_base); return Some(cursor); } + ProjectionElem::UnwrapUnsafeBinder(_) => { + self.next = Some(cursor_base); + return Some(cursor); + } ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } | ProjectionElem::OpaqueCast { .. } diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index 2c37d2bc123..11b30c145c2 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -459,13 +459,6 @@ pub(crate) enum OnClosureNote<'a> { } #[derive(Subdiagnostic)] -#[note(borrowck_long_type_full_path)] -#[note(borrowck_long_type_consider_verbose)] -pub(crate) struct LongTypePath { - pub(crate) path: String, -} - -#[derive(Subdiagnostic)] pub(crate) enum TypeNoCopy<'a> { #[label(borrowck_ty_no_impl_copy)] Label { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index a2ef5588f48..92492bfdb8d 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -302,6 +302,25 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { ) .unwrap(); } + ProjectionElem::UnwrapUnsafeBinder(ty) => { + let ty::UnsafeBinder(binder_ty) = *base_ty.ty.kind() else { + unreachable!(); + }; + let found_ty = self.typeck.infcx.instantiate_binder_with_fresh_vars( + self.body().source_info(location).span, + BoundRegionConversionTime::HigherRankedType, + binder_ty.into(), + ); + self.typeck + .relate_types( + ty, + context.ambient_variance(), + found_ty, + location.to_locations(), + ConstraintCategory::Boring, + ) + .unwrap(); + } ProjectionElem::Subtype(_) => { bug!("ProjectionElem::Subtype shouldn't exist in borrowck") } @@ -2233,6 +2252,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.check_operand(right, location); } + Rvalue::WrapUnsafeBinder(op, ty) => { + self.check_operand(op, location); + let operand_ty = op.ty(self.body, self.tcx()); + + let ty::UnsafeBinder(binder_ty) = *ty.kind() else { + unreachable!(); + }; + let expected_ty = self.infcx.instantiate_binder_with_fresh_vars( + self.body().source_info(location).span, + BoundRegionConversionTime::HigherRankedType, + binder_ty.into(), + ); + self.sub_types( + operand_ty, + expected_ty, + location.to_locations(), + ConstraintCategory::Boring, + ) + .unwrap(); + } + Rvalue::RawPtr(..) | Rvalue::ThreadLocalRef(..) | Rvalue::Len(..) @@ -2258,7 +2298,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | Rvalue::NullaryOp(..) | Rvalue::CopyForDeref(..) | Rvalue::UnaryOp(..) - | Rvalue::Discriminant(..) => None, + | Rvalue::Discriminant(..) + | Rvalue::WrapUnsafeBinder(..) => None, Rvalue::Aggregate(aggregate, _) => match **aggregate { AggregateKind::Adt(_, _, _, user_ty, _) => user_ty, @@ -2450,7 +2491,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | ProjectionElem::OpaqueCast(..) | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } => { + | ProjectionElem::Subslice { .. } + | ProjectionElem::UnwrapUnsafeBinder(_) => { // other field access } ProjectionElem::Subtype(_) => { diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index eb01ca3941d..8ab21986e68 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -56,7 +56,7 @@ fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> let (ident, vdata, fields) = match substr.fields { Struct(vdata, fields) => (substr.type_ident, *vdata, fields), - EnumMatching(_, v, fields) => (v.ident, &v.data, fields), + EnumMatching(v, fields) => (v.ident, &v.data, fields), AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr), EnumDiscr(..) | StaticStruct(..) | StaticEnum(..) => { cx.dcx().span_bug(span, "nonsensical .fields in `#[derive(Debug)]`") diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs deleted file mode 100644 index 6348560496e..00000000000 --- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs +++ /dev/null @@ -1,215 +0,0 @@ -//! The compiler code necessary for `#[derive(RustcDecodable)]`. See encodable.rs for more. - -use rustc_ast::ptr::P; -use rustc_ast::{self as ast, Expr, MetaItem, Mutability}; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::{Ident, Span, Symbol, sym}; -use thin_vec::{ThinVec, thin_vec}; - -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::pathvec_std; - -pub(crate) fn expand_deriving_rustc_decodable( - cx: &ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - is_const: bool, -) { - let krate = sym::rustc_serialize; - let typaram = sym::__D; - - let trait_def = TraitDef { - span, - path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global), - skip_path_as_bound: false, - needs_copy_as_bound_if_packed: true, - additional_bounds: Vec::new(), - supports_unions: false, - methods: vec![MethodDef { - name: sym::decode, - generics: Bounds { - bounds: vec![(typaram, vec![Path::new_( - vec![krate, sym::Decoder], - vec![], - PathKind::Global, - )])], - }, - explicit_self: false, - nonself_args: vec![( - Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut), - sym::d, - )], - ret_ty: Path(Path::new_( - pathvec_std!(result::Result), - vec![ - Box::new(Self_), - Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))), - ], - PathKind::Std, - )), - attributes: ast::AttrVec::new(), - fieldless_variants_strategy: FieldlessVariantsStrategy::Default, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - decodable_substructure(a, b, c, krate) - })), - }], - associated_types: Vec::new(), - is_const, - }; - - trait_def.expand(cx, mitem, item, push) -} - -fn decodable_substructure( - cx: &ExtCtxt<'_>, - trait_span: Span, - substr: &Substructure<'_>, - krate: Symbol, -) -> BlockOrExpr { - let decoder = substr.nonselflike_args[0].clone(); - let recurse = vec![ - Ident::new(krate, trait_span), - Ident::new(sym::Decodable, trait_span), - Ident::new(sym::decode, trait_span), - ]; - let exprdecode = cx.expr_path(cx.path_global(trait_span, recurse)); - // throw an underscore in front to suppress unused variable warnings - let blkarg = Ident::new(sym::_d, trait_span); - let blkdecoder = cx.expr_ident(trait_span, blkarg); - - let expr = match substr.fields { - StaticStruct(_, summary) => { - let nfields = match summary { - Unnamed(fields, _) => fields.len(), - Named(fields) => fields.len(), - }; - let fn_read_struct_field_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_struct_field]); - - let path = cx.path_ident(trait_span, substr.type_ident); - let result = - decode_static_fields(cx, trait_span, path, summary, |cx, span, name, field| { - cx.expr_try( - span, - cx.expr_call_global(span, fn_read_struct_field_path.clone(), thin_vec![ - blkdecoder.clone(), - cx.expr_str(span, name), - cx.expr_usize(span, field), - exprdecode.clone(), - ]), - ) - }); - let result = cx.expr_ok(trait_span, result); - let fn_read_struct_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_struct]); - - cx.expr_call_global(trait_span, fn_read_struct_path, thin_vec![ - decoder, - cx.expr_str(trait_span, substr.type_ident.name), - cx.expr_usize(trait_span, nfields), - cx.lambda1(trait_span, result, blkarg), - ]) - } - StaticEnum(_, fields) => { - let variant = Ident::new(sym::i, trait_span); - - let mut arms = ThinVec::with_capacity(fields.len() + 1); - let mut variants = ThinVec::with_capacity(fields.len()); - - let fn_read_enum_variant_arg_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum_variant_arg]); - - for (i, &(ident, v_span, ref parts)) in fields.iter().enumerate() { - variants.push(cx.expr_str(v_span, ident.name)); - - let path = cx.path(trait_span, vec![substr.type_ident, ident]); - let decoded = - decode_static_fields(cx, v_span, path, parts, |cx, span, _, field| { - let idx = cx.expr_usize(span, field); - cx.expr_try( - span, - cx.expr_call_global( - span, - fn_read_enum_variant_arg_path.clone(), - thin_vec![blkdecoder.clone(), idx, exprdecode.clone()], - ), - ) - }); - - arms.push(cx.arm(v_span, cx.pat_lit(v_span, cx.expr_usize(v_span, i)), decoded)); - } - - arms.push(cx.arm_unreachable(trait_span)); - - let result = cx.expr_ok( - trait_span, - cx.expr_match(trait_span, cx.expr_ident(trait_span, variant), arms), - ); - let lambda = cx.lambda(trait_span, vec![blkarg, variant], result); - let variant_array_ref = cx.expr_array_ref(trait_span, variants); - let fn_read_enum_variant_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum_variant]); - let result = cx.expr_call_global(trait_span, fn_read_enum_variant_path, thin_vec![ - blkdecoder, - variant_array_ref, - lambda - ]); - let fn_read_enum_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum]); - - cx.expr_call_global(trait_span, fn_read_enum_path, thin_vec![ - decoder, - cx.expr_str(trait_span, substr.type_ident.name), - cx.lambda1(trait_span, result, blkarg), - ]) - } - _ => cx.dcx().bug("expected StaticEnum or StaticStruct in derive(Decodable)"), - }; - BlockOrExpr::new_expr(expr) -} - -/// Creates a decoder for a single enum variant/struct: -/// - `outer_pat_path` is the path to this enum variant/struct -/// - `getarg` should retrieve the `usize`-th field with name `@str`. -fn decode_static_fields<F>( - cx: &ExtCtxt<'_>, - trait_span: Span, - outer_pat_path: ast::Path, - fields: &StaticFields, - mut getarg: F, -) -> P<Expr> -where - F: FnMut(&ExtCtxt<'_>, Span, Symbol, usize) -> P<Expr>, -{ - match fields { - Unnamed(fields, is_tuple) => { - let path_expr = cx.expr_path(outer_pat_path); - if matches!(is_tuple, IsTuple::No) { - path_expr - } else { - let fields = fields - .iter() - .enumerate() - .map(|(i, &span)| getarg(cx, span, Symbol::intern(&format!("_field{i}")), i)) - .collect(); - - cx.expr_call(trait_span, path_expr, fields) - } - } - Named(fields) => { - // use the field's span to get nicer error messages. - let fields = fields - .iter() - .enumerate() - .map(|(i, &(ident, span, _))| { - let arg = getarg(cx, span, ident.name, i); - cx.field_imm(span, ident, arg) - }) - .collect(); - cx.expr_struct(trait_span, outer_pat_path, fields) - } - } -} diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 3c7bebd0f19..2388b7dd648 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -42,7 +42,7 @@ pub(crate) fn expand_deriving_default( StaticStruct(_, fields) => { default_struct_substructure(cx, trait_span, substr, fields) } - StaticEnum(enum_def, _) => { + StaticEnum(enum_def) => { default_enum_substructure(cx, trait_span, enum_def, item.span()) } _ => cx.dcx().span_bug(trait_span, "method in `derive(Default)`"), diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs deleted file mode 100644 index 20aacb2caca..00000000000 --- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs +++ /dev/null @@ -1,284 +0,0 @@ -//! The compiler code necessary to implement the `#[derive(RustcEncodable)]` -//! (and `RustcDecodable`, in `decodable.rs`) extension. The idea here is that -//! type-defining items may be tagged with -//! `#[derive(RustcEncodable, RustcDecodable)]`. -//! -//! For example, a type like: -//! -//! ```ignore (old code) -//! #[derive(RustcEncodable, RustcDecodable)] -//! struct Node { id: usize } -//! ``` -//! -//! would generate two implementations like: -//! -//! ```ignore (old code) -//! # struct Node { id: usize } -//! impl<S: Encoder<E>, E> Encodable<S, E> for Node { -//! fn encode(&self, s: &mut S) -> Result<(), E> { -//! s.emit_struct("Node", 1, |this| { -//! this.emit_struct_field("id", 0, |this| { -//! Encodable::encode(&self.id, this) -//! /* this.emit_usize(self.id) can also be used */ -//! }) -//! }) -//! } -//! } -//! -//! impl<D: Decoder<E>, E> Decodable<D, E> for Node { -//! fn decode(d: &mut D) -> Result<Node, E> { -//! d.read_struct("Node", 1, |this| { -//! match this.read_struct_field("id", 0, |this| Decodable::decode(this)) { -//! Ok(id) => Ok(Node { id: id }), -//! Err(e) => Err(e), -//! } -//! }) -//! } -//! } -//! ``` -//! -//! Other interesting scenarios are when the item has type parameters or -//! references other non-built-in types. A type definition like: -//! -//! ```ignore (old code) -//! # #[derive(RustcEncodable, RustcDecodable)] -//! # struct Span; -//! #[derive(RustcEncodable, RustcDecodable)] -//! struct Spanned<T> { node: T, span: Span } -//! ``` -//! -//! would yield functions like: -//! -//! ```ignore (old code) -//! # #[derive(RustcEncodable, RustcDecodable)] -//! # struct Span; -//! # struct Spanned<T> { node: T, span: Span } -//! impl< -//! S: Encoder<E>, -//! E, -//! T: Encodable<S, E> -//! > Encodable<S, E> for Spanned<T> { -//! fn encode(&self, s: &mut S) -> Result<(), E> { -//! s.emit_struct("Spanned", 2, |this| { -//! this.emit_struct_field("node", 0, |this| self.node.encode(this)) -//! .unwrap(); -//! this.emit_struct_field("span", 1, |this| self.span.encode(this)) -//! }) -//! } -//! } -//! -//! impl< -//! D: Decoder<E>, -//! E, -//! T: Decodable<D, E> -//! > Decodable<D, E> for Spanned<T> { -//! fn decode(d: &mut D) -> Result<Spanned<T>, E> { -//! d.read_struct("Spanned", 2, |this| { -//! Ok(Spanned { -//! node: this.read_struct_field("node", 0, |this| Decodable::decode(this)) -//! .unwrap(), -//! span: this.read_struct_field("span", 1, |this| Decodable::decode(this)) -//! .unwrap(), -//! }) -//! }) -//! } -//! } -//! ``` - -use rustc_ast::{AttrVec, ExprKind, MetaItem, Mutability}; -use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::{Ident, Span, Symbol, sym}; -use thin_vec::{ThinVec, thin_vec}; - -use crate::deriving::generic::ty::*; -use crate::deriving::generic::*; -use crate::deriving::pathvec_std; - -pub(crate) fn expand_deriving_rustc_encodable( - cx: &ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - is_const: bool, -) { - let krate = sym::rustc_serialize; - let typaram = sym::__S; - - let trait_def = TraitDef { - span, - path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global), - skip_path_as_bound: false, - needs_copy_as_bound_if_packed: true, - additional_bounds: Vec::new(), - supports_unions: false, - methods: vec![MethodDef { - name: sym::encode, - generics: Bounds { - bounds: vec![(typaram, vec![Path::new_( - vec![krate, sym::Encoder], - vec![], - PathKind::Global, - )])], - }, - explicit_self: true, - nonself_args: vec![( - Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut), - sym::s, - )], - ret_ty: Path(Path::new_( - pathvec_std!(result::Result), - vec![ - Box::new(Unit), - Box::new(Path(Path::new_(vec![typaram, sym::Error], vec![], PathKind::Local))), - ], - PathKind::Std, - )), - attributes: AttrVec::new(), - fieldless_variants_strategy: FieldlessVariantsStrategy::Default, - combine_substructure: combine_substructure(Box::new(|a, b, c| { - encodable_substructure(a, b, c, krate) - })), - }], - associated_types: Vec::new(), - is_const, - }; - - trait_def.expand(cx, mitem, item, push) -} - -fn encodable_substructure( - cx: &ExtCtxt<'_>, - trait_span: Span, - substr: &Substructure<'_>, - krate: Symbol, -) -> BlockOrExpr { - let encoder = substr.nonselflike_args[0].clone(); - // throw an underscore in front to suppress unused variable warnings - let blkarg = Ident::new(sym::_e, trait_span); - let blkencoder = cx.expr_ident(trait_span, blkarg); - let fn_path = cx.expr_path(cx.path_global(trait_span, vec![ - Ident::new(krate, trait_span), - Ident::new(sym::Encodable, trait_span), - Ident::new(sym::encode, trait_span), - ])); - - match substr.fields { - Struct(_, fields) => { - let fn_emit_struct_field_path = - cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct_field]); - let mut stmts = ThinVec::new(); - for (i, &FieldInfo { name, ref self_expr, span, .. }) in fields.iter().enumerate() { - let name = match name { - Some(id) => id.name, - None => Symbol::intern(&format!("_field{i}")), - }; - let self_ref = cx.expr_addr_of(span, self_expr.clone()); - let enc = - cx.expr_call(span, fn_path.clone(), thin_vec![self_ref, blkencoder.clone()]); - let lambda = cx.lambda1(span, enc, blkarg); - let call = cx.expr_call_global(span, fn_emit_struct_field_path.clone(), thin_vec![ - blkencoder.clone(), - cx.expr_str(span, name), - cx.expr_usize(span, i), - lambda, - ]); - - // last call doesn't need a try! - let last = fields.len() - 1; - let call = if i != last { - cx.expr_try(span, call) - } else { - cx.expr(span, ExprKind::Ret(Some(call))) - }; - - let stmt = cx.stmt_expr(call); - stmts.push(stmt); - } - - // unit structs have no fields and need to return Ok() - let blk = if stmts.is_empty() { - let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, ThinVec::new())); - cx.lambda1(trait_span, ok, blkarg) - } else { - cx.lambda_stmts_1(trait_span, stmts, blkarg) - }; - - let fn_emit_struct_path = - cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct]); - - let expr = cx.expr_call_global(trait_span, fn_emit_struct_path, thin_vec![ - encoder, - cx.expr_str(trait_span, substr.type_ident.name), - cx.expr_usize(trait_span, fields.len()), - blk, - ]); - BlockOrExpr::new_expr(expr) - } - - EnumMatching(idx, variant, fields) => { - // We're not generating an AST that the borrow checker is expecting, - // so we need to generate a unique local variable to take the - // mutable loan out on, otherwise we get conflicts which don't - // actually exist. - let me = cx.stmt_let(trait_span, false, blkarg, encoder); - let encoder = cx.expr_ident(trait_span, blkarg); - - let fn_emit_enum_variant_arg_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum_variant_arg]); - - let mut stmts = ThinVec::new(); - if !fields.is_empty() { - let last = fields.len() - 1; - for (i, &FieldInfo { ref self_expr, span, .. }) in fields.iter().enumerate() { - let self_ref = cx.expr_addr_of(span, self_expr.clone()); - let enc = cx - .expr_call(span, fn_path.clone(), thin_vec![self_ref, blkencoder.clone()]); - let lambda = cx.lambda1(span, enc, blkarg); - - let call = cx.expr_call_global( - span, - fn_emit_enum_variant_arg_path.clone(), - thin_vec![blkencoder.clone(), cx.expr_usize(span, i), lambda], - ); - let call = if i != last { - cx.expr_try(span, call) - } else { - cx.expr(span, ExprKind::Ret(Some(call))) - }; - stmts.push(cx.stmt_expr(call)); - } - } else { - let ok = cx.expr_ok(trait_span, cx.expr_tuple(trait_span, ThinVec::new())); - let ret_ok = cx.expr(trait_span, ExprKind::Ret(Some(ok))); - stmts.push(cx.stmt_expr(ret_ok)); - } - - let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg); - let name = cx.expr_str(trait_span, variant.ident.name); - - let fn_emit_enum_variant_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum_variant]); - - let call = cx.expr_call_global(trait_span, fn_emit_enum_variant_path, thin_vec![ - blkencoder, - name, - cx.expr_usize(trait_span, *idx), - cx.expr_usize(trait_span, fields.len()), - blk, - ]); - - let blk = cx.lambda1(trait_span, call, blkarg); - let fn_emit_enum_path: Vec<_> = - cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum]); - let expr = cx.expr_call_global(trait_span, fn_emit_enum_path, thin_vec![ - encoder, - cx.expr_str(trait_span, substr.type_ident.name), - blk - ]); - BlockOrExpr::new_mixed(thin_vec![me], Some(expr)) - } - - _ => cx.dcx().bug("expected Struct or EnumMatching in derive(Encodable)"), - } -} diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index f0a5e44e066..755a733286c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -311,7 +311,7 @@ pub(crate) enum SubstructureFields<'a> { /// Matching variants of the enum: variant index, ast::Variant, /// fields: the field name is only non-`None` in the case of a struct /// variant. - EnumMatching(usize, &'a ast::Variant, Vec<FieldInfo>), + EnumMatching(&'a ast::Variant, Vec<FieldInfo>), /// The discriminant of an enum. The first field is a `FieldInfo` for the discriminants, as /// if they were fields. The second field is the expression to combine the @@ -322,7 +322,7 @@ pub(crate) enum SubstructureFields<'a> { StaticStruct(&'a ast::VariantData, StaticFields), /// A static method where `Self` is an enum. - StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>), + StaticEnum(&'a ast::EnumDef), } /// Combine the values of all the fields together. The last argument is @@ -1270,7 +1270,7 @@ impl<'a> MethodDef<'a> { trait_, type_ident, nonselflike_args, - &EnumMatching(0, variant, Vec::new()), + &EnumMatching(variant, Vec::new()), ); } } @@ -1282,9 +1282,8 @@ impl<'a> MethodDef<'a> { // where each tuple has length = selflike_args.len() let mut match_arms: ThinVec<ast::Arm> = variants .iter() - .enumerate() - .filter(|&(_, v)| !(unify_fieldless_variants && v.data.fields().is_empty())) - .map(|(index, variant)| { + .filter(|&v| !(unify_fieldless_variants && v.data.fields().is_empty())) + .map(|variant| { // A single arm has form (&VariantK, &VariantK, ...) => BodyK // (see "Final wrinkle" note below for why.) @@ -1316,7 +1315,7 @@ impl<'a> MethodDef<'a> { // expressions for referencing every field of every // Self arg, assuming all are instances of VariantK. // Build up code associated with such a case. - let substructure = EnumMatching(index, variant, fields); + let substructure = EnumMatching(variant, fields); let arm_expr = self .call_substructure_method( cx, @@ -1344,7 +1343,7 @@ impl<'a> MethodDef<'a> { trait_, type_ident, nonselflike_args, - &EnumMatching(0, v, Vec::new()), + &EnumMatching(v, Vec::new()), ) .into_expr(cx, span), ) @@ -1407,21 +1406,12 @@ impl<'a> MethodDef<'a> { type_ident: Ident, nonselflike_args: &[P<Expr>], ) -> BlockOrExpr { - let summary = enum_def - .variants - .iter() - .map(|v| { - let sp = v.span.with_ctxt(trait_.span.ctxt()); - let summary = trait_.summarise_struct(cx, &v.data); - (v.ident, sp, summary) - }) - .collect(); self.call_substructure_method( cx, trait_, type_ident, nonselflike_args, - &StaticEnum(enum_def, summary), + &StaticEnum(enum_def), ) } } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs index af6dc62db7a..f34a6ae1d98 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs @@ -21,7 +21,6 @@ pub(crate) struct Path { #[derive(Clone)] pub(crate) enum PathKind { Local, - Global, Std, } @@ -57,7 +56,6 @@ impl Path { let params = tys.map(GenericArg::Type).collect(); match self.kind { - PathKind::Global => cx.path_all(span, true, idents, params), PathKind::Local => cx.path_all(span, false, idents, params), PathKind::Std => { let def_site = cx.with_def_site_ctxt(DUMMY_SP); diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index ec058b41313..c112589b131 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -23,9 +23,7 @@ pub(crate) mod bounds; pub(crate) mod clone; pub(crate) mod coerce_pointee; pub(crate) mod debug; -pub(crate) mod decodable; pub(crate) mod default; -pub(crate) mod encodable; pub(crate) mod hash; #[path = "cmp/eq.rs"] diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index a0ab6375a66..90447da6680 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -8,7 +8,9 @@ use rustc_ast::{ token, }; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans}; +use rustc_errors::{ + Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans, listify, pluralize, +}; use rustc_expand::base::*; use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY; use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId}; @@ -101,15 +103,14 @@ fn parse_args<'a>(ecx: &ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, match p.expect(exp!(Comma)) { Err(err) => { - match token::TokenKind::Comma.similar_tokens() { - Some(tks) if tks.contains(&p.token.kind) => { - // If a similar token is found, then it may be a typo. We - // consider it as a comma, and continue parsing. - err.emit(); - p.bump(); - } + if token::TokenKind::Comma.similar_tokens().contains(&p.token.kind) { + // If a similar token is found, then it may be a typo. We + // consider it as a comma, and continue parsing. + err.emit(); + p.bump(); + } else { // Otherwise stop the parsing and return the error. - _ => return Err(err), + return Err(err); } } Ok(Recovered::Yes(_)) => (), @@ -976,15 +977,11 @@ fn report_invalid_references( } else { MultiSpan::from_spans(invalid_refs.iter().filter_map(|&(_, span, _, _)| span).collect()) }; - let arg_list = if let &[index] = &indexes[..] { - format!("argument {index}") - } else { - let tail = indexes.pop().unwrap(); - format!( - "arguments {head} and {tail}", - head = indexes.into_iter().map(|i| i.to_string()).collect::<Vec<_>>().join(", ") - ) - }; + let arg_list = format!( + "argument{} {}", + pluralize!(indexes.len()), + listify(&indexes, |i: &usize| i.to_string()).unwrap_or_default() + ); e = ecx.dcx().struct_span_err( span, format!("invalid reference to positional {arg_list} ({num_args_desc})"), diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 0918403b855..6987ae95980 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -132,8 +132,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { Ord: ord::expand_deriving_ord, PartialEq: partial_eq::expand_deriving_partial_eq, PartialOrd: partial_ord::expand_deriving_partial_ord, - RustcDecodable: decodable::expand_deriving_rustc_decodable, - RustcEncodable: encodable::expand_deriving_rustc_encodable, CoercePointee: coerce_pointee::expand_deriving_coerce_pointee, } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 34066eb83fc..7a40d236b92 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -417,6 +417,16 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { Some(source_info.span), ); } + AssertKind::NullPointerDereference => { + let location = fx.get_caller_location(source_info).load_scalar(fx); + + codegen_panic_inner( + fx, + rustc_hir::LangItem::PanicNullPointerDereference, + &[location], + Some(source_info.span), + ) + } _ => { let location = fx.get_caller_location(source_info).load_scalar(fx); @@ -915,6 +925,10 @@ fn codegen_stmt<'tcx>( } crate::discriminant::codegen_set_discriminant(fx, lval, variant_index); } + Rvalue::WrapUnsafeBinder(ref operand, _to_ty) => { + let operand = codegen_operand(fx, operand); + lval.write_cvalue_transmute(fx, operand); + } } } StatementKind::StorageLive(_) @@ -983,7 +997,9 @@ pub(crate) fn codegen_place<'tcx>( cplace = cplace.place_deref(fx); } PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"), - PlaceElem::Subtype(ty) => cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty)), + PlaceElem::Subtype(ty) | PlaceElem::UnwrapUnsafeBinder(ty) => { + cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty)); + } PlaceElem::Field(field, _ty) => { cplace = cplace.place_field(fx, field); } diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 3e7b81a96b6..425b2adf32a 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -6,7 +6,7 @@ use cranelift_module::*; use rustc_data_structures::fx::FxHashSet; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::{AllocId, GlobalAlloc, Scalar, read_target_uint}; -use rustc_middle::ty::{Binder, ExistentialTraitRef, ScalarInt}; +use rustc_middle::ty::{ExistentialTraitRef, ScalarInt}; use crate::prelude::*; @@ -167,7 +167,9 @@ pub(crate) fn codegen_const_value<'tcx>( &mut fx.constants_cx, fx.module, ty, - dyn_ty.principal(), + dyn_ty.principal().map(|principal| { + fx.tcx.instantiate_bound_regions_with_erased(principal) + }), ); let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func); @@ -243,7 +245,7 @@ pub(crate) fn data_id_for_vtable<'tcx>( cx: &mut ConstantCx, module: &mut dyn Module, ty: Ty<'tcx>, - trait_ref: Option<Binder<'tcx, ExistentialTraitRef<'tcx>>>, + trait_ref: Option<ExistentialTraitRef<'tcx>>, ) -> DataId { let alloc_id = tcx.vtable_allocation((ty, trait_ref)); data_id_for_alloc_id(cx, module, alloc_id, Mutability::Not) @@ -460,9 +462,15 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant GlobalAlloc::Memory(target_alloc) => { data_id_for_alloc_id(cx, module, alloc_id, target_alloc.inner().mutability) } - GlobalAlloc::VTable(ty, dyn_ty) => { - data_id_for_vtable(tcx, cx, module, ty, dyn_ty.principal()) - } + GlobalAlloc::VTable(ty, dyn_ty) => data_id_for_vtable( + tcx, + cx, + module, + ty, + dyn_ty + .principal() + .map(|principal| tcx.instantiate_bound_regions_with_erased(principal)), + ), GlobalAlloc::Static(def_id) => { if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 27adf6318e2..a52b18573b1 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -692,7 +692,7 @@ pub(crate) fn run_aot( if tcx.dep_graph.is_fully_enabled() { for cgu in cgus { - tcx.ensure().codegen_unit(cgu.name()); + tcx.ensure_ok().codegen_unit(cgu.name()); } } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 6d71b8e8aba..d682efd19aa 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -129,12 +129,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( return; } - let idx = generic_args[2] - .expect_const() - .try_to_valtree() - .expect("expected monomorphic const in codegen") - .0 - .unwrap_branch(); + let idx = generic_args[2].expect_const().to_value().valtree.unwrap_branch(); assert_eq!(x.layout(), y.layout()); let layout = x.layout(); diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index 2843e5bbdfb..f8bbb214920 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -61,7 +61,12 @@ pub(crate) fn unsized_info<'tcx>( old_info } } - (_, ty::Dynamic(data, ..)) => crate::vtable::get_vtable(fx, source, data.principal()), + (_, ty::Dynamic(data, ..)) => crate::vtable::get_vtable( + fx, + source, + data.principal() + .map(|principal| fx.tcx.instantiate_bound_regions_with_erased(principal)), + ), _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target), } } diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index 82b6178be9d..a460023b59c 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -90,7 +90,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( pub(crate) fn get_vtable<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>, - trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, + trait_ref: Option<ty::ExistentialTraitRef<'tcx>>, ) -> Value { let data_id = data_id_for_vtable(fx.tcx, &mut fx.constants_cx, fx.module, ty, trait_ref); let local_data_id = fx.module.declare_data_in_func(data_id, fx.bcx.func); diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index bd5d6ba387c..20a3482aaa2 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -234,7 +234,12 @@ impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { GlobalAlloc::VTable(ty, dyn_ty) => { let alloc = self .tcx - .global_alloc(self.tcx.vtable_allocation((ty, dyn_ty.principal()))) + .global_alloc(self.tcx.vtable_allocation(( + ty, + dyn_ty.principal().map(|principal| { + self.tcx.instantiate_bound_regions_with_erased(principal) + }), + ))) .unwrap_memory(); let init = const_alloc_to_gcc(self, alloc); self.static_addr_of(init, alloc.inner().align, None) diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 30732c74eb3..570ef938dc4 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::layout::{ FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError, LayoutOfHelpers, }; -use rustc_middle::ty::{self, Instance, PolyExistentialTraitRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, ExistentialTraitRef, Instance, Ty, TyCtxt}; use rustc_session::Session; use rustc_span::source_map::respan; use rustc_span::{DUMMY_SP, Span}; @@ -90,7 +90,7 @@ pub struct CodegenCx<'gcc, 'tcx> { pub function_instances: RefCell<FxHashMap<Instance<'tcx>, Function<'gcc>>>, /// Cache generated vtables pub vtables: - RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>>, + RefCell<FxHashMap<(Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>), RValue<'gcc>>>, // TODO(antoyo): improve the SSA API to not require those. /// Mapping from function pointer type to indexes of on stack parameters. @@ -401,7 +401,7 @@ impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> { impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn vtables( &self, - ) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>> { + ) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ExistentialTraitRef<'tcx>>), RValue<'gcc>>> { &self.vtables } diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index 4b84b1dbfd3..86d3de225f7 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -7,7 +7,7 @@ use rustc_data_structures::sync::Lrc; use rustc_index::bit_set::DenseBitSet; use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::{self, Body, SourceScope}; -use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty}; +use rustc_middle::ty::{ExistentialTraitRef, Instance, Ty}; use rustc_session::config::DebugInfo; use rustc_span::{BytePos, Pos, SourceFile, SourceFileAndLine, Span, Symbol}; use rustc_target::abi::Size; @@ -214,7 +214,7 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn create_vtable_debuginfo( &self, _ty: Ty<'tcx>, - _trait_ref: Option<PolyExistentialTraitRef<'tcx>>, + _trait_ref: Option<ExistentialTraitRef<'tcx>>, _vtable: Self::Value, ) { // TODO(antoyo) diff --git a/compiler/rustc_codegen_gcc/tests/run/int.rs b/compiler/rustc_codegen_gcc/tests/run/int.rs index bfe73c38435..58a26801b67 100644 --- a/compiler/rustc_codegen_gcc/tests/run/int.rs +++ b/compiler/rustc_codegen_gcc/tests/run/int.rs @@ -3,8 +3,6 @@ // Run-time: // status: 0 -#![feature(const_black_box)] - /* * Code */ diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index d2de62b17f0..2d007416263 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1325,7 +1325,9 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> { fn get_static(&mut self, def_id: DefId) -> &'ll Value { // Forward to the `get_static` method of `CodegenCx` - self.cx().get_static(def_id) + let s = self.cx().get_static(def_id); + // Cast to default address space if globals are in a different addrspace + self.cx().const_pointercast(s, self.type_ptr()) } } diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 6b17b5f6989..9e8e4e1c567 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -62,8 +62,8 @@ fn generate_enzyme_call<'ll>( // add outer_fn name to ad_name to make it unique, in case users apply autodiff to multiple // functions. Unwrap will only panic, if LLVM gave us an invalid string. let name = llvm::get_value_name(outer_fn); - let outer_fn_name = std::ffi::CStr::from_bytes_with_nul(name).unwrap().to_str().unwrap(); - ad_name.push_str(outer_fn_name.to_string().as_str()); + let outer_fn_name = std::str::from_utf8(name).unwrap(); + ad_name.push_str(outer_fn_name); // Let us assume the user wrote the following function square: // @@ -255,14 +255,14 @@ fn generate_enzyme_call<'ll>( // have no debug info to copy, which would then be ok. trace!("no dbg info"); } + // Now that we copied the metadata, get rid of dummy code. - llvm::LLVMRustEraseInstBefore(entry, last_inst); - llvm::LLVMRustEraseInstFromParent(last_inst); + llvm::LLVMRustEraseInstUntilInclusive(entry, last_inst); - if cx.val_ty(outer_fn) != cx.type_void() { - builder.ret(call); - } else { + if cx.val_ty(call) == cx.type_void() { builder.ret_void(); + } else { + builder.ret(call); } // Let's crash in case that we messed something up above and generated invalid IR. diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index b4e9b9f44f4..8c94a46ebf3 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -225,6 +225,8 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global); } llvm::set_linkage(g, llvm::Linkage::InternalLinkage); + // Cast to default address space if globals are in a different addrspace + let g = self.const_pointercast(g, self.type_ptr()); (s.to_owned(), g) }) .1; @@ -289,7 +291,7 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { let alloc = alloc.inner(); let value = match alloc.mutability { Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None), - _ => self.static_addr_of(init, alloc.align, None), + _ => self.static_addr_of_impl(init, alloc.align, None), }; if !self.sess().fewer_names() && llvm::get_value_name(value).is_empty() { @@ -312,10 +314,15 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { GlobalAlloc::VTable(ty, dyn_ty) => { let alloc = self .tcx - .global_alloc(self.tcx.vtable_allocation((ty, dyn_ty.principal()))) + .global_alloc(self.tcx.vtable_allocation(( + ty, + dyn_ty.principal().map(|principal| { + self.tcx.instantiate_bound_regions_with_erased(principal) + }), + ))) .unwrap_memory(); let init = const_alloc_to_llvm(self, alloc, /*static*/ false); - let value = self.static_addr_of(init, alloc.inner().align, None); + let value = self.static_addr_of_impl(init, alloc.inner().align, None); (value, AddressSpace::DATA) } GlobalAlloc::Static(def_id) => { @@ -327,7 +334,8 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { let llval = unsafe { llvm::LLVMConstInBoundsGEP2( self.type_i8(), - self.const_bitcast(base_addr, self.type_ptr_ext(base_addr_space)), + // Cast to the required address space if necessary + self.const_pointercast(base_addr, self.type_ptr_ext(base_addr_space)), &self.const_usize(offset.bytes()), 1, ) diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index c7114480d8b..c6855dd42e5 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -210,6 +210,14 @@ impl<'ll> CodegenCx<'ll, '_> { unsafe { llvm::LLVMConstBitCast(val, ty) } } + pub(crate) fn const_pointercast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value { + unsafe { llvm::LLVMConstPointerCast(val, ty) } + } + + /// Create a global variable. + /// + /// The returned global variable is a pointer in the default address space for globals. + /// Fails if a symbol with the given name already exists. pub(crate) fn static_addr_of_mut( &self, cv: &'ll Value, @@ -233,6 +241,34 @@ impl<'ll> CodegenCx<'ll, '_> { gv } + /// Create a global constant. + /// + /// The returned global variable is a pointer in the default address space for globals. + pub(crate) fn static_addr_of_impl( + &self, + cv: &'ll Value, + align: Align, + kind: Option<&str>, + ) -> &'ll Value { + if let Some(&gv) = self.const_globals.borrow().get(&cv) { + unsafe { + // Upgrade the alignment in cases where the same constant is used with different + // alignment requirements + let llalign = align.bytes() as u32; + if llalign > llvm::LLVMGetAlignment(gv) { + llvm::LLVMSetAlignment(gv, llalign); + } + } + return gv; + } + let gv = self.static_addr_of_mut(cv, align, kind); + unsafe { + llvm::LLVMSetGlobalConstant(gv, True); + } + self.const_globals.borrow_mut().insert(cv, gv); + gv + } + #[instrument(level = "debug", skip(self))] pub(crate) fn get_static(&self, def_id: DefId) -> &'ll Value { let instance = Instance::mono(self.tcx, def_id); @@ -384,8 +420,14 @@ impl<'ll> CodegenCx<'ll, '_> { let g = if val_llty == llty { g } else { - // If we created the global with the wrong type, - // correct the type. + // codegen_static_initializer creates the global value just from the + // `Allocation` data by generating one big struct value that is just + // all the bytes and pointers after each other. This will almost never + // match the type that the static was declared with. Unfortunately + // we can't just LLVMConstBitCast our way out of it because that has very + // specific rules on what can be cast. So instead of adding a new way to + // generate static initializers that match the static's type, we picked + // the easier option and retroactively change the type of the static item itself. let name = llvm::get_value_name(g).to_vec(); llvm::set_value_name(g, b""); @@ -505,24 +547,15 @@ impl<'ll> CodegenCx<'ll, '_> { } impl<'ll> StaticCodegenMethods for CodegenCx<'ll, '_> { + /// Get a pointer to a global variable. + /// + /// The pointer will always be in the default address space. If global variables default to a + /// different address space, an addrspacecast is inserted. fn static_addr_of(&self, cv: &'ll Value, align: Align, kind: Option<&str>) -> &'ll Value { - if let Some(&gv) = self.const_globals.borrow().get(&cv) { - unsafe { - // Upgrade the alignment in cases where the same constant is used with different - // alignment requirements - let llalign = align.bytes() as u32; - if llalign > llvm::LLVMGetAlignment(gv) { - llvm::LLVMSetAlignment(gv, llalign); - } - } - return gv; - } - let gv = self.static_addr_of_mut(cv, align, kind); - unsafe { - llvm::LLVMSetGlobalConstant(gv, True); - } - self.const_globals.borrow_mut().insert(cv, gv); - gv + let gv = self.static_addr_of_impl(cv, align, kind); + // static_addr_of_impl returns the bare global variable, which might not be in the default + // address space. Cast to the default address space if necessary. + self.const_pointercast(gv, self.type_ptr()) } fn codegen_static(&self, def_id: DefId) { diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 79381f35a3c..ba4fd75fb94 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -77,8 +77,7 @@ pub(crate) struct CodegenCx<'ll, 'tcx> { /// Cache instances of monomorphic and polymorphic items pub instances: RefCell<FxHashMap<Instance<'tcx>, &'ll Value>>, /// Cache generated vtables - pub vtables: - RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), &'ll Value>>, + pub vtables: RefCell<FxHashMap<(Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>), &'ll Value>>, /// Cache of constant strings, pub const_str_cache: RefCell<FxHashMap<String, &'ll Value>>, @@ -663,15 +662,14 @@ impl<'ll> SimpleCx<'ll> { impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn vtables( &self, - ) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), &'ll Value>> - { + ) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>), &'ll Value>> { &self.vtables } fn apply_vcall_visibility_metadata( &self, ty: Ty<'tcx>, - poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, + poly_trait_ref: Option<ty::ExistentialTraitRef<'tcx>>, vtable: &'ll Value, ) { apply_vcall_visibility_metadata(self, ty, poly_trait_ref, vtable); diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index fd22421c7fc..9a2473d6cf2 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -298,7 +298,7 @@ struct UsageSets<'tcx> { /// Prepare sets of definitions that are relevant to deciding whether something /// is an "unused function" for coverage purposes. fn prepare_usage_sets<'tcx>(tcx: TyCtxt<'tcx>) -> UsageSets<'tcx> { - let MonoItemPartitions { all_mono_items, codegen_units } = + let MonoItemPartitions { all_mono_items, codegen_units, .. } = tcx.collect_and_partition_mono_items(()); // Obtain a MIR body for each function participating in codegen, via an diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 8d782a618fc..3a0c7f007bd 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -13,7 +13,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::bug; use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::{ - self, AdtKind, CoroutineArgsExt, Instance, PolyExistentialTraitRef, Ty, TyCtxt, Visibility, + self, AdtKind, CoroutineArgsExt, ExistentialTraitRef, Instance, Ty, TyCtxt, Visibility, }; use rustc_session::config::{self, DebugInfo, Lto}; use rustc_span::{DUMMY_SP, FileName, FileNameDisplayPreference, SourceFile, Symbol, hygiene}; @@ -919,8 +919,7 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>( .unwrap_or_default(); let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo); - let dwarf_version = - tcx.sess.opts.unstable_opts.dwarf_version.unwrap_or(tcx.sess.target.default_dwarf_version); + let dwarf_version = tcx.sess.dwarf_version(); let is_dwarf_kind = matches!(tcx.sess.target.debuginfo_kind, DebuginfoKind::Dwarf | DebuginfoKind::DwarfDsym); // Don't emit `.debug_pubnames` and `.debug_pubtypes` on DWARFv4 or lower. @@ -1400,7 +1399,7 @@ pub(crate) fn build_global_var_di_node<'ll>( fn build_vtable_type_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, - poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, + poly_trait_ref: Option<ty::ExistentialTraitRef<'tcx>>, ) -> &'ll DIType { let tcx = cx.tcx; @@ -1488,10 +1487,30 @@ fn build_vtable_type_di_node<'ll, 'tcx>( .di_node } +/// Get the global variable for the vtable. +/// +/// When using global variables, we may have created an addrspacecast to get a pointer to the +/// default address space if global variables are created in a different address space. +/// For modifying the vtable, we need the real global variable. This function accepts either a +/// global variable (which is simply returned), or an addrspacecast constant expression. +/// If the given value is an addrspacecast, the cast is removed and the global variable behind +/// the cast is returned. +fn find_vtable_behind_cast<'ll>(vtable: &'ll Value) -> &'ll Value { + // The vtable is a global variable, which may be behind an addrspacecast. + unsafe { + if let Some(c) = llvm::LLVMIsAConstantExpr(vtable) { + if llvm::LLVMGetConstOpcode(c) == llvm::Opcode::AddrSpaceCast { + return llvm::LLVMGetOperand(c, 0).unwrap(); + } + } + } + vtable +} + pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, - trait_ref: Option<PolyExistentialTraitRef<'tcx>>, + trait_ref: Option<ExistentialTraitRef<'tcx>>, vtable: &'ll Value, ) { // FIXME(flip1995): The virtual function elimination optimization only works with full LTO in @@ -1508,9 +1527,11 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( let Some(trait_ref) = trait_ref else { return }; + // Unwrap potential addrspacecast + let vtable = find_vtable_behind_cast(vtable); let trait_ref_self = trait_ref.with_self_ty(cx.tcx, ty); let trait_ref_self = cx.tcx.erase_regions(trait_ref_self); - let trait_def_id = trait_ref_self.def_id(); + let trait_def_id = trait_ref_self.def_id; let trait_vis = cx.tcx.visibility(trait_def_id); let cgus = cx.sess().codegen_units().as_usize(); @@ -1569,7 +1590,7 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>( pub(crate) fn create_vtable_di_node<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, - poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, + poly_trait_ref: Option<ty::ExistentialTraitRef<'tcx>>, vtable: &'ll Value, ) { if cx.dbg_cx.is_none() { @@ -1581,6 +1602,9 @@ pub(crate) fn create_vtable_di_node<'ll, 'tcx>( return; } + // Unwrap potential addrspacecast + let vtable = find_vtable_behind_cast(vtable); + // When full debuginfo is enabled, we want to try and prevent vtables from being // merged. Otherwise debuggers will have a hard time mapping from dyn pointer // to concrete type. diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs index a37e719d43f..af1d503ad6a 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_macros::HashStable; use rustc_middle::bug; -use rustc_middle::ty::{self, PolyExistentialTraitRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, ExistentialTraitRef, Ty, TyCtxt}; use super::{DefinitionLocation, SmallVec, UNKNOWN_LINE_NUMBER, unknown_file_metadata}; use crate::common::{AsCCharPtr, CodegenCx}; @@ -44,7 +44,7 @@ pub(super) enum UniqueTypeId<'tcx> { /// The ID for the additional wrapper struct type describing an enum variant in CPP-like mode. VariantStructTypeCppLikeWrapper(Ty<'tcx>, VariantIdx, private::HiddenZst), /// The ID of the artificial type we create for VTables. - VTableTy(Ty<'tcx>, Option<PolyExistentialTraitRef<'tcx>>, private::HiddenZst), + VTableTy(Ty<'tcx>, Option<ExistentialTraitRef<'tcx>>, private::HiddenZst), } impl<'tcx> UniqueTypeId<'tcx> { @@ -88,7 +88,7 @@ impl<'tcx> UniqueTypeId<'tcx> { pub(crate) fn for_vtable_ty( tcx: TyCtxt<'tcx>, self_type: Ty<'tcx>, - implemented_trait: Option<PolyExistentialTraitRef<'tcx>>, + implemented_trait: Option<ExistentialTraitRef<'tcx>>, ) -> Self { assert_eq!( self_type, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index e6778411365..b1ce52667bd 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -22,6 +22,7 @@ use rustc_session::config::{self, DebugInfo}; use rustc_span::{ BytePos, Pos, SourceFile, SourceFileAndLine, SourceFileHash, Span, StableSourceFileId, Symbol, }; +use rustc_target::spec::DebuginfoKind; use smallvec::SmallVec; use tracing::debug; @@ -93,29 +94,31 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { pub(crate) fn finalize(&self, sess: &Session) { unsafe { llvm::LLVMRustDIBuilderFinalize(self.builder) }; - if !sess.target.is_like_msvc { - // Debuginfo generation in LLVM by default uses a higher - // version of dwarf than macOS currently understands. We can - // instruct LLVM to emit an older version of dwarf, however, - // for macOS to understand. For more info see #11352 - // This can be overridden using --llvm-opts -dwarf-version,N. - // Android has the same issue (#22398) - let dwarf_version = - sess.opts.unstable_opts.dwarf_version.unwrap_or(sess.target.default_dwarf_version); - llvm::add_module_flag_u32( - self.llmod, - llvm::ModuleFlagMergeBehavior::Warning, - "Dwarf Version", - dwarf_version, - ); - } else { - // Indicate that we want CodeView debug information on MSVC - llvm::add_module_flag_u32( - self.llmod, - llvm::ModuleFlagMergeBehavior::Warning, - "CodeView", - 1, - ); + + match sess.target.debuginfo_kind { + DebuginfoKind::Dwarf | DebuginfoKind::DwarfDsym => { + // Debuginfo generation in LLVM by default uses a higher + // version of dwarf than macOS currently understands. We can + // instruct LLVM to emit an older version of dwarf, however, + // for macOS to understand. For more info see #11352 + // This can be overridden using --llvm-opts -dwarf-version,N. + // Android has the same issue (#22398) + llvm::add_module_flag_u32( + self.llmod, + llvm::ModuleFlagMergeBehavior::Warning, + "Dwarf Version", + sess.dwarf_version(), + ); + } + DebuginfoKind::Pdb => { + // Indicate that we want CodeView debug information + llvm::add_module_flag_u32( + self.llmod, + llvm::ModuleFlagMergeBehavior::Warning, + "CodeView", + 1, + ); + } } // Prevent bitcode readers from deleting the debug info. @@ -585,7 +588,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn create_vtable_debuginfo( &self, ty: Ty<'tcx>, - trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, + trait_ref: Option<ty::ExistentialTraitRef<'tcx>>, vtable: Self::Value, ) { metadata::create_vtable_di_node(self, ty, trait_ref, vtable) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index eab4a9f30c9..43d6ccfcb4a 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1329,7 +1329,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( } if name == sym::simd_shuffle_generic { - let idx = fn_args[2].expect_const().try_to_valtree().unwrap().0.unwrap_branch(); + let idx = fn_args[2].expect_const().to_value().valtree.unwrap_branch(); let n = idx.len() as u64; let (out_len, out_ty) = require_simd!(ret_ty, SimdReturn); diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index 729d6f62e24..92b0ce8ffe1 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -4,16 +4,23 @@ use libc::{c_char, c_uint}; use super::ffi::{BasicBlock, Metadata, Module, Type, Value}; use crate::llvm::Bool; + +#[link(name = "llvm-wrapper", kind = "static")] extern "C" { // Enzyme pub fn LLVMRustHasMetadata(I: &Value, KindID: c_uint) -> bool; - pub fn LLVMRustEraseInstBefore(BB: &BasicBlock, I: &Value); + pub fn LLVMRustEraseInstUntilInclusive(BB: &BasicBlock, I: &Value); pub fn LLVMRustGetLastInstruction<'a>(BB: &BasicBlock) -> Option<&'a Value>; pub fn LLVMRustDIGetInstMetadata(I: &Value) -> Option<&Metadata>; pub fn LLVMRustEraseInstFromParent(V: &Value); pub fn LLVMRustGetTerminator<'a>(B: &BasicBlock) -> &'a Value; pub fn LLVMRustVerifyFunction(V: &Value, action: LLVMRustVerifierFailureAction) -> Bool; +} +extern "C" { + // Enzyme + pub fn LLVMDumpModule(M: &Module); + pub fn LLVMDumpValue(V: &Value); pub fn LLVMGetFunctionCallConv(F: &Value) -> c_uint; pub fn LLVMGetReturnType(T: &Type) -> &Type; pub fn LLVMGetParams(Fnc: &Value, parms: *mut &Value); diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 009d15a932f..cc7c5231aca 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -661,6 +661,79 @@ pub enum MemoryEffects { InaccessibleMemOnly, } +/// LLVMOpcode +#[derive(Copy, Clone, PartialEq, Eq)] +#[repr(C)] +pub enum Opcode { + Ret = 1, + Br = 2, + Switch = 3, + IndirectBr = 4, + Invoke = 5, + Unreachable = 7, + CallBr = 67, + FNeg = 66, + Add = 8, + FAdd = 9, + Sub = 10, + FSub = 11, + Mul = 12, + FMul = 13, + UDiv = 14, + SDiv = 15, + FDiv = 16, + URem = 17, + SRem = 18, + FRem = 19, + Shl = 20, + LShr = 21, + AShr = 22, + And = 23, + Or = 24, + Xor = 25, + Alloca = 26, + Load = 27, + Store = 28, + GetElementPtr = 29, + Trunc = 30, + ZExt = 31, + SExt = 32, + FPToUI = 33, + FPToSI = 34, + UIToFP = 35, + SIToFP = 36, + FPTrunc = 37, + FPExt = 38, + PtrToInt = 39, + IntToPtr = 40, + BitCast = 41, + AddrSpaceCast = 60, + ICmp = 42, + FCmp = 43, + PHI = 44, + Call = 45, + Select = 46, + UserOp1 = 47, + UserOp2 = 48, + VAArg = 49, + ExtractElement = 50, + InsertElement = 51, + ShuffleVector = 52, + ExtractValue = 53, + InsertValue = 54, + Freeze = 68, + Fence = 55, + AtomicCmpXchg = 56, + AtomicRMW = 57, + Resume = 58, + LandingPad = 59, + CleanupRet = 61, + CatchRet = 62, + CatchPad = 63, + CleanupPad = 64, + CatchSwitch = 65, +} + unsafe extern "C" { type Opaque; } @@ -991,7 +1064,10 @@ unsafe extern "C" { pub fn LLVMConstPtrToInt<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value; pub fn LLVMConstIntToPtr<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value; pub fn LLVMConstBitCast<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value; + pub fn LLVMConstPointerCast<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value; pub fn LLVMGetAggregateElement(ConstantVal: &Value, Idx: c_uint) -> Option<&Value>; + pub fn LLVMGetConstOpcode(ConstantVal: &Value) -> Opcode; + pub fn LLVMIsAConstantExpr(Val: &Value) -> Option<&Value>; // Operations on global variables, functions, and aliases (globals) pub fn LLVMIsDeclaration(Global: &Value) -> Bool; @@ -1048,6 +1124,7 @@ unsafe extern "C" { // Operations on instructions pub fn LLVMIsAInstruction(Val: &Value) -> Option<&Value>; pub fn LLVMGetFirstBasicBlock(Fn: &Value) -> &BasicBlock; + pub fn LLVMGetOperand(Val: &Value, Index: c_uint) -> Option<&Value>; // Operations on call sites pub fn LLVMSetInstructionCallConv(Instr: &Value, CC: c_uint); diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index de37de09f5a..22e262546c3 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -16,6 +16,8 @@ codegen_ssa_archive_build_failure = failed to build archive at `{$path}`: {$erro codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing failure memory ordering +codegen_ssa_autodiff_without_lto = using the autodiff feature requires using fat-lto + codegen_ssa_binary_output_to_tty = option `-o` or `--emit` is used to write binary output type `{$shorthand}` to stdout, but stdout is a tty codegen_ssa_cgu_not_recorded = @@ -30,6 +32,8 @@ codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error} codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$error} +codegen_ssa_cpu_required = target requires explicitly specifying a cpu with `-C target-cpu` + codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error} codegen_ssa_dlltool_fail_import_library = diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index b40bb4ed5d2..ce2161a07eb 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -7,6 +7,7 @@ use std::sync::mpsc::{Receiver, Sender, channel}; use std::{fs, io, mem, str, thread}; use rustc_ast::attr; +use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::jobserver::{self, Acquired}; use rustc_data_structures::memmap::Mmap; @@ -40,7 +41,7 @@ use tracing::debug; use super::link::{self, ensure_removed}; use super::lto::{self, SerializedModule}; use super::symbol_export::symbol_name_for_instance_in_crate; -use crate::errors::ErrorCreatingRemarkDir; +use crate::errors::{AutodiffWithoutLto, ErrorCreatingRemarkDir}; use crate::traits::*; use crate::{ CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind, @@ -118,6 +119,7 @@ pub struct ModuleConfig { pub merge_functions: bool, pub emit_lifetime_markers: bool, pub llvm_plugins: Vec<String>, + pub autodiff: Vec<config::AutoDiff>, } impl ModuleConfig { @@ -266,6 +268,7 @@ impl ModuleConfig { emit_lifetime_markers: sess.emit_lifetime_markers(), llvm_plugins: if_regular!(sess.opts.unstable_opts.llvm_plugins.clone(), vec![]), + autodiff: if_regular!(sess.opts.unstable_opts.autodiff.clone(), vec![]), } } @@ -389,6 +392,7 @@ impl<B: WriteBackendMethods> CodegenContext<B> { fn generate_lto_work<B: ExtraBackendMethods>( cgcx: &CodegenContext<B>, + autodiff: Vec<AutoDiffItem>, needs_fat_lto: Vec<FatLtoInput<B>>, needs_thin_lto: Vec<(String, B::ThinBuffer)>, import_only_modules: Vec<(SerializedModule<B::ModuleBuffer>, WorkProduct)>, @@ -397,11 +401,19 @@ fn generate_lto_work<B: ExtraBackendMethods>( if !needs_fat_lto.is_empty() { assert!(needs_thin_lto.is_empty()); - let module = + let mut module = B::run_fat_lto(cgcx, needs_fat_lto, import_only_modules).unwrap_or_else(|e| e.raise()); + if cgcx.lto == Lto::Fat && !autodiff.is_empty() { + let config = cgcx.config(ModuleKind::Regular); + module = unsafe { module.autodiff(cgcx, autodiff, config).unwrap() }; + } // We are adding a single work item, so the cost doesn't matter. vec![(WorkItem::LTO(module), 0)] } else { + if !autodiff.is_empty() { + let dcx = cgcx.create_dcx(); + dcx.handle().emit_fatal(AutodiffWithoutLto {}); + } assert!(needs_fat_lto.is_empty()); let (lto_modules, copy_jobs) = B::run_thin_lto(cgcx, needs_thin_lto, import_only_modules) .unwrap_or_else(|e| e.raise()); @@ -1021,6 +1033,9 @@ pub(crate) enum Message<B: WriteBackendMethods> { /// Sent from a backend worker thread. WorkItem { result: Result<WorkItemResult<B>, Option<WorkerFatalError>>, worker_id: usize }, + /// A vector containing all the AutoDiff tasks that we have to pass to Enzyme. + AddAutoDiffItems(Vec<AutoDiffItem>), + /// The frontend has finished generating something (backend IR or a /// post-LTO artifact) for a codegen unit, and it should be passed to the /// backend. Sent from the main thread. @@ -1348,6 +1363,7 @@ fn start_executing_work<B: ExtraBackendMethods>( // This is where we collect codegen units that have gone all the way // through codegen and LLVM. + let mut autodiff_items = Vec::new(); let mut compiled_modules = vec![]; let mut compiled_allocator_module = None; let mut needs_link = Vec::new(); @@ -1459,9 +1475,13 @@ fn start_executing_work<B: ExtraBackendMethods>( let needs_thin_lto = mem::take(&mut needs_thin_lto); let import_only_modules = mem::take(&mut lto_import_only_modules); - for (work, cost) in - generate_lto_work(&cgcx, needs_fat_lto, needs_thin_lto, import_only_modules) - { + for (work, cost) in generate_lto_work( + &cgcx, + autodiff_items.clone(), + needs_fat_lto, + needs_thin_lto, + import_only_modules, + ) { let insertion_index = work_items .binary_search_by_key(&cost, |&(_, cost)| cost) .unwrap_or_else(|e| e); @@ -1596,6 +1616,10 @@ fn start_executing_work<B: ExtraBackendMethods>( main_thread_state = MainThreadState::Idle; } + Message::AddAutoDiffItems(mut items) => { + autodiff_items.append(&mut items); + } + Message::CodegenComplete => { if codegen_state != Aborted { codegen_state = Completed; @@ -2070,6 +2094,10 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> { drop(self.coordinator.sender.send(Box::new(Message::CodegenComplete::<B>))); } + pub(crate) fn submit_autodiff_items(&self, items: Vec<AutoDiffItem>) { + drop(self.coordinator.sender.send(Box::new(Message::<B>::AddAutoDiffItems(items)))); + } + pub(crate) fn check_for_errors(&self, sess: &Session) { self.shared_emitter_main.check(sess, false); } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index e438bd70c51..df945920ee8 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -18,14 +18,13 @@ use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, Debugger use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_middle::middle::{exported_symbols, lang_items}; use rustc_middle::mir::BinOp; -use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; +use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem, MonoItemPartitions}; use rustc_middle::query::Providers; use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_session::Session; use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType}; use rustc_span::{DUMMY_SP, Symbol, sym}; -use rustc_trait_selection::infer::at::ToTrace; use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt}; use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; use tracing::{debug, info}; @@ -129,14 +128,9 @@ pub fn validate_trivial_unsize<'tcx>( BoundRegionConversionTime::HigherRankedType, hr_source_principal, ); - let Ok(()) = ocx.eq_trace( + let Ok(()) = ocx.eq( &ObligationCause::dummy(), param_env, - ToTrace::to_trace( - &ObligationCause::dummy(), - hr_target_principal, - hr_source_principal, - ), target_principal, source_principal, ) else { @@ -211,7 +205,12 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( old_info } } - (_, ty::Dynamic(data, _, _)) => meth::get_vtable(cx, source, data.principal()), + (_, ty::Dynamic(data, _, _)) => meth::get_vtable( + cx, + source, + data.principal() + .map(|principal| bx.tcx().instantiate_bound_regions_with_erased(principal)), + ), _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target), } } @@ -615,11 +614,18 @@ pub fn codegen_crate<B: ExtraBackendMethods>( return ongoing_codegen; } + if tcx.sess.target.need_explicit_cpu && tcx.sess.opts.cg.target_cpu.is_none() { + // The target has no default cpu, but none is set explicitly + tcx.dcx().emit_fatal(errors::CpuRequired); + } + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); // Run the monomorphization collector and partition the collected items into // codegen units. - let codegen_units = tcx.collect_and_partition_mono_items(()).codegen_units; + let MonoItemPartitions { codegen_units, autodiff_items, .. } = + tcx.collect_and_partition_mono_items(()); + let autodiff_fncs = autodiff_items.to_vec(); // Force all codegen_unit queries so they are already either red or green // when compile_codegen_unit accesses them. We are not able to re-execute @@ -628,7 +634,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>( // unnecessarily. if tcx.dep_graph.is_fully_enabled() { for cgu in codegen_units { - tcx.ensure().codegen_unit(cgu.name()); + tcx.ensure_ok().codegen_unit(cgu.name()); } } @@ -690,6 +696,10 @@ pub fn codegen_crate<B: ExtraBackendMethods>( ); } + if !autodiff_fncs.is_empty() { + ongoing_codegen.submit_autodiff_items(autodiff_fncs); + } + // For better throughput during parallel processing by LLVM, we used to sort // CGUs largest to smallest. This would lead to better thread utilization // by, for example, preventing a large CGU from being processed last and diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index a0bc2d4ea48..4166387dad0 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,5 +1,10 @@ +use std::str::FromStr; + use rustc_ast::attr::list_contains_name; -use rustc_ast::{MetaItemInner, attr}; +use rustc_ast::expand::autodiff_attrs::{ + AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ret_activity, +}; +use rustc_ast::{MetaItem, MetaItemInner, attr}; use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::codes::*; @@ -13,6 +18,7 @@ use rustc_middle::middle::codegen_fn_attrs::{ }; use rustc_middle::mir::mono::Linkage; use rustc_middle::query::Providers; +use rustc_middle::span_bug; use rustc_middle::ty::{self as ty, TyCtxt}; use rustc_session::parse::feature_err; use rustc_session::{Session, lint}; @@ -65,6 +71,13 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; } + // If our rustc version supports autodiff/enzyme, then we call our handler + // to check for any `#[rustc_autodiff(...)]` attributes. + if cfg!(llvm_enzyme) { + let ad = autodiff_attrs(tcx, did.into()); + codegen_fn_attrs.autodiff_item = ad; + } + // When `no_builtins` is applied at the crate level, we should add the // `no-builtins` attribute to each function to ensure it takes effect in LTO. let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); @@ -856,6 +869,109 @@ impl<'a> MixedExportNameAndNoMangleState<'a> { } } +/// We now check the #\[rustc_autodiff\] attributes which we generated from the #[autodiff(...)] +/// macros. There are two forms. The pure one without args to mark primal functions (the functions +/// being differentiated). The other form is #[rustc_autodiff(Mode, ActivityList)] on top of the +/// placeholder functions. We wrote the rustc_autodiff attributes ourself, so this should never +/// panic, unless we introduced a bug when parsing the autodiff macro. +fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> { + let attrs = tcx.get_attrs(id, sym::rustc_autodiff); + + let attrs = + attrs.filter(|attr| attr.name_or_empty() == sym::rustc_autodiff).collect::<Vec<_>>(); + + // check for exactly one autodiff attribute on placeholder functions. + // There should only be one, since we generate a new placeholder per ad macro. + // FIXME(ZuseZ4): re-enable this check. Currently we add multiple, which doesn't cause harm but + // looks strange e.g. under cargo-expand. + let attr = match &attrs[..] { + [] => return None, + [attr] => attr, + // These two attributes are the same and unfortunately duplicated due to a previous bug. + [attr, _attr2] => attr, + _ => { + //FIXME(ZuseZ4): Once we fixed our parser, we should also prohibit the two-attribute + //branch above. + span_bug!(attrs[1].span, "cg_ssa: rustc_autodiff should only exist once per source"); + } + }; + + let list = attr.meta_item_list().unwrap_or_default(); + + // empty autodiff attribute macros (i.e. `#[autodiff]`) are used to mark source functions + if list.is_empty() { + return Some(AutoDiffAttrs::source()); + } + + let [mode, input_activities @ .., ret_activity] = &list[..] else { + span_bug!(attr.span, "rustc_autodiff attribute must contain mode and activities"); + }; + let mode = if let MetaItemInner::MetaItem(MetaItem { path: ref p1, .. }) = mode { + p1.segments.first().unwrap().ident + } else { + span_bug!(attr.span, "rustc_autodiff attribute must contain mode"); + }; + + // parse mode + let mode = match mode.as_str() { + "Forward" => DiffMode::Forward, + "Reverse" => DiffMode::Reverse, + "ForwardFirst" => DiffMode::ForwardFirst, + "ReverseFirst" => DiffMode::ReverseFirst, + _ => { + span_bug!(mode.span, "rustc_autodiff attribute contains invalid mode"); + } + }; + + // First read the ret symbol from the attribute + let ret_symbol = if let MetaItemInner::MetaItem(MetaItem { path: ref p1, .. }) = ret_activity { + p1.segments.first().unwrap().ident + } else { + span_bug!(attr.span, "rustc_autodiff attribute must contain the return activity"); + }; + + // Then parse it into an actual DiffActivity + let Ok(ret_activity) = DiffActivity::from_str(ret_symbol.as_str()) else { + span_bug!(ret_symbol.span, "invalid return activity"); + }; + + // Now parse all the intermediate (input) activities + let mut arg_activities: Vec<DiffActivity> = vec![]; + for arg in input_activities { + let arg_symbol = if let MetaItemInner::MetaItem(MetaItem { path: ref p2, .. }) = arg { + match p2.segments.first() { + Some(x) => x.ident, + None => { + span_bug!( + arg.span(), + "rustc_autodiff attribute must contain the input activity" + ); + } + } + } else { + span_bug!(arg.span(), "rustc_autodiff attribute must contain the input activity"); + }; + + match DiffActivity::from_str(arg_symbol.as_str()) { + Ok(arg_activity) => arg_activities.push(arg_activity), + Err(_) => { + span_bug!(arg_symbol.span, "invalid input activity"); + } + } + } + + for &input in &arg_activities { + if !valid_input_activity(mode, input) { + span_bug!(attr.span, "Invalid input activity {} for {} mode", input, mode); + } + } + if !valid_ret_activity(mode, ret_activity) { + span_bug!(attr.span, "Invalid return activity {} for {} mode", ret_activity, mode); + } + + Some(AutoDiffAttrs { mode, ret_activity, input_activity: arg_activities }) +} + pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers }; } diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 869798d8be1..05175371591 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -507,7 +507,7 @@ pub enum VTableNameKind { pub fn compute_debuginfo_vtable_name<'tcx>( tcx: TyCtxt<'tcx>, t: Ty<'tcx>, - trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, + trait_ref: Option<ty::ExistentialTraitRef<'tcx>>, kind: VTableNameKind, ) -> String { let cpp_like_debuginfo = cpp_like_debuginfo(tcx); @@ -530,8 +530,8 @@ pub fn compute_debuginfo_vtable_name<'tcx>( } if let Some(trait_ref) = trait_ref { - let trait_ref = tcx - .normalize_erasing_late_bound_regions(ty::TypingEnv::fully_monomorphized(), trait_ref); + let trait_ref = + tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref); push_item_name(tcx, trait_ref.def_id, true, &mut vtable_name); visited.clear(); push_generic_params_internal(tcx, trait_ref.args, &mut vtable_name, &mut visited); @@ -673,25 +673,23 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S ty::ConstKind::Param(param) => { write!(output, "{}", param.name) } - ty::ConstKind::Value(ty, valtree) => { - match ty.kind() { + ty::ConstKind::Value(cv) => { + match cv.ty.kind() { ty::Int(ity) => { - // FIXME: directly extract the bits from a valtree instead of evaluating an - // already evaluated `Const` in order to get the bits. - let bits = ct + let bits = cv .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized()) .expect("expected monomorphic const in codegen"); let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; write!(output, "{val}") } ty::Uint(_) => { - let val = ct + let val = cv .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized()) .expect("expected monomorphic const in codegen"); write!(output, "{val}") } ty::Bool => { - let val = ct.try_to_bool().expect("expected monomorphic const in codegen"); + let val = cv.try_to_bool().expect("expected monomorphic const in codegen"); write!(output, "{val}") } _ => { @@ -703,9 +701,7 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S // avoiding collisions and will make the emitted type names shorter. let hash_short = tcx.with_stable_hashing_context(|mut hcx| { let mut hasher = StableHasher::new(); - hcx.while_hashing_spans(false, |hcx| { - (ty, valtree).hash_stable(hcx, &mut hasher) - }); + hcx.while_hashing_spans(false, |hcx| cv.hash_stable(hcx, &mut hasher)); hasher.finish::<Hash64>() }); diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 5e684632fb2..3ddbe4aeeec 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -40,6 +40,10 @@ pub(crate) struct CguNotRecorded<'a> { } #[derive(Diagnostic)] +#[diag(codegen_ssa_autodiff_without_lto)] +pub struct AutodiffWithoutLto; + +#[derive(Diagnostic)] #[diag(codegen_ssa_unknown_reuse_kind)] pub(crate) struct UnknownReuseKind { #[primary_span] @@ -524,6 +528,10 @@ pub(crate) struct CheckInstalledVisualStudio; pub(crate) struct InsufficientVSCodeProduct; #[derive(Diagnostic)] +#[diag(codegen_ssa_cpu_required)] +pub(crate) struct CpuRequired; + +#[derive(Diagnostic)] #[diag(codegen_ssa_processing_dymutil_failed)] #[note] pub(crate) struct ProcessingDymutilFailed { diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index 64cd4c38937..399c592432a 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -1,5 +1,5 @@ use rustc_middle::bug; -use rustc_middle::ty::{self, GenericArgKind, Ty}; +use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt}; use rustc_session::config::Lto; use rustc_symbol_mangling::typeid_for_trait_ref; use rustc_target::callconv::FnAbi; @@ -72,12 +72,19 @@ impl<'a, 'tcx> VirtualIndex { /// This takes a valid `self` receiver type and extracts the principal trait /// ref of the type. Return `None` if there is no principal trait. -fn dyn_trait_in_self(ty: Ty<'_>) -> Option<ty::PolyExistentialTraitRef<'_>> { +fn dyn_trait_in_self<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Option<ty::ExistentialTraitRef<'tcx>> { for arg in ty.peel_refs().walk() { if let GenericArgKind::Type(ty) = arg.unpack() && let ty::Dynamic(data, _, _) = ty.kind() { - return data.principal(); + // FIXME(arbitrary_self_types): This is likely broken for receivers which + // have a "non-self" trait objects as a generic argument. + return data + .principal() + .map(|principal| tcx.instantiate_bound_regions_with_erased(principal)); } } @@ -96,7 +103,7 @@ fn dyn_trait_in_self(ty: Ty<'_>) -> Option<ty::PolyExistentialTraitRef<'_>> { pub(crate) fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( cx: &Cx, ty: Ty<'tcx>, - trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, + trait_ref: Option<ty::ExistentialTraitRef<'tcx>>, ) -> Cx::Value { let tcx = cx.tcx(); @@ -131,7 +138,7 @@ pub(crate) fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( if bx.cx().sess().opts.unstable_opts.virtual_function_elimination && bx.cx().sess().lto() == Lto::Fat { - if let Some(trait_ref) = dyn_trait_in_self(ty) { + if let Some(trait_ref) = dyn_trait_in_self(bx.tcx(), ty) { let typeid = bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref)).unwrap(); let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid); return func; diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index b0a1dedd646..4be363ca9a2 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -713,6 +713,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // and `#[track_caller]` adds an implicit third argument. (LangItem::PanicMisalignedPointerDereference, vec![required, found, location]) } + AssertKind::NullPointerDereference => { + // It's `fn panic_null_pointer_dereference()`, + // `#[track_caller]` adds an implicit argument. + (LangItem::PanicNullPointerDereference, vec![location]) + } _ => { // It's `pub fn panic_...()` and `#[track_caller]` adds an implicit argument. (msg.panic_function(), vec![location]) diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 7676e1e171a..eafc551501c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -43,7 +43,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Const::Ty(_, c) => match c.kind() { // A constant that came from a const generic but was then used as an argument to // old-style simd_shuffle (passing as argument instead of as a generic param). - rustc_type_ir::ConstKind::Value(_, valtree) => return Ok(Ok(valtree)), + rustc_type_ir::ConstKind::Value(cv) => return Ok(Ok(cv.valtree)), other => span_bug!(constant.span, "{other:#?}"), }, // We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index c634f864ffb..73a41676802 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -502,6 +502,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bug!("encountered OpaqueCast({ty}) in codegen") } mir::ProjectionElem::Subtype(ty) => cg_base.project_type(bx, self.monomorphize(ty)), + mir::ProjectionElem::UnwrapUnsafeBinder(ty) => { + cg_base.project_type(bx, self.monomorphize(ty)) + } mir::ProjectionElem::Index(index) => { let index = &mir::Operand::Copy(mir::Place::from(index)); let index = self.codegen_operand(bx, index); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index d7fc5e8e673..85de3238b3e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -823,6 +823,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandRef { val: OperandValue::Immediate(val), layout: box_layout } } + mir::Rvalue::WrapUnsafeBinder(ref operand, binder_ty) => { + let operand = self.codegen_operand(bx, operand); + let binder_ty = self.monomorphize(binder_ty); + let layout = bx.cx().layout_of(binder_ty); + OperandRef { val: operand.val, layout } + } } } @@ -1123,7 +1129,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::Discriminant(..) | mir::Rvalue::NullaryOp(..) | mir::Rvalue::ThreadLocalRef(_) | - mir::Rvalue::Use(..) => // (*) + mir::Rvalue::Use(..) | + mir::Rvalue::WrapUnsafeBinder(..) => // (*) true, // Arrays are always aggregates, so it's not worth checking anything here. // (If it's really `[(); N]` or `[T; 0]` and we use the place path, fine.) diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs index fe135e911fb..30d77c206a5 100644 --- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs @@ -2,7 +2,7 @@ use std::ops::Range; use rustc_abi::Size; use rustc_middle::mir; -use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty}; +use rustc_middle::ty::{ExistentialTraitRef, Instance, Ty}; use rustc_span::{SourceFile, Span, Symbol}; use rustc_target::callconv::FnAbi; @@ -13,7 +13,7 @@ pub trait DebugInfoCodegenMethods<'tcx>: BackendTypes { fn create_vtable_debuginfo( &self, ty: Ty<'tcx>, - trait_ref: Option<PolyExistentialTraitRef<'tcx>>, + trait_ref: Option<ExistentialTraitRef<'tcx>>, vtable: Self::Value, ); diff --git a/compiler/rustc_codegen_ssa/src/traits/misc.rs b/compiler/rustc_codegen_ssa/src/traits/misc.rs index 5b33fd7ab10..4004947b464 100644 --- a/compiler/rustc_codegen_ssa/src/traits/misc.rs +++ b/compiler/rustc_codegen_ssa/src/traits/misc.rs @@ -10,11 +10,11 @@ use super::BackendTypes; pub trait MiscCodegenMethods<'tcx>: BackendTypes { fn vtables( &self, - ) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), Self::Value>>; + ) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>), Self::Value>>; fn apply_vcall_visibility_metadata( &self, _ty: Ty<'tcx>, - _poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, + _poly_trait_ref: Option<ty::ExistentialTraitRef<'tcx>>, _vtable: Self::Value, ) { } diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index d600d223bff..eecc6690f51 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -280,7 +280,9 @@ const_eval_nullary_intrinsic_fail = could not evaluate nullary intrinsic const_eval_offset_from_different_allocations = - `{$name}` called on pointers into different allocations + `{$name}` called on two different pointers that are not both derived from the same allocation +const_eval_offset_from_out_of_bounds = + `{$name}` called on two different pointers where the memory range between them is not in-bounds of an allocation const_eval_offset_from_overflow = `{$name}` called when first pointer is too far ahead of second const_eval_offset_from_test = diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 16ead1b9785..e8052a3c83a 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -634,7 +634,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::RawPtr(RawPtrKind::FakeForPtrMetadata, place) => { // These are only inserted for slice length, so the place must already be indirect. // This implies we do not have to worry about whether the borrow escapes. - assert!(place.is_indirect(), "fake borrows are always indirect"); + if !place.is_indirect() { + self.tcx.dcx().span_delayed_bug( + self.body.source_info(location).span, + "fake borrows are always indirect", + ); + } } Rvalue::Cast( @@ -723,6 +728,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { ); } } + + Rvalue::WrapUnsafeBinder(..) => { + // Unsafe binders are always trivial to create. + } } } diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index e244b50a4b5..9c99782d223 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -258,6 +258,8 @@ where in_place::<Q, _>(cx, in_local, place.as_ref()) } + Rvalue::WrapUnsafeBinder(op, _) => in_operand::<Q, _>(cx, in_local, op), + Rvalue::Aggregate(kind, operands) => { // Return early if we know that the struct or enum being constructed is always // qualified. @@ -297,7 +299,8 @@ where | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(_, _) - | ProjectionElem::Index(_) => {} + | ProjectionElem::Index(_) + | ProjectionElem::UnwrapUnsafeBinder(_) => {} } let base_ty = place_base.ty(cx.body, cx.tcx); @@ -345,7 +348,7 @@ where Const::Ty(_, ct) if matches!( ct.kind(), - ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_, _) + ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_) ) => { None diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index 79df63a9e84..8cee282311f 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -202,7 +202,8 @@ where | mir::Rvalue::NullaryOp(..) | mir::Rvalue::UnaryOp(..) | mir::Rvalue::Discriminant(..) - | mir::Rvalue::Aggregate(..) => {} + | mir::Rvalue::Aggregate(..) + | mir::Rvalue::WrapUnsafeBinder(..) => {} } } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 6a339d69542..82e0a6e6666 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -508,6 +508,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { found: eval_to_int(found)?, } } + NullPointerDereference => NullPointerDereference, }; Err(ConstEvalErrKind::AssertFailure(err)).into() } diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 34f795bda75..c0438fb3ff8 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -1,7 +1,7 @@ // Not in interpret to make sure we do not use private implementation details use rustc_abi::VariantIdx; -use rustc_middle::query::{Key, TyCtxtAt}; +use rustc_middle::query::Key; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, mir}; @@ -35,16 +35,17 @@ pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeC #[instrument(skip(tcx), level = "debug")] pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( - tcx: TyCtxtAt<'tcx>, + tcx: TyCtxt<'tcx>, val: mir::ConstValue<'tcx>, ty: Ty<'tcx>, ) -> Option<mir::DestructuredConstant<'tcx>> { let typing_env = ty::TypingEnv::fully_monomorphized(); - let (ecx, op) = mk_eval_cx_for_const_val(tcx, typing_env, val, ty)?; + // FIXME: use a proper span here? + let (ecx, op) = mk_eval_cx_for_const_val(tcx.at(rustc_span::DUMMY_SP), typing_env, val, ty)?; // We go to `usize` as we cannot allocate anything bigger anyway. let (field_count, variant, down) = match ty.kind() { - ty::Array(_, len) => (len.try_to_target_usize(tcx.tcx)? as usize, None, op), + ty::Array(_, len) => (len.try_to_target_usize(tcx)? as usize, None, op), ty::Adt(def, _) if def.variants().is_empty() => { return None; } diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 4ff8aa9a3b4..4d625f76aba 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -272,7 +272,8 @@ pub(crate) fn eval_to_valtree<'tcx>( /// Converts a `ValTree` to a `ConstValue`, which is needed after mir /// construction has finished. -// FIXME Merge `valtree_to_const_value` and `valtree_into_mplace` into one function +// FIXME(valtrees): Merge `valtree_to_const_value` and `valtree_into_mplace` into one function +// FIXME(valtrees): Accept `ty::Value` instead of `Ty` and `ty::ValTree` separately. #[instrument(skip(tcx), level = "debug", ret)] pub fn valtree_to_const_value<'tcx>( tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index e6a34193c9d..e2e6e16d8a7 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -5,6 +5,7 @@ use std::borrow::Cow; use either::{Left, Right}; use rustc_abi::{self as abi, ExternAbi, FieldIdx, Integer, VariantIdx}; +use rustc_hir::def_id::DefId; use rustc_middle::ty::layout::{FnAbiOf, IntegerExt, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef}; use rustc_middle::{bug, mir, span_bug}; @@ -693,25 +694,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { trace!("Virtual call dispatches to {fn_inst:#?}"); // We can also do the lookup based on `def_id` and `dyn_ty`, and check that that // produces the same result. - if cfg!(debug_assertions) { - let tcx = *self.tcx; - - let trait_def_id = tcx.trait_of_item(def_id).unwrap(); - let virtual_trait_ref = - ty::TraitRef::from_method(tcx, trait_def_id, instance.args); - let existential_trait_ref = - ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref); - let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty); - - let concrete_method = Instance::expect_resolve_for_vtable( - tcx, - self.typing_env, - def_id, - instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args), - self.cur_span(), - ); - assert_eq!(fn_inst, concrete_method); - } + self.assert_virtual_instance_matches_concrete(dyn_ty, def_id, instance, fn_inst); // Adjust receiver argument. Layout can be any (thin) ptr. let receiver_ty = Ty::new_mut_ptr(self.tcx.tcx, dyn_ty); @@ -744,6 +727,30 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } + fn assert_virtual_instance_matches_concrete( + &self, + dyn_ty: Ty<'tcx>, + def_id: DefId, + virtual_instance: ty::Instance<'tcx>, + concrete_instance: ty::Instance<'tcx>, + ) { + let tcx = *self.tcx; + + let trait_def_id = tcx.trait_of_item(def_id).unwrap(); + let virtual_trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, virtual_instance.args); + let existential_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref); + let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty); + + let concrete_method = Instance::expect_resolve_for_vtable( + tcx, + self.typing_env, + def_id, + virtual_instance.args.rebase_onto(tcx, trait_def_id, concrete_trait_ref.args), + self.cur_span(), + ); + assert_eq!(concrete_instance, concrete_method); + } + /// Initiate a tail call to this function -- popping the current stack frame, pushing the new /// stack frame and initializing the arguments. pub(super) fn init_fn_tail_call( diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index ef3e96784ce..e110c155da0 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -414,36 +414,33 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Sanity-check that `supertrait_vtable_slot` in this type's vtable indeed produces // our destination trait. - if cfg!(debug_assertions) { - let vptr_entry_idx = - self.tcx.supertrait_vtable_slot((src_pointee_ty, dest_pointee_ty)); - let vtable_entries = self.vtable_entries(data_a.principal(), ty); - if let Some(entry_idx) = vptr_entry_idx { - let Some(&ty::VtblEntry::TraitVPtr(upcast_trait_ref)) = - vtable_entries.get(entry_idx) - else { - span_bug!( - self.cur_span(), - "invalid vtable entry index in {} -> {} upcast", - src_pointee_ty, - dest_pointee_ty - ); - }; - let erased_trait_ref = upcast_trait_ref - .map_bound(|r| ty::ExistentialTraitRef::erase_self_ty(*self.tcx, r)); - assert!( - data_b - .principal() - .is_some_and(|b| self.eq_in_param_env(erased_trait_ref, b)) + let vptr_entry_idx = + self.tcx.supertrait_vtable_slot((src_pointee_ty, dest_pointee_ty)); + let vtable_entries = self.vtable_entries(data_a.principal(), ty); + if let Some(entry_idx) = vptr_entry_idx { + let Some(&ty::VtblEntry::TraitVPtr(upcast_trait_ref)) = + vtable_entries.get(entry_idx) + else { + span_bug!( + self.cur_span(), + "invalid vtable entry index in {} -> {} upcast", + src_pointee_ty, + dest_pointee_ty ); - } else { - // In this case codegen would keep using the old vtable. We don't want to do - // that as it has the wrong trait. The reason codegen can do this is that - // one vtable is a prefix of the other, so we double-check that. - let vtable_entries_b = self.vtable_entries(data_b.principal(), ty); - assert!(&vtable_entries[..vtable_entries_b.len()] == vtable_entries_b); }; - } + let erased_trait_ref = + ty::ExistentialTraitRef::erase_self_ty(*self.tcx, upcast_trait_ref); + assert!(data_b.principal().is_some_and(|b| self.eq_in_param_env( + erased_trait_ref, + self.tcx.instantiate_bound_regions_with_erased(b) + ))); + } else { + // In this case codegen would keep using the old vtable. We don't want to do + // that as it has the wrong trait. The reason codegen can do this is that + // one vtable is a prefix of the other, so we double-check that. + let vtable_entries_b = self.vtable_entries(data_b.principal(), ty); + assert!(&vtable_entries[..vtable_entries_b.len()] == vtable_entries_b); + }; // Get the destination trait vtable and return that. let new_vptr = self.get_vtable_ptr(ty, data_b)?; diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 0664a882c1d..4ca317e3a1e 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -319,7 +319,25 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Check that the memory between them is dereferenceable at all, starting from the // origin pointer: `dist` is `a - b`, so it is based on `b`. - self.check_ptr_access_signed(b, dist, CheckInAllocMsg::OffsetFromTest)?; + self.check_ptr_access_signed(b, dist, CheckInAllocMsg::OffsetFromTest) + .map_err_kind(|_| { + // This could mean they point to different allocations, or they point to the same allocation + // but not the entire range between the pointers is in-bounds. + if let Ok((a_alloc_id, ..)) = self.ptr_try_get_alloc_id(a, 0) + && let Ok((b_alloc_id, ..)) = self.ptr_try_get_alloc_id(b, 0) + && a_alloc_id == b_alloc_id + { + err_ub_custom!( + fluent::const_eval_offset_from_out_of_bounds, + name = intrinsic_name, + ) + } else { + err_ub_custom!( + fluent::const_eval_offset_from_different_allocations, + name = intrinsic_name, + ) + } + })?; // Then check that this is also dereferenceable from `a`. This ensures that they are // derived from the same allocation. self.check_ptr_access_signed( @@ -747,7 +765,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { { let a: F = self.read_scalar(&args[0])?.to_float()?; let b: F = self.read_scalar(&args[1])?.to_float()?; - let res = self.adjust_nan(a.min(b), &[a, b]); + let res = if a == b { + // They are definitely not NaN (those are never equal), but they could be `+0` and `-0`. + // Let the machine decide which one to return. + M::equal_float_min_max(self, a, b) + } else { + self.adjust_nan(a.min(b), &[a, b]) + }; self.write_scalar(res, dest)?; interp_ok(()) } @@ -762,7 +786,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { { let a: F = self.read_scalar(&args[0])?.to_float()?; let b: F = self.read_scalar(&args[1])?.to_float()?; - let res = self.adjust_nan(a.max(b), &[a, b]); + let res = if a == b { + // They are definitely not NaN (those are never equal), but they could be `+0` and `-0`. + // Let the machine decide which one to return. + M::equal_float_min_max(self, a, b) + } else { + self.adjust_nan(a.max(b), &[a, b]) + }; self.write_scalar(res, dest)?; interp_ok(()) } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 36e5a2ff750..8f6b15b8df0 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -278,6 +278,12 @@ pub trait Machine<'tcx>: Sized { F2::NAN } + /// Determines the result of `min`/`max` on floats when the arguments are equal. + fn equal_float_min_max<F: Float>(_ecx: &InterpCx<'tcx, Self>, a: F, _b: F) -> F { + // By default, we pick the left argument. + a + } + /// Called before a basic block terminator is executed. #[inline] fn before_terminator(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> { diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 996142d7b03..8ecb3e13d5c 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -381,6 +381,7 @@ where OpaqueCast(ty) => { span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck") } + UnwrapUnsafeBinder(target) => base.transmute(self.layout_of(target)?, self)?, // We don't want anything happening here, this is here as a dummy. Subtype(_) => base.transmute(base.layout(), self)?, Field(field, _) => self.project_field(base, field.index())?, diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index d9c0ff5acd1..abe73c43d8a 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -277,6 +277,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let discr = self.discriminant_for_variant(op.layout.ty, variant)?; self.write_immediate(*discr, &dest)?; } + + WrapUnsafeBinder(ref op, _ty) => { + // Constructing an unsafe binder acts like a transmute + // since the operand's layout does not change. + let op = self.eval_operand(op, None)?; + self.copy_op_allow_transmute(&op, &dest)?; + } } trace!("{:?}", self.dump_place(&dest)); diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index af8d618b6b5..4cfaacebfcd 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -54,7 +54,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> &'tcx [VtblEntry<'tcx>] { if let Some(trait_) = trait_ { let trait_ref = trait_.with_self_ty(*self.tcx, dyn_ty); - let trait_ref = self.tcx.erase_regions(trait_ref); + let trait_ref = + self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref)); self.tcx.vtable_entries(trait_ref) } else { TyCtxt::COMMON_VTABLE_ENTRIES diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index d75df1ad442..8e544798742 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1240,6 +1240,17 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, self.visit_field(val, 0, &self.ecx.project_index(val, 0)?)?; } } + ty::Pat(base, pat) => { + // First check that the base type is valid + self.visit_value(&val.transmute(self.ecx.layout_of(*base)?, self.ecx)?)?; + // When you extend this match, make sure to also add tests to + // tests/ui/type/pattern_types/validity.rs(( + match **pat { + // Range patterns are precisely reflected into `valid_range` and thus + // handled fully by `visit_scalar` (called below). + ty::PatternKind::Range { .. } => {}, + } + } _ => { // default handler try_validation!( diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index b5adf06b300..ecf9745b779 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -46,8 +46,13 @@ pub fn provide(providers: &mut Providers) { }; providers.hooks.try_destructure_mir_constant_for_user_output = const_eval::try_destructure_mir_constant_for_user_output; - providers.valtree_to_const_val = |tcx, (ty, valtree)| { - const_eval::valtree_to_const_value(tcx, ty::TypingEnv::fully_monomorphized(), ty, valtree) + providers.valtree_to_const_val = |tcx, cv| { + const_eval::valtree_to_const_value( + tcx, + ty::TypingEnv::fully_monomorphized(), + cv.ty, + cv.valtree, + ) }; providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| { util::check_validity_requirement(tcx, init_kind, param_env_and_ty) diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index 6dd9447cf5a..e926040e9ba 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -1,7 +1,6 @@ use rustc_hir::LangItem; -use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::{self}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_span::Symbol; use tracing::trace; @@ -48,15 +47,15 @@ fn alloc_caller_location<'tcx>( } pub(crate) fn const_caller_location_provider( - tcx: TyCtxtAt<'_>, + tcx: TyCtxt<'_>, file: Symbol, line: u32, col: u32, ) -> mir::ConstValue<'_> { trace!("const_caller_location: {}:{}:{}", file, line, col); let mut ecx = mk_eval_cx_to_read_const_val( - tcx.tcx, - tcx.span, + tcx, + rustc_span::DUMMY_SP, // FIXME: use a proper span here? ty::TypingEnv::fully_monomorphized(), CanAccessMutGlobal::No, ); diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 65d586124b3..6ef73debadd 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -76,6 +76,7 @@ pub mod sync; pub mod tagged_ptr; pub mod temp_dir; pub mod thinvec; +pub mod thousands; pub mod transitive_relation; pub mod unhash; pub mod unord; diff --git a/compiler/rustc_data_structures/src/thousands/mod.rs b/compiler/rustc_data_structures/src/thousands/mod.rs new file mode 100644 index 00000000000..e7ab7ec2932 --- /dev/null +++ b/compiler/rustc_data_structures/src/thousands/mod.rs @@ -0,0 +1,16 @@ +//! This is an extremely bare-bones alternative to the `thousands` crate on +//! crates.io, for printing large numbers in a readable fashion. + +#[cfg(test)] +mod tests; + +// Converts the number to a string, with underscores as the thousands separator. +pub fn format_with_underscores(n: usize) -> String { + let mut s = n.to_string(); + let mut i = s.len(); + while i > 3 { + i -= 3; + s.insert(i, '_'); + } + s +} diff --git a/compiler/rustc_data_structures/src/thousands/tests.rs b/compiler/rustc_data_structures/src/thousands/tests.rs new file mode 100644 index 00000000000..906605d9a93 --- /dev/null +++ b/compiler/rustc_data_structures/src/thousands/tests.rs @@ -0,0 +1,14 @@ +use super::*; + +#[test] +fn test_format_with_underscores() { + assert_eq!("0", format_with_underscores(0)); + assert_eq!("1", format_with_underscores(1)); + assert_eq!("99", format_with_underscores(99)); + assert_eq!("345", format_with_underscores(345)); + assert_eq!("1_000", format_with_underscores(1_000)); + assert_eq!("12_001", format_with_underscores(12_001)); + assert_eq!("999_999", format_with_underscores(999_999)); + assert_eq!("1_000_000", format_with_underscores(1_000_000)); + assert_eq!("12_345_678", format_with_underscores(12_345_678)); +} diff --git a/compiler/rustc_driver_impl/src/args.rs b/compiler/rustc_driver_impl/src/args.rs index 2fc767b3750..b0970144c42 100644 --- a/compiler/rustc_driver_impl/src/args.rs +++ b/compiler/rustc_driver_impl/src/args.rs @@ -1,7 +1,6 @@ use std::{env, error, fmt, fs, io}; use rustc_session::EarlyDiagCtxt; -use rustc_span::ErrorGuaranteed; /// Expands argfiles in command line arguments. #[derive(Default)] @@ -118,22 +117,22 @@ pub fn arg_expand_all(early_dcx: &EarlyDiagCtxt, at_args: &[String]) -> Vec<Stri /// /// This function is identical to [`env::args()`] except that it emits an error when it encounters /// non-Unicode arguments instead of panicking. -pub fn raw_args(early_dcx: &EarlyDiagCtxt) -> Result<Vec<String>, ErrorGuaranteed> { - let mut res = Ok(Vec::new()); +pub fn raw_args(early_dcx: &EarlyDiagCtxt) -> Vec<String> { + let mut args = Vec::new(); + let mut guar = Ok(()); for (i, arg) in env::args_os().enumerate() { match arg.into_string() { - Ok(arg) => { - if let Ok(args) = &mut res { - args.push(arg); - } - } + Ok(arg) => args.push(arg), Err(arg) => { - res = + guar = Err(early_dcx.early_err(format!("argument {i} is not valid Unicode: {arg:?}"))) } } } - res + if let Err(guar) = guar { + guar.raise_fatal(); + } + args } #[derive(Debug)] diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index c9d38a0f932..6ea14d15c14 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -317,7 +317,7 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) if let Some(pp_mode) = sess.opts.pretty { if pp_mode.needs_ast_map() { create_and_enter_global_ctxt(compiler, krate, |tcx| { - tcx.ensure().early_lint_checks(()); + tcx.ensure_ok().early_lint_checks(()); pretty::print(sess, pp_mode, pretty::PrintExtra::NeedsAstMap { tcx }); passes::write_dep_info(tcx); }); @@ -365,7 +365,7 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) return early_exit(); } - tcx.ensure().analysis(()); + tcx.ensure_ok().analysis(()); if callbacks.after_analysis(compiler, tcx) == Compilation::Stop { return early_exit(); @@ -1212,9 +1212,9 @@ pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, FatalError> { /// Variant of `catch_fatal_errors` for the `interface::Result` return type /// that also computes the exit code. -pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 { +pub fn catch_with_exit_code(f: impl FnOnce()) -> i32 { match catch_fatal_errors(f) { - Ok(Ok(())) => EXIT_SUCCESS, + Ok(()) => EXIT_SUCCESS, _ => EXIT_FAILURE, } } @@ -1499,10 +1499,8 @@ pub fn main() -> ! { install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ()); install_ctrlc_handler(); - let exit_code = catch_with_exit_code(|| { - run_compiler(&args::raw_args(&early_dcx)?, &mut callbacks); - Ok(()) - }); + let exit_code = + catch_with_exit_code(|| run_compiler(&args::raw_args(&early_dcx), &mut callbacks)); if let Some(format) = callbacks.time_passes { let end_rss = get_resident_set_size(); diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 93f3d2ab911..9ace486fa56 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -7,6 +7,7 @@ use rustc_ast_pretty::pprust as pprust_ast; use rustc_middle::bug; use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty}; use rustc_middle::ty::{self, TyCtxt}; +use rustc_mir_build::thir::print::{thir_flat, thir_tree}; use rustc_session::Session; use rustc_session::config::{OutFileName, PpHirMode, PpMode, PpSourceMode}; use rustc_smir::rustc_internal::pretty::write_smir_pretty; @@ -221,7 +222,7 @@ impl<'tcx> PrintExtra<'tcx> { pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { if ppm.needs_analysis() { - ex.tcx().ensure().analysis(()); + ex.tcx().ensure_ok().analysis(()); } let (src, src_name) = get_source(sess); @@ -313,7 +314,7 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { tcx.dcx().abort_if_errors(); debug!("pretty printing THIR tree"); for did in tcx.hir().body_owners() { - let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_tree(did)); + let _ = writeln!(out, "{:?}:\n{}\n", did, thir_tree(tcx, did)); } out } @@ -324,7 +325,7 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { tcx.dcx().abort_if_errors(); debug!("pretty printing THIR flat"); for did in tcx.hir().body_owners() { - let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_flat(did)); + let _ = writeln!(out, "{:?}:\n{}\n", did, thir_flat(tcx, did)); } out } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 797dcd7b4d1..29a74ed3f4e 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -4,6 +4,7 @@ use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::panic; +use std::path::PathBuf; use std::thread::panicking; use rustc_data_structures::fx::FxIndexMap; @@ -301,6 +302,7 @@ pub struct DiagInner { pub is_lint: Option<IsLint>, + pub long_ty_path: Option<PathBuf>, /// With `-Ztrack_diagnostics` enabled, /// we print where in rustc this error was emitted. pub(crate) emitted_at: DiagLocation, @@ -324,6 +326,7 @@ impl DiagInner { args: Default::default(), sort_span: DUMMY_SP, is_lint: None, + long_ty_path: None, emitted_at: DiagLocation::caller(), } } @@ -641,7 +644,14 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { found_label: &dyn fmt::Display, found: DiagStyledString, ) -> &mut Self { - self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"") + self.note_expected_found_extra( + expected_label, + expected, + found_label, + found, + DiagStyledString::normal(""), + DiagStyledString::normal(""), + ) } #[rustc_lint_diagnostics] @@ -651,8 +661,8 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { expected: DiagStyledString, found_label: &dyn fmt::Display, found: DiagStyledString, - expected_extra: &dyn fmt::Display, - found_extra: &dyn fmt::Display, + expected_extra: DiagStyledString, + found_extra: DiagStyledString, ) -> &mut Self { let expected_label = expected_label.to_string(); let expected_label = if expected_label.is_empty() { @@ -677,10 +687,13 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { expected_label ))]; msg.extend(expected.0); - msg.push(StringPart::normal(format!("`{expected_extra}\n"))); + msg.push(StringPart::normal(format!("`"))); + msg.extend(expected_extra.0); + msg.push(StringPart::normal(format!("\n"))); msg.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label))); msg.extend(found.0); - msg.push(StringPart::normal(format!("`{found_extra}"))); + msg.push(StringPart::normal(format!("`"))); + msg.extend(found_extra.0); // For now, just attach these as notes. self.highlighted_note(msg); @@ -1293,9 +1306,37 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { /// `cancel`, etc. Afterwards, `drop` is the only code that will be run on /// `self`. fn take_diag(&mut self) -> DiagInner { + if let Some(path) = &self.long_ty_path { + self.note(format!( + "the full name for the type has been written to '{}'", + path.display() + )); + self.note("consider using `--verbose` to print the full type name to the console"); + } Box::into_inner(self.diag.take().unwrap()) } + /// This method allows us to access the path of the file where "long types" are written to. + /// + /// When calling `Diag::emit`, as part of that we will check if a `long_ty_path` has been set, + /// and if it has been then we add a note mentioning the file where the "long types" were + /// written to. + /// + /// When calling `tcx.short_string()` after a `Diag` is constructed, the preferred way of doing + /// so is `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that + /// keeps the existence of a "long type" anywhere in the diagnostic, so the note telling the + /// user where we wrote the file to is only printed once at most, *and* it makes it much harder + /// to forget to set it. + /// + /// If the diagnostic hasn't been created before a "short ty string" is created, then you should + /// ensure that this method is called to set it `*diag.long_ty_path() = path`. + /// + /// As a rule of thumb, if you see or add at least one `tcx.short_string()` call anywhere, in a + /// scope, `diag.long_ty_path()` should be called once somewhere close by. + pub fn long_ty_path(&mut self) -> &mut Option<PathBuf> { + &mut self.long_ty_path + } + /// Most `emit_producing_guarantee` functions use this as a starting point. fn emit_producing_nothing(mut self) { let diag = self.take_diag(); diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 991dfa1821a..d0b4211c351 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -35,8 +35,8 @@ use crate::snippet::{ use crate::styled_buffer::StyledBuffer; use crate::translation::{Translate, to_fluent_args}; use crate::{ - CodeSuggestion, DiagCtxt, DiagInner, DiagMessage, ErrCode, FluentBundle, LazyFallbackBundle, - Level, MultiSpan, Subdiag, SubstitutionHighlight, SuggestionStyle, TerminalUrl, + CodeSuggestion, DiagInner, DiagMessage, ErrCode, FluentBundle, LazyFallbackBundle, Level, + MultiSpan, Subdiag, SubstitutionHighlight, SuggestionStyle, TerminalUrl, }; /// Default column width, used in tests and when terminal dimensions cannot be determined. @@ -537,11 +537,10 @@ impl Emitter for HumanEmitter { } /// An emitter that does nothing when emitting a non-fatal diagnostic. -/// Fatal diagnostics are forwarded to `fatal_dcx` to avoid silent +/// Fatal diagnostics are forwarded to `fatal_emitter` to avoid silent /// failures of rustc, as witnessed e.g. in issue #89358. pub struct SilentEmitter { - pub fallback_bundle: LazyFallbackBundle, - pub fatal_dcx: DiagCtxt, + pub fatal_emitter: Box<dyn Emitter + DynSend>, pub fatal_note: Option<String>, pub emit_fatal_diagnostic: bool, } @@ -552,9 +551,7 @@ impl Translate for SilentEmitter { } fn fallback_fluent_bundle(&self) -> &FluentBundle { - // Ideally this field wouldn't be necessary and the fallback bundle in `fatal_dcx` would be - // used but the lock prevents this. - &self.fallback_bundle + self.fatal_emitter.fallback_fluent_bundle() } } @@ -563,12 +560,12 @@ impl Emitter for SilentEmitter { None } - fn emit_diagnostic(&mut self, mut diag: DiagInner, _registry: &Registry) { + fn emit_diagnostic(&mut self, mut diag: DiagInner, registry: &Registry) { if self.emit_fatal_diagnostic && diag.level == Level::Fatal { if let Some(fatal_note) = &self.fatal_note { diag.sub(Level::Note, fatal_note.clone(), MultiSpan::new()); } - self.fatal_dcx.handle().emit_diagnostic(diag); + self.fatal_emitter.emit_diagnostic(diag, registry); } } } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 549729548f5..7a02e0dd2f0 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -59,13 +59,13 @@ use emitter::{DynEmitter, Emitter, is_case_difference, is_different}; use rustc_data_structures::AtomicRef; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::{Hash128, StableHasher}; -use rustc_data_structures::sync::Lock; +use rustc_data_structures::sync::{DynSend, Lock}; pub use rustc_error_messages::{ DiagMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage, fallback_fluent_bundle, fluent_bundle, }; use rustc_lint_defs::LintExpectationId; -pub use rustc_lint_defs::{Applicability, pluralize}; +pub use rustc_lint_defs::{Applicability, listify, pluralize}; use rustc_macros::{Decodable, Encodable}; pub use rustc_span::ErrorGuaranteed; pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker}; @@ -676,57 +676,44 @@ impl DiagCtxt { Self { inner: Lock::new(DiagCtxtInner::new(emitter)) } } - pub fn make_silent( - &self, - fallback_bundle: LazyFallbackBundle, - fatal_note: Option<String>, - emit_fatal_diagnostic: bool, - ) { - self.wrap_emitter(|old_dcx| { - Box::new(emitter::SilentEmitter { - fallback_bundle, - fatal_dcx: DiagCtxt { inner: Lock::new(old_dcx) }, - fatal_note, - emit_fatal_diagnostic, - }) - }); - } - - fn wrap_emitter<F>(&self, f: F) - where - F: FnOnce(DiagCtxtInner) -> Box<DynEmitter>, - { - // A empty type that implements `Emitter` so that a `DiagCtxtInner` can be constructed - // to temporarily swap in place of the real one, which will be used in constructing - // its replacement. + pub fn make_silent(&self, fatal_note: Option<String>, emit_fatal_diagnostic: bool) { + // An empty type that implements `Emitter` to temporarily swap in place of the real one, + // which will be used in constructing its replacement. struct FalseEmitter; impl Emitter for FalseEmitter { fn emit_diagnostic(&mut self, _: DiagInner, _: &Registry) { - unimplemented!("false emitter must only used during `wrap_emitter`") + unimplemented!("false emitter must only used during `make_silent`") } fn source_map(&self) -> Option<&SourceMap> { - unimplemented!("false emitter must only used during `wrap_emitter`") + unimplemented!("false emitter must only used during `make_silent`") } } impl translation::Translate for FalseEmitter { fn fluent_bundle(&self) -> Option<&FluentBundle> { - unimplemented!("false emitter must only used during `wrap_emitter`") + unimplemented!("false emitter must only used during `make_silent`") } fn fallback_fluent_bundle(&self) -> &FluentBundle { - unimplemented!("false emitter must only used during `wrap_emitter`") + unimplemented!("false emitter must only used during `make_silent`") } } let mut inner = self.inner.borrow_mut(); - let mut prev_dcx = DiagCtxtInner::new(Box::new(FalseEmitter)); - std::mem::swap(&mut *inner, &mut prev_dcx); - let new_emitter = f(prev_dcx); - let mut new_dcx = DiagCtxtInner::new(new_emitter); - std::mem::swap(&mut *inner, &mut new_dcx); + let mut prev_emitter = Box::new(FalseEmitter) as Box<dyn Emitter + DynSend>; + std::mem::swap(&mut inner.emitter, &mut prev_emitter); + let new_emitter = Box::new(emitter::SilentEmitter { + fatal_emitter: prev_emitter, + fatal_note, + emit_fatal_diagnostic, + }); + inner.emitter = new_emitter; + } + + pub fn set_emitter(&self, emitter: Box<dyn Emitter + DynSend>) { + self.inner.borrow_mut().emitter = emitter; } /// Translate `message` eagerly with `args` to `SubdiagMessage::Eager`. @@ -1999,18 +1986,6 @@ pub fn a_or_an(s: &str) -> &'static str { } } -/// Grammatical tool for displaying messages to end users in a nice form. -/// -/// Take a list ["a", "b", "c"] and output a display friendly version "a, b and c" -pub fn display_list_with_comma_and<T: std::fmt::Display>(v: &[T]) -> String { - match v { - [] => "".to_string(), - [a] => a.to_string(), - [a, b] => format!("{a} and {b}"), - [a, v @ ..] => format!("{a}, {}", display_list_with_comma_and(v)), - } -} - #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum TerminalUrl { No, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 17433eed9e7..e0543977e98 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -616,7 +616,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::No, "allow_internal_unsafe side-steps the unsafe_code lint", ), rustc_attr!( - rustc_allowed_through_unstable_modules, Normal, template!(Word, NameValueStr: "deprecation message"), + rustc_allowed_through_unstable_modules, Normal, template!(NameValueStr: "deprecation message"), WarnFollowing, EncodeCrossCrate::No, "rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \ through unstable paths" @@ -1136,7 +1136,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), rustc_attr!( TEST, rustc_dump_vtable, Normal, template!(Word), - WarnFollowing, EncodeCrossCrate::Yes + WarnFollowing, EncodeCrossCrate::No ), rustc_attr!( TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/), diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 02bc069fc5f..d9759580e8f 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -316,6 +316,7 @@ language_item_table! { PanicAsyncFnResumedPanic, sym::panic_const_async_fn_resumed_panic, panic_const_async_fn_resumed_panic, Target::Fn, GenericRequirement::None; PanicAsyncGenFnResumedPanic, sym::panic_const_async_gen_fn_resumed_panic, panic_const_async_gen_fn_resumed_panic, Target::Fn, GenericRequirement::None; PanicGenFnNonePanic, sym::panic_const_gen_fn_none_panic, panic_const_gen_fn_none_panic, Target::Fn, GenericRequirement::None; + PanicNullPointerDereference, sym::panic_null_pointer_dereference, panic_null_pointer_dereference, Target::Fn, GenericRequirement::None; /// libstd panic entry point. Necessary for const eval to be able to catch it BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None; diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index be4004f5904..a4b5a87361e 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -234,6 +234,9 @@ hir_analysis_inherent_ty_outside_relevant = cannot define inherent `impl` for a .help = consider moving this inherent impl into the crate defining the type if possible .span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items +hir_analysis_invalid_base_type = `{$ty}` is not a valid base type for range patterns + .note = range patterns only support integers + hir_analysis_invalid_generic_receiver_ty = invalid generic `self` parameter type: `{$receiver_ty}` .note = type of `self` must not be a method generic parameter type @@ -438,7 +441,6 @@ hir_analysis_pattern_type_wild_pat = wildcard patterns are not permitted for pat .label = this type is the same as the inner type without a pattern hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind} .label = not allowed in type signatures - hir_analysis_precise_capture_self_alias = `Self` can't be captured in `use<...>` precise captures list, since it is an alias .label = `Self` is not a generic argument, but an alias to the type of the {$what} diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 40049f96de4..6c534d58a7d 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -778,13 +778,13 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) { pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { match tcx.def_kind(def_id) { DefKind::Static { .. } => { - tcx.ensure().typeck(def_id); + tcx.ensure_ok().typeck(def_id); maybe_check_static_with_link_section(tcx, def_id); check_static_inhabited(tcx, def_id); check_static_linkage(tcx, def_id); } DefKind::Const => { - tcx.ensure().typeck(def_id); + tcx.ensure_ok().typeck(def_id); } DefKind::Enum => { check_enum(tcx, def_id); @@ -804,7 +804,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { DefKind::Impl { of_trait } => { if of_trait && let Some(impl_trait_header) = tcx.impl_trait_header(def_id) { if tcx - .ensure() + .ensure_ok() .coherent_trait(impl_trait_header.trait_ref.instantiate_identity().def_id) .is_ok() { @@ -1042,7 +1042,7 @@ fn check_impl_items_against_trait<'tcx>( continue; }; - let res = tcx.ensure().compare_impl_item(impl_item.expect_local()); + let res = tcx.ensure_ok().compare_impl_item(impl_item.expect_local()); if res.is_ok() { match ty_impl_item.kind { @@ -1488,7 +1488,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { for v in def.variants() { if let ty::VariantDiscr::Explicit(discr_def_id) = v.discr { - tcx.ensure().typeck(discr_def_id.expect_local()); + tcx.ensure_ok().typeck(discr_def_id.expect_local()); } } 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 7332888c5f9..a91d72e9225 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -424,12 +424,12 @@ fn compare_method_predicate_entailment<'tcx>( Ok(()) } -struct RemapLateParam<'a, 'tcx> { +struct RemapLateParam<'tcx> { tcx: TyCtxt<'tcx>, - mapping: &'a FxIndexMap<ty::LateParamRegionKind, ty::LateParamRegionKind>, + mapping: FxIndexMap<ty::LateParamRegionKind, ty::LateParamRegionKind>, } -impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateParam<'_, 'tcx> { +impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateParam<'tcx> { fn cx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -653,6 +653,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( }))), terr, false, + None, ); return Err(diag.emit()); } @@ -1070,6 +1071,7 @@ fn report_trait_method_mismatch<'tcx>( }))), terr, false, + None, ); diag.emit() @@ -1862,6 +1864,7 @@ fn compare_const_predicate_entailment<'tcx>( }))), terr, false, + None, ); return Err(diag.emit()); }; @@ -2031,7 +2034,7 @@ pub(super) fn check_type_bounds<'tcx>( ) -> Result<(), ErrorGuaranteed> { // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case // other `Foo` impls are incoherent. - tcx.ensure().coherent_trait(impl_trait_ref.def_id)?; + tcx.ensure_ok().coherent_trait(impl_trait_ref.def_id)?; let param_env = tcx.param_env(impl_ty.def_id); debug!(?param_env); 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 494e9560c81..0e9e9b48ab3 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 @@ -299,8 +299,7 @@ fn report_mismatched_rpitit_signature<'tcx>( }) .collect(); - let mut return_ty = - trait_m_sig.output().fold_with(&mut super::RemapLateParam { tcx, mapping: &mapping }); + let mut return_ty = trait_m_sig.output().fold_with(&mut super::RemapLateParam { tcx, mapping }); if tcx.asyncness(impl_m_def_id).is_async() && tcx.asyncness(trait_m_def_id).is_async() { let ty::Alias(ty::Projection, future_ty) = return_ty.kind() else { diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 0876bb82848..d7dfe482da4 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -1,7 +1,3 @@ -// 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::*; use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; @@ -32,7 +28,10 @@ use crate::hir::def_id::{DefId, LocalDefId}; /// struct/enum definition for the nominal type itself (i.e. /// cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`). /// -pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), ErrorGuaranteed> { +pub(crate) fn check_drop_impl( + tcx: TyCtxt<'_>, + drop_impl_did: DefId, +) -> Result<(), ErrorGuaranteed> { match tcx.impl_polarity(drop_impl_did) { ty::ImplPolarity::Positive => {} ty::ImplPolarity::Negative => { diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 8aa95d1c1d5..cf3d4897304 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -199,7 +199,8 @@ pub fn check_intrinsic_type( let split: Vec<&str> = name_str.split('_').collect(); assert!(split.len() >= 2, "Atomic intrinsic in an incorrect format"); - //We only care about the operation here + // Each atomic op has variants with different suffixes (`_seq_cst`, `_acquire`, etc.). Use + // string ops to strip the suffixes, because the variants all get the same treatment here. let (n_tps, inputs, output) = match split[1] { "cxchg" | "cxchgweak" => ( 1, diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 814c784710a..96b33bdd250 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -455,18 +455,14 @@ fn fn_sig_suggestion<'tcx>( let mut output = sig.output(); let asyncness = if tcx.asyncness(assoc.def_id).is_async() { - output = if let ty::Alias(_, alias_ty) = *output.kind() { - tcx.explicit_item_self_bounds(alias_ty.def_id) + output = if let ty::Alias(_, alias_ty) = *output.kind() + && let Some(output) = tcx + .explicit_item_self_bounds(alias_ty.def_id) .iter_instantiated_copied(tcx, alias_ty.args) .find_map(|(bound, _)| { bound.as_projection_clause()?.no_bound_vars()?.term.as_type() - }) - .unwrap_or_else(|| { - span_bug!( - ident.span, - "expected async fn to have `impl Future` output, but it returns {output}" - ) - }) + }) { + output } else { span_bug!( ident.span, @@ -649,6 +645,7 @@ pub fn check_function_signature<'tcx>( }))), err, false, + None, ); return Err(diag.emit()); } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 83bb8c0dfaf..a90e034ba4a 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -328,16 +328,20 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<() hir::ItemKind::TraitAlias(..) => check_trait(tcx, item), // `ForeignItem`s are handled separately. hir::ItemKind::ForeignMod { .. } => Ok(()), - hir::ItemKind::TyAlias(hir_ty, hir_generics) => { - if tcx.type_alias_is_lazy(item.owner_id) { - // Bounds of lazy type aliases and of eager ones that contain opaque types are respected. - // E.g: `type X = impl Trait;`, `type X = (impl Trait, Y);`. - let res = check_item_type(tcx, def_id, hir_ty.span, UnsizedHandling::Allow); - check_variances_for_type_defn(tcx, item, hir_generics); - res - } else { + hir::ItemKind::TyAlias(hir_ty, hir_generics) if tcx.type_alias_is_lazy(item.owner_id) => { + let res = enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| { + let ty = tcx.type_of(def_id).instantiate_identity(); + let item_ty = wfcx.normalize(hir_ty.span, Some(WellFormedLoc::Ty(def_id)), ty); + wfcx.register_wf_obligation( + hir_ty.span, + Some(WellFormedLoc::Ty(def_id)), + item_ty.into(), + ); + check_where_clauses(wfcx, item.span, def_id); Ok(()) - } + }); + check_variances_for_type_defn(tcx, item, hir_generics); + res } _ => Ok(()), }; @@ -1046,7 +1050,7 @@ fn check_associated_item( // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case // other `Foo` impls are incoherent. - tcx.ensure() + tcx.ensure_ok() .coherent_trait(tcx.parent(item.trait_item_def_id.unwrap_or(item_id.into())))?; let self_ty = match item.container { @@ -1276,7 +1280,6 @@ fn check_item_fn( enum UnsizedHandling { Forbid, - Allow, AllowIfForeignTail, } @@ -1294,7 +1297,6 @@ fn check_item_type( let forbid_unsized = match unsized_handling { UnsizedHandling::Forbid => true, - UnsizedHandling::Allow => false, UnsizedHandling::AllowIfForeignTail => { let tail = tcx.struct_tail_for_codegen(item_ty, wfcx.infcx.typing_env(wfcx.param_env)); @@ -1354,7 +1356,7 @@ fn check_impl<'tcx>( let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap().instantiate_identity(); // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case // other `Foo` impls are incoherent. - tcx.ensure().coherent_trait(trait_ref.def_id)?; + tcx.ensure_ok().coherent_trait(trait_ref.def_id)?; let trait_span = hir_trait_ref.path.span; let trait_ref = wfcx.normalize( trait_span, @@ -2267,14 +2269,14 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), ErrorGuaranteed> { let items = tcx.hir_module_items(module); - let mut res = items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)); - res = - res.and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id))); - res = - res.and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id))); - res = res - .and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id))); - res = res.and(items.par_opaques(|item| tcx.ensure().check_well_formed(item))); + let res = items + .par_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)) + .and(items.par_impl_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id))) + .and(items.par_trait_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id))) + .and( + items.par_foreign_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)), + ) + .and(items.par_opaques(|item| tcx.ensure_ok().check_well_formed(item))); if module == LocalModDefId::CRATE_DEF_ID { super::entry::check_for_entry_fn(tcx); } diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 6bbd76633da..3511dbc6252 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -192,7 +192,7 @@ fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), E // errors; other parts of the code may demand it for the info of // course. let span = tcx.def_span(impl_did); - tcx.at(span).ensure().coerce_unsized_info(impl_did) + tcx.at(span).ensure_ok().coerce_unsized_info(impl_did) } fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> { @@ -404,17 +404,12 @@ pub(crate) fn coerce_unsized_info<'tcx>( check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty)) } - (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => check_mutbl( - ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }, - ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b }, - &|ty| Ty::new_imm_ptr(tcx, ty), - ), - - (&ty::RawPtr(ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => check_mutbl( - ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }, - ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b }, - &|ty| Ty::new_imm_ptr(tcx, ty), - ), + (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) + | (&ty::RawPtr(ty_a, mutbl_a), &ty::RawPtr(ty_b, mutbl_b)) => { + let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; + let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b }; + check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ptr(tcx, ty)) + } (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b)) if def_a.is_struct() && def_b.is_struct() => diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 4e5f0a3186a..1bc60087ab5 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -151,19 +151,19 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed> let Some(impls) = tcx.all_local_trait_impls(()).get(&def_id) else { return Ok(()) }; // Trigger building the specialization graph for the trait. This will detect and report any // overlap errors. - let mut res = tcx.ensure().specialization_graph_of(def_id); + let mut res = tcx.ensure_ok().specialization_graph_of(def_id); for &impl_def_id in impls { let trait_header = tcx.impl_trait_header(impl_def_id).unwrap(); let trait_ref = trait_header.trait_ref.instantiate_identity(); let trait_def = tcx.trait_def(trait_ref.def_id); - res = res.and(check_impl(tcx, impl_def_id, trait_ref, trait_def)); - res = res.and(check_object_overlap(tcx, impl_def_id, trait_ref)); - - res = res.and(unsafety::check_item(tcx, impl_def_id, trait_header, trait_def)); - res = res.and(tcx.ensure().orphan_check_impl(impl_def_id)); - res = res.and(builtin::check_trait(tcx, def_id, impl_def_id, trait_header)); + res = res + .and(check_impl(tcx, impl_def_id, trait_ref, trait_def)) + .and(check_object_overlap(tcx, impl_def_id, trait_ref)) + .and(unsafety::check_item(tcx, impl_def_id, trait_header, trait_def)) + .and(tcx.ensure_ok().orphan_check_impl(impl_def_id)) + .and(builtin::check_trait(tcx, def_id, impl_def_id, trait_header)); } res @@ -199,10 +199,9 @@ fn check_object_overlap<'tcx>( for component_def_id in component_def_ids { if !tcx.is_dyn_compatible(component_def_id) { - // FIXME(dyn_compat_renaming): Rename test and update comment. // Without the 'dyn_compatible_for_dispatch' feature this is an error // which will be reported by wfcheck. Ignore it here. - // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`. + // This is tested by `coherence-impl-trait-for-trait-dyn-compatible.rs`. // With the feature enabled, the trait is not implemented automatically, // so this is valid. } else { diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index cad7b2a1e57..ce7319f6561 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -57,7 +57,7 @@ mod type_of; /////////////////////////////////////////////////////////////////////////// -pub fn provide(providers: &mut Providers) { +pub(crate) fn provide(providers: &mut Providers) { resolve_bound_vars::provide(providers); *providers = Providers { type_of: type_of::type_of, @@ -122,7 +122,7 @@ pub fn provide(providers: &mut Providers) { /// `ItemCtxt` is parameterized by a `DefId` that it uses to satisfy /// `probe_ty_param_bounds` requests, drawing the information from /// the HIR (`hir::Generics`), recursively. -pub struct ItemCtxt<'tcx> { +pub(crate) struct ItemCtxt<'tcx> { tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, tainted_by_errors: Cell<Option<ErrorGuaranteed>>, @@ -148,7 +148,7 @@ impl<'v> Visitor<'v> for HirPlaceholderCollector { } } -pub struct CollectItemTypesVisitor<'tcx> { +pub(crate) struct CollectItemTypesVisitor<'tcx> { pub tcx: TyCtxt<'tcx>, } @@ -292,16 +292,16 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { match param.kind { hir::GenericParamKind::Lifetime { .. } => {} hir::GenericParamKind::Type { default: Some(_), .. } => { - self.tcx.ensure().type_of(param.def_id); + self.tcx.ensure_ok().type_of(param.def_id); } hir::GenericParamKind::Type { .. } => {} hir::GenericParamKind::Const { default, .. } => { - self.tcx.ensure().type_of(param.def_id); + self.tcx.ensure_ok().type_of(param.def_id); if let Some(default) = default { // need to store default and type of default - self.tcx.ensure().const_param_default(param.def_id); + self.tcx.ensure_ok().const_param_default(param.def_id); if let hir::ConstArgKind::Anon(ac) = default.kind { - self.tcx.ensure().type_of(ac.def_id); + self.tcx.ensure_ok().type_of(ac.def_id); } } } @@ -312,8 +312,8 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { if let hir::ExprKind::Closure(closure) = expr.kind { - self.tcx.ensure().generics_of(closure.def_id); - self.tcx.ensure().codegen_fn_attrs(closure.def_id); + self.tcx.ensure_ok().generics_of(closure.def_id); + self.tcx.ensure_ok().codegen_fn_attrs(closure.def_id); // We do not call `type_of` for closures here as that // depends on typecheck and would therefore hide // any further errors in case one typeck fails. @@ -325,15 +325,15 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { /// `check_item_type` ensures that it's called instead. fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) { let def_id = opaque.def_id; - self.tcx.ensure().generics_of(def_id); - self.tcx.ensure().predicates_of(def_id); - self.tcx.ensure().explicit_item_bounds(def_id); - self.tcx.ensure().explicit_item_self_bounds(def_id); - self.tcx.ensure().item_bounds(def_id); - self.tcx.ensure().item_self_bounds(def_id); + self.tcx.ensure_ok().generics_of(def_id); + self.tcx.ensure_ok().predicates_of(def_id); + self.tcx.ensure_ok().explicit_item_bounds(def_id); + self.tcx.ensure_ok().explicit_item_self_bounds(def_id); + self.tcx.ensure_ok().item_bounds(def_id); + self.tcx.ensure_ok().item_self_bounds(def_id); if self.tcx.is_conditionally_const(def_id) { - self.tcx.ensure().explicit_implied_const_bounds(def_id); - self.tcx.ensure().const_conditions(def_id); + self.tcx.ensure_ok().explicit_implied_const_bounds(def_id); + self.tcx.ensure_ok().const_conditions(def_id); } intravisit::walk_opaque_ty(self, opaque); } @@ -364,19 +364,19 @@ fn bad_placeholder<'cx, 'tcx>( } impl<'tcx> ItemCtxt<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId) -> ItemCtxt<'tcx> { + pub(crate) fn new(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId) -> ItemCtxt<'tcx> { ItemCtxt { tcx, item_def_id, tainted_by_errors: Cell::new(None) } } - pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { + pub(crate) fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { self.lowerer().lower_ty(hir_ty) } - pub fn hir_id(&self) -> hir::HirId { + pub(crate) fn hir_id(&self) -> hir::HirId { self.tcx.local_def_id_to_hir_id(self.item_def_id) } - pub fn node(&self) -> hir::Node<'tcx> { + pub(crate) fn node(&self) -> hir::Node<'tcx> { self.tcx.hir_node(self.hir_id()) } @@ -683,20 +683,20 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { hir::ItemKind::ForeignMod { items, .. } => { for item in *items { let item = tcx.hir().foreign_item(item.id); - tcx.ensure().generics_of(item.owner_id); - tcx.ensure().type_of(item.owner_id); - tcx.ensure().predicates_of(item.owner_id); + tcx.ensure_ok().generics_of(item.owner_id); + tcx.ensure_ok().type_of(item.owner_id); + tcx.ensure_ok().predicates_of(item.owner_id); if tcx.is_conditionally_const(def_id) { - tcx.ensure().explicit_implied_const_bounds(def_id); - tcx.ensure().const_conditions(def_id); + tcx.ensure_ok().explicit_implied_const_bounds(def_id); + tcx.ensure_ok().const_conditions(def_id); } match item.kind { hir::ForeignItemKind::Fn(..) => { - tcx.ensure().codegen_fn_attrs(item.owner_id); - tcx.ensure().fn_sig(item.owner_id) + tcx.ensure_ok().codegen_fn_attrs(item.owner_id); + tcx.ensure_ok().fn_sig(item.owner_id) } hir::ForeignItemKind::Static(..) => { - tcx.ensure().codegen_fn_attrs(item.owner_id); + tcx.ensure_ok().codegen_fn_attrs(item.owner_id); let mut visitor = HirPlaceholderCollector::default(); visitor.visit_foreign_item(item); placeholder_type_error( @@ -713,40 +713,40 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { } } hir::ItemKind::Enum(..) => { - tcx.ensure().generics_of(def_id); - tcx.ensure().type_of(def_id); - tcx.ensure().predicates_of(def_id); + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().predicates_of(def_id); lower_enum_variant_types(tcx, def_id.to_def_id()); } hir::ItemKind::Impl { .. } => { - tcx.ensure().generics_of(def_id); - tcx.ensure().type_of(def_id); - tcx.ensure().impl_trait_header(def_id); - tcx.ensure().predicates_of(def_id); - tcx.ensure().associated_items(def_id); + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().impl_trait_header(def_id); + tcx.ensure_ok().predicates_of(def_id); + tcx.ensure_ok().associated_items(def_id); } hir::ItemKind::Trait(..) => { - tcx.ensure().generics_of(def_id); - tcx.ensure().trait_def(def_id); + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().trait_def(def_id); tcx.at(it.span).explicit_super_predicates_of(def_id); - tcx.ensure().predicates_of(def_id); - tcx.ensure().associated_items(def_id); + tcx.ensure_ok().predicates_of(def_id); + tcx.ensure_ok().associated_items(def_id); } hir::ItemKind::TraitAlias(..) => { - tcx.ensure().generics_of(def_id); + tcx.ensure_ok().generics_of(def_id); tcx.at(it.span).explicit_implied_predicates_of(def_id); tcx.at(it.span).explicit_super_predicates_of(def_id); - tcx.ensure().predicates_of(def_id); + tcx.ensure_ok().predicates_of(def_id); } hir::ItemKind::Struct(struct_def, _) | hir::ItemKind::Union(struct_def, _) => { - tcx.ensure().generics_of(def_id); - tcx.ensure().type_of(def_id); - tcx.ensure().predicates_of(def_id); + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().predicates_of(def_id); for f in struct_def.fields() { - tcx.ensure().generics_of(f.def_id); - tcx.ensure().type_of(f.def_id); - tcx.ensure().predicates_of(f.def_id); + tcx.ensure_ok().generics_of(f.def_id); + tcx.ensure_ok().type_of(f.def_id); + tcx.ensure_ok().predicates_of(f.def_id); } if let Some(ctor_def_id) = struct_def.ctor_def_id() { @@ -755,15 +755,15 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { } hir::ItemKind::TyAlias(..) => { - tcx.ensure().generics_of(def_id); - tcx.ensure().type_of(def_id); - tcx.ensure().predicates_of(def_id); + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().predicates_of(def_id); } hir::ItemKind::Static(ty, ..) | hir::ItemKind::Const(ty, ..) => { - tcx.ensure().generics_of(def_id); - tcx.ensure().type_of(def_id); - tcx.ensure().predicates_of(def_id); + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().predicates_of(def_id); if !ty.is_suggestable_infer_ty() { let mut visitor = HirPlaceholderCollector::default(); visitor.visit_item(it); @@ -779,11 +779,11 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { } hir::ItemKind::Fn { .. } => { - tcx.ensure().generics_of(def_id); - tcx.ensure().type_of(def_id); - tcx.ensure().predicates_of(def_id); - tcx.ensure().fn_sig(def_id); - tcx.ensure().codegen_fn_attrs(def_id); + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().predicates_of(def_id); + tcx.ensure_ok().fn_sig(def_id); + tcx.ensure_ok().codegen_fn_attrs(def_id); } } } @@ -791,18 +791,18 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { let trait_item = tcx.hir().trait_item(trait_item_id); let def_id = trait_item_id.owner_id; - tcx.ensure().generics_of(def_id); + tcx.ensure_ok().generics_of(def_id); let icx = ItemCtxt::new(tcx, def_id.def_id); match trait_item.kind { hir::TraitItemKind::Fn(..) => { - tcx.ensure().codegen_fn_attrs(def_id); - tcx.ensure().type_of(def_id); - tcx.ensure().fn_sig(def_id); + tcx.ensure_ok().codegen_fn_attrs(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().fn_sig(def_id); } hir::TraitItemKind::Const(ty, body_id) => { - tcx.ensure().type_of(def_id); + tcx.ensure_ok().type_of(def_id); if !tcx.dcx().has_stashed_diagnostic(ty.span, StashKey::ItemNoType) && !(ty.is_suggestable_infer_ty() && body_id.is_some()) { @@ -821,9 +821,9 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { } hir::TraitItemKind::Type(_, Some(_)) => { - tcx.ensure().item_bounds(def_id); - tcx.ensure().item_self_bounds(def_id); - tcx.ensure().type_of(def_id); + tcx.ensure_ok().item_bounds(def_id); + tcx.ensure_ok().item_self_bounds(def_id); + tcx.ensure_ok().type_of(def_id); // Account for `type T = _;`. let mut visitor = HirPlaceholderCollector::default(); visitor.visit_trait_item(trait_item); @@ -838,8 +838,8 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { } hir::TraitItemKind::Type(_, None) => { - tcx.ensure().item_bounds(def_id); - tcx.ensure().item_self_bounds(def_id); + tcx.ensure_ok().item_bounds(def_id); + tcx.ensure_ok().item_self_bounds(def_id); // #74612: Visit and try to find bad placeholders // even if there is no concrete type. let mut visitor = HirPlaceholderCollector::default(); @@ -856,20 +856,20 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { } }; - tcx.ensure().predicates_of(def_id); + tcx.ensure_ok().predicates_of(def_id); } fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) { let def_id = impl_item_id.owner_id; - tcx.ensure().generics_of(def_id); - tcx.ensure().type_of(def_id); - tcx.ensure().predicates_of(def_id); + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().predicates_of(def_id); let impl_item = tcx.hir().impl_item(impl_item_id); let icx = ItemCtxt::new(tcx, def_id.def_id); match impl_item.kind { hir::ImplItemKind::Fn(..) => { - tcx.ensure().codegen_fn_attrs(def_id); - tcx.ensure().fn_sig(def_id); + tcx.ensure_ok().codegen_fn_attrs(def_id); + tcx.ensure_ok().fn_sig(def_id); } hir::ImplItemKind::Type(_) => { // Account for `type T = _;` @@ -904,9 +904,9 @@ fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) { } fn lower_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) { - tcx.ensure().generics_of(def_id); - tcx.ensure().type_of(def_id); - tcx.ensure().predicates_of(def_id); + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().predicates_of(def_id); } fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) { @@ -937,9 +937,9 @@ fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) { ); for f in &variant.fields { - tcx.ensure().generics_of(f.did); - tcx.ensure().type_of(f.did); - tcx.ensure().predicates_of(f.did); + tcx.ensure_ok().generics_of(f.did); + tcx.ensure_ok().type_of(f.did); + tcx.ensure_ok().predicates_of(f.did); } // Lower the ctor, if any. This also registers the variant as an item. diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs index f1022d95753..4a508fc0cf6 100644 --- a/compiler/rustc_hir_analysis/src/collect/dump.rs +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -1,7 +1,8 @@ +use rustc_hir as hir; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_hir::intravisit; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_span::sym; pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) { @@ -87,3 +88,82 @@ pub(crate) fn def_parents(tcx: TyCtxt<'_>) { } } } + +pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { + for id in tcx.hir().items() { + let def_id = id.owner_id.def_id; + + let Some(attr) = tcx.get_attr(def_id, sym::rustc_dump_vtable) else { + continue; + }; + + let vtable_entries = match tcx.hir().item(id).kind { + hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => { + let trait_ref = tcx.impl_trait_ref(def_id).unwrap().instantiate_identity(); + if trait_ref.has_non_region_param() { + tcx.dcx().span_err( + attr.span, + "`rustc_dump_vtable` must be applied to non-generic impl", + ); + continue; + } + if !tcx.is_dyn_compatible(trait_ref.def_id) { + tcx.dcx().span_err( + attr.span, + "`rustc_dump_vtable` must be applied to dyn-compatible trait", + ); + continue; + } + let Ok(trait_ref) = tcx + .try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref) + else { + tcx.dcx().span_err( + attr.span, + "`rustc_dump_vtable` applied to impl header that cannot be normalized", + ); + continue; + }; + tcx.vtable_entries(trait_ref) + } + hir::ItemKind::TyAlias(_, _) => { + let ty = tcx.type_of(def_id).instantiate_identity(); + if ty.has_non_region_param() { + tcx.dcx().span_err( + attr.span, + "`rustc_dump_vtable` must be applied to non-generic type", + ); + continue; + } + let Ok(ty) = + tcx.try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), ty) + else { + tcx.dcx().span_err( + attr.span, + "`rustc_dump_vtable` applied to type alias that cannot be normalized", + ); + continue; + }; + let ty::Dynamic(data, _, _) = *ty.kind() else { + tcx.dcx().span_err(attr.span, "`rustc_dump_vtable` to type alias of dyn type"); + continue; + }; + if let Some(principal) = data.principal() { + tcx.vtable_entries( + tcx.instantiate_bound_regions_with_erased(principal).with_self_ty(tcx, ty), + ) + } else { + TyCtxt::COMMON_VTABLE_ENTRIES + } + } + _ => { + tcx.dcx().span_err( + attr.span, + "`rustc_dump_vtable` only applies to impl, or type alias of dyn type", + ); + continue; + } + }; + + tcx.dcx().span_err(tcx.def_span(def_id), format!("vtable entries: {vtable_entries:#?}")); + } +} diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 72baf5c4b58..d67b9d33596 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -12,13 +12,11 @@ use std::ops::ControlFlow; use rustc_ast::visit::walk_list; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; -use rustc_data_structures::sorted_map::SortedMap; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt}; use rustc_hir::{ - self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, ItemLocalMap, - LifetimeName, Node, + self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeName, Node, }; use rustc_macros::extension; use rustc_middle::hir::nested_filter; @@ -26,7 +24,7 @@ use rustc_middle::middle::resolve_bound_vars::*; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_middle::{bug, span_bug}; -use rustc_span::def_id::{DefId, LocalDefId, LocalDefIdMap}; +use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::{Ident, Span, sym}; use tracing::{debug, debug_span, instrument}; @@ -62,33 +60,9 @@ impl ResolvedArg { } } -/// Maps the id of each bound variable reference to the variable decl -/// that it corresponds to. -/// -/// FIXME. This struct gets converted to a `ResolveBoundVars` for -/// actual use. It has the same data, but indexed by `LocalDefId`. This -/// is silly. -#[derive(Debug, Default)] -struct NamedVarMap { - // maps from every use of a named (not anonymous) bound var to a - // `ResolvedArg` describing how that variable is bound - defs: ItemLocalMap<ResolvedArg>, - - // Maps relevant hir items to the bound vars on them. These include: - // - function defs - // - function pointers - // - closures - // - trait refs - // - bound types (like `T` in `for<'a> T<'a>: Foo`) - late_bound_vars: ItemLocalMap<Vec<ty::BoundVariableKind>>, - - // List captured variables for each opaque type. - opaque_captured_lifetimes: LocalDefIdMap<Vec<(ResolvedArg, LocalDefId)>>, -} - struct BoundVarContext<'a, 'tcx> { tcx: TyCtxt<'tcx>, - map: &'a mut NamedVarMap, + rbv: &'a mut ResolveBoundVars, scope: ScopeRef<'a>, } @@ -267,19 +241,12 @@ pub(crate) fn provide(providers: &mut Providers) { /// Computes the `ResolveBoundVars` map that contains data for an entire `Item`. /// You should not read the result of this query directly, but rather use -/// `named_variable_map`, `is_late_bound_map`, etc. +/// `named_variable_map`, `late_bound_vars_map`, etc. #[instrument(level = "debug", skip(tcx))] fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBoundVars { - let mut named_variable_map = NamedVarMap { - defs: Default::default(), - late_bound_vars: Default::default(), - opaque_captured_lifetimes: Default::default(), - }; - let mut visitor = BoundVarContext { - tcx, - map: &mut named_variable_map, - scope: &Scope::Root { opt_parent_item: None }, - }; + let mut rbv = ResolveBoundVars::default(); + let mut visitor = + BoundVarContext { tcx, rbv: &mut rbv, scope: &Scope::Root { opt_parent_item: None } }; match tcx.hir_owner_node(local_def_id) { hir::OwnerNode::Item(item) => visitor.visit_item(item), hir::OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item), @@ -299,19 +266,10 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou hir::OwnerNode::Synthetic => unreachable!(), } - let defs = named_variable_map.defs.into_sorted_stable_ord(); - let late_bound_vars = named_variable_map.late_bound_vars.into_sorted_stable_ord(); - let opaque_captured_lifetimes = named_variable_map.opaque_captured_lifetimes; - let rl = ResolveBoundVars { - defs: SortedMap::from_presorted_elements(defs), - late_bound_vars: SortedMap::from_presorted_elements(late_bound_vars), - opaque_captured_lifetimes, - }; - - debug!(?rl.defs); - debug!(?rl.late_bound_vars); - debug!(?rl.opaque_captured_lifetimes); - rl + debug!(?rbv.defs); + debug!(?rbv.late_bound_vars); + debug!(?rbv.opaque_captured_lifetimes); + rbv } fn late_arg_as_bound_arg<'tcx>( @@ -404,7 +362,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Binder { hir_id, .. } => { // Nested poly trait refs have the binders concatenated let mut full_binders = - self.map.late_bound_vars.entry(hir_id.local_id).or_default().clone(); + self.rbv.late_bound_vars.get_mut_or_insert_default(hir_id.local_id).clone(); full_binders.extend(supertrait_bound_vars); break (full_binders, BinderScopeType::Concatenating); } @@ -646,7 +604,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let captures = captures.into_inner().into_iter().collect(); debug!(?captures); - self.map.opaque_captured_lifetimes.insert(opaque.def_id, captures); + self.rbv.opaque_captured_lifetimes.insert(opaque.def_id, captures); } #[instrument(level = "debug", skip(self))] @@ -848,7 +806,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { hir::TyKind::Ref(lifetime_ref, ref mt) => { self.visit_lifetime(lifetime_ref); let scope = Scope::ObjectLifetimeDefault { - lifetime: self.map.defs.get(&lifetime_ref.hir_id.local_id).cloned(), + lifetime: self.rbv.defs.get(&lifetime_ref.hir_id.local_id).cloned(), s: self.scope, }; self.with(scope, |this| this.visit_ty_unambig(mt.ty)); @@ -966,7 +924,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let bound_vars: Vec<_> = self.tcx.fn_sig(sig_id).skip_binder().bound_vars().iter().collect(); let hir_id = self.tcx.local_def_id_to_hir_id(def_id); - self.map.late_bound_vars.insert(hir_id.local_id, bound_vars); + self.rbv.late_bound_vars.insert(hir_id.local_id, bound_vars); } self.visit_fn_like_elision(fd.inputs, output, matches!(fk, intravisit::FnKind::Closure)); intravisit::walk_fn_kind(self, fk); @@ -1140,8 +1098,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { where F: for<'b> FnOnce(&mut BoundVarContext<'b, 'tcx>), { - let BoundVarContext { tcx, map, .. } = self; - let mut this = BoundVarContext { tcx: *tcx, map, scope: &wrap_scope }; + let BoundVarContext { tcx, rbv, .. } = self; + let mut this = BoundVarContext { tcx: *tcx, rbv, scope: &wrap_scope }; let span = debug_span!("scope", scope = ?this.scope.debug_truncated()); { let _enter = span.enter(); @@ -1150,10 +1108,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } fn record_late_bound_vars(&mut self, hir_id: HirId, binder: Vec<ty::BoundVariableKind>) { - if let Some(old) = self.map.late_bound_vars.insert(hir_id.local_id, binder) { + if let Some(old) = self.rbv.late_bound_vars.insert(hir_id.local_id, binder) { bug!( "overwrote bound vars for {hir_id:?}:\nold={old:?}\nnew={:?}", - self.map.late_bound_vars[&hir_id.local_id] + self.rbv.late_bound_vars[&hir_id.local_id] ) } } @@ -1597,9 +1555,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { kind.descr(param_def_id.to_def_id()) ), }; - self.map.defs.insert(hir_id.local_id, ResolvedArg::Error(guar)); + self.rbv.defs.insert(hir_id.local_id, ResolvedArg::Error(guar)); } else { - self.map.defs.insert(hir_id.local_id, def); + self.rbv.defs.insert(hir_id.local_id, def); } return; } @@ -1632,7 +1590,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { bug!("unexpected def-kind: {}", kind.descr(param_def_id.to_def_id())) } }); - self.map.defs.insert(hir_id.local_id, ResolvedArg::Error(guar)); + self.rbv.defs.insert(hir_id.local_id, ResolvedArg::Error(guar)); return; } Scope::Root { .. } => break, @@ -1725,7 +1683,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { } }; - let map = &self.map; + let rbv = &self.rbv; let generics = self.tcx.generics_of(def_id); // `type_def_id` points to an item, so there is nothing to inherit generics from. @@ -1744,7 +1702,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // This index can be used with `generic_args` since `parent_count == 0`. let index = generics.param_def_id_to_index[¶m_def_id] as usize; generic_args.args.get(index).and_then(|arg| match arg { - GenericArg::Lifetime(lt) => map.defs.get(<.hir_id.local_id).copied(), + GenericArg::Lifetime(lt) => rbv.defs.get(<.hir_id.local_id).copied(), _ => None, }) } @@ -2042,7 +2000,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: ResolvedArg) { debug!(span = ?lifetime_ref.ident.span); - self.map.defs.insert(lifetime_ref.hir_id.local_id, def); + self.rbv.defs.insert(lifetime_ref.hir_id.local_id, def); } // When we have a return type notation type in a where clause, like @@ -2197,7 +2155,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // See where these vars are used in `HirTyLowerer::lower_ty_maybe_return_type_notation`. // And this is exercised in: // `tests/ui/associated-type-bounds/return-type-notation/higher-ranked-bound-works.rs`. - let existing_bound_vars = self.map.late_bound_vars.get_mut(&hir_id.local_id).unwrap(); + let existing_bound_vars = self.rbv.late_bound_vars.get_mut(&hir_id.local_id).unwrap(); let existing_bound_vars_saved = existing_bound_vars.clone(); existing_bound_vars.extend(bound_vars); self.record_late_bound_vars(item_segment.hir_id, existing_bound_vars_saved); diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index e65420ea8bf..ed45833b614 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -100,213 +100,156 @@ enum InheritanceKind { Own, } -struct GenericsBuilder<'tcx> { +fn build_generics<'tcx>( tcx: TyCtxt<'tcx>, sig_id: DefId, parent: Option<DefId>, inh_kind: InheritanceKind, -} - -impl<'tcx> GenericsBuilder<'tcx> { - fn new(tcx: TyCtxt<'tcx>, sig_id: DefId) -> GenericsBuilder<'tcx> { - GenericsBuilder { tcx, sig_id, parent: None, inh_kind: InheritanceKind::WithParent(false) } - } - - fn with_parent(mut self, parent: DefId) -> Self { - self.parent = Some(parent); - self - } - - fn with_inheritance_kind(mut self, inh_kind: InheritanceKind) -> Self { - self.inh_kind = inh_kind; - self - } - - fn build(self) -> ty::Generics { - let mut own_params = vec![]; +) -> ty::Generics { + let mut own_params = vec![]; - let sig_generics = self.tcx.generics_of(self.sig_id); - if let InheritanceKind::WithParent(has_self) = self.inh_kind - && let Some(parent_def_id) = sig_generics.parent - { - let sig_parent_generics = self.tcx.generics_of(parent_def_id); - own_params.append(&mut sig_parent_generics.own_params.clone()); - if !has_self { - own_params.remove(0); - } + let sig_generics = tcx.generics_of(sig_id); + if let InheritanceKind::WithParent(has_self) = inh_kind + && let Some(parent_def_id) = sig_generics.parent + { + let sig_parent_generics = tcx.generics_of(parent_def_id); + own_params.append(&mut sig_parent_generics.own_params.clone()); + if !has_self { + own_params.remove(0); } - own_params.append(&mut sig_generics.own_params.clone()); + } + own_params.append(&mut sig_generics.own_params.clone()); + + // Lifetime parameters must be declared before type and const parameters. + // Therefore, When delegating from a free function to a associated function, + // generic parameters need to be reordered: + // + // trait Trait<'a, A> { + // fn foo<'b, B>(...) {...} + // } + // + // reuse Trait::foo; + // desugaring: + // fn foo<'a, 'b, This: Trait<'a, A>, A, B>(...) { + // Trait::foo(...) + // } + own_params.sort_by_key(|key| key.kind.is_ty_or_const()); + + let param_def_id_to_index = + own_params.iter().map(|param| (param.def_id, param.index)).collect(); + + let (parent_count, has_self) = if let Some(def_id) = parent { + let parent_generics = tcx.generics_of(def_id); + let parent_kind = tcx.def_kind(def_id); + (parent_generics.count(), parent_kind == DefKind::Trait) + } else { + (0, false) + }; - // Lifetime parameters must be declared before type and const parameters. - // Therefore, When delegating from a free function to a associated function, - // generic parameters need to be reordered: + for (idx, param) in own_params.iter_mut().enumerate() { + param.index = (idx + parent_count) as u32; + // FIXME(fn_delegation): Default parameters are not inherited, because they are + // not permitted in functions. Therefore, there are 2 options here: // - // trait Trait<'a, A> { - // fn foo<'b, B>(...) {...} - // } + // - We can create non-default generic parameters. + // - We can substitute default parameters into the signature. // - // reuse Trait::foo; - // desugaring: - // fn foo<'a, 'b, This: Trait<'a, A>, A, B>(...) { - // Trait::foo(...) - // } - own_params.sort_by_key(|key| key.kind.is_ty_or_const()); - - let param_def_id_to_index = - own_params.iter().map(|param| (param.def_id, param.index)).collect(); - - let (parent_count, has_self) = if let Some(def_id) = self.parent { - let parent_generics = self.tcx.generics_of(def_id); - let parent_kind = self.tcx.def_kind(def_id); - (parent_generics.count(), parent_kind == DefKind::Trait) - } else { - (0, false) - }; - - for (idx, param) in own_params.iter_mut().enumerate() { - param.index = (idx + parent_count) as u32; - // FIXME(fn_delegation): Default parameters are not inherited, because they are - // not permitted in functions. Therefore, there are 2 options here: - // - // - We can create non-default generic parameters. - // - We can substitute default parameters into the signature. - // - // At the moment, first option has been selected as the most general. - if let ty::GenericParamDefKind::Type { has_default, .. } - | ty::GenericParamDefKind::Const { has_default, .. } = &mut param.kind - { - *has_default = false; - } + // At the moment, first option has been selected as the most general. + if let ty::GenericParamDefKind::Type { has_default, .. } + | ty::GenericParamDefKind::Const { has_default, .. } = &mut param.kind + { + *has_default = false; } + } - ty::Generics { - parent: self.parent, - parent_count, - own_params, - param_def_id_to_index, - has_self, - has_late_bound_regions: sig_generics.has_late_bound_regions, - } + ty::Generics { + parent, + parent_count, + own_params, + param_def_id_to_index, + has_self, + has_late_bound_regions: sig_generics.has_late_bound_regions, } } -struct PredicatesBuilder<'tcx> { +fn build_predicates<'tcx>( tcx: TyCtxt<'tcx>, sig_id: DefId, parent: Option<DefId>, inh_kind: InheritanceKind, args: ty::GenericArgsRef<'tcx>, -} - -impl<'tcx> PredicatesBuilder<'tcx> { - fn new( +) -> ty::GenericPredicates<'tcx> { + struct PredicatesCollector<'tcx> { tcx: TyCtxt<'tcx>, + preds: Vec<(ty::Clause<'tcx>, Span)>, args: ty::GenericArgsRef<'tcx>, - sig_id: DefId, - ) -> PredicatesBuilder<'tcx> { - PredicatesBuilder { - tcx, - sig_id, - parent: None, - inh_kind: InheritanceKind::WithParent(false), - args, - } - } - - fn with_parent(mut self, parent: DefId) -> Self { - self.parent = Some(parent); - self } - fn with_inheritance_kind(mut self, inh_kind: InheritanceKind) -> Self { - self.inh_kind = inh_kind; - self - } - - fn build(self) -> ty::GenericPredicates<'tcx> { - struct PredicatesCollector<'tcx> { - tcx: TyCtxt<'tcx>, - preds: Vec<(ty::Clause<'tcx>, Span)>, - args: ty::GenericArgsRef<'tcx>, + impl<'tcx> PredicatesCollector<'tcx> { + fn new(tcx: TyCtxt<'tcx>, args: ty::GenericArgsRef<'tcx>) -> PredicatesCollector<'tcx> { + PredicatesCollector { tcx, preds: vec![], args } } - impl<'tcx> PredicatesCollector<'tcx> { - fn new(tcx: TyCtxt<'tcx>, args: ty::GenericArgsRef<'tcx>) -> PredicatesCollector<'tcx> { - PredicatesCollector { tcx, preds: vec![], args } - } - - fn with_own_preds( - mut self, - f: impl Fn(DefId) -> ty::GenericPredicates<'tcx>, - def_id: DefId, - ) -> Self { - let preds = f(def_id).instantiate_own(self.tcx, self.args); - self.preds.extend(preds); - self - } + fn with_own_preds( + mut self, + f: impl Fn(DefId) -> ty::GenericPredicates<'tcx>, + def_id: DefId, + ) -> Self { + let preds = f(def_id).instantiate_own(self.tcx, self.args); + self.preds.extend(preds); + self + } - fn with_preds( - mut self, - f: impl Fn(DefId) -> ty::GenericPredicates<'tcx> + Copy, - def_id: DefId, - ) -> Self { - let preds = f(def_id); - if let Some(parent_def_id) = preds.parent { - self = self.with_own_preds(f, parent_def_id); - } - self.with_own_preds(f, def_id) + fn with_preds( + mut self, + f: impl Fn(DefId) -> ty::GenericPredicates<'tcx> + Copy, + def_id: DefId, + ) -> Self { + let preds = f(def_id); + if let Some(parent_def_id) = preds.parent { + self = self.with_own_preds(f, parent_def_id); } + self.with_own_preds(f, def_id) } - let collector = PredicatesCollector::new(self.tcx, self.args); - - // `explicit_predicates_of` is used here to avoid copying `Self: Trait` predicate. - // Note: `predicates_of` query can also add inferred outlives predicates, but that - // is not the case here as `sig_id` is either a trait or a function. - let preds = match self.inh_kind { - InheritanceKind::WithParent(false) => { - collector.with_preds(|def_id| self.tcx.explicit_predicates_of(def_id), self.sig_id) - } - InheritanceKind::WithParent(true) => { - collector.with_preds(|def_id| self.tcx.predicates_of(def_id), self.sig_id) - } - InheritanceKind::Own => { - collector.with_own_preds(|def_id| self.tcx.predicates_of(def_id), self.sig_id) - } + } + let collector = PredicatesCollector::new(tcx, args); + + // `explicit_predicates_of` is used here to avoid copying `Self: Trait` predicate. + // Note: `predicates_of` query can also add inferred outlives predicates, but that + // is not the case here as `sig_id` is either a trait or a function. + let preds = match inh_kind { + InheritanceKind::WithParent(false) => { + collector.with_preds(|def_id| tcx.explicit_predicates_of(def_id), sig_id) } - .preds; - - ty::GenericPredicates { - parent: self.parent, - predicates: self.tcx.arena.alloc_from_iter(preds), + InheritanceKind::WithParent(true) => { + collector.with_preds(|def_id| tcx.predicates_of(def_id), sig_id) + } + InheritanceKind::Own => { + collector.with_own_preds(|def_id| tcx.predicates_of(def_id), sig_id) } } + .preds; + + ty::GenericPredicates { parent, predicates: tcx.arena.alloc_from_iter(preds) } } -struct GenericArgsBuilder<'tcx> { +fn build_generic_args<'tcx>( tcx: TyCtxt<'tcx>, - remap_table: RemapTable, sig_id: DefId, def_id: LocalDefId, -} + args: ty::GenericArgsRef<'tcx>, +) -> ty::GenericArgsRef<'tcx> { + let caller_generics = tcx.generics_of(def_id); + let callee_generics = tcx.generics_of(sig_id); -impl<'tcx> GenericArgsBuilder<'tcx> { - fn new(tcx: TyCtxt<'tcx>, sig_id: DefId, def_id: LocalDefId) -> GenericArgsBuilder<'tcx> { - GenericArgsBuilder { tcx, remap_table: FxHashMap::default(), sig_id, def_id } + let mut remap_table = FxHashMap::default(); + for caller_param in &caller_generics.own_params { + let callee_index = callee_generics.param_def_id_to_index(tcx, caller_param.def_id).unwrap(); + remap_table.insert(callee_index, caller_param.index); } - fn build_from_args(mut self, args: ty::GenericArgsRef<'tcx>) -> ty::GenericArgsRef<'tcx> { - let caller_generics = self.tcx.generics_of(self.def_id); - let callee_generics = self.tcx.generics_of(self.sig_id); - - for caller_param in &caller_generics.own_params { - let callee_index = - callee_generics.param_def_id_to_index(self.tcx, caller_param.def_id).unwrap(); - self.remap_table.insert(callee_index, caller_param.index); - } - - let mut folder = ParamIndexRemapper { tcx: self.tcx, remap_table: self.remap_table }; - args.fold_with(&mut folder) - } + let mut folder = ParamIndexRemapper { tcx, remap_table }; + args.fold_with(&mut folder) } fn create_generic_args<'tcx>( @@ -314,8 +257,6 @@ fn create_generic_args<'tcx>( def_id: LocalDefId, sig_id: DefId, ) -> ty::GenericArgsRef<'tcx> { - let builder = GenericArgsBuilder::new(tcx, sig_id, def_id); - let caller_kind = fn_kind(tcx, def_id.into()); let callee_kind = fn_kind(tcx, sig_id); match (caller_kind, callee_kind) { @@ -325,7 +266,7 @@ fn create_generic_args<'tcx>( | (FnKind::AssocTrait, FnKind::Free) | (FnKind::AssocTrait, FnKind::AssocTrait) => { let args = ty::GenericArgs::identity_for_item(tcx, sig_id); - builder.build_from_args(args) + build_generic_args(tcx, sig_id, def_id, args) } (FnKind::AssocTraitImpl, FnKind::AssocTrait) => { @@ -335,8 +276,9 @@ fn create_generic_args<'tcx>( tcx.impl_trait_header(parent).unwrap().trait_ref.instantiate_identity().args; let trait_args = ty::GenericArgs::identity_for_item(tcx, sig_id); - let method_args = tcx.mk_args_from_iter(trait_args.iter().skip(callee_generics.parent_count)); - let method_args = builder.build_from_args(method_args); + let method_args = + tcx.mk_args_from_iter(trait_args.iter().skip(callee_generics.parent_count)); + let method_args = build_generic_args(tcx, sig_id, def_id, method_args); tcx.mk_args_from_iter(parent_args.iter().chain(method_args)) } @@ -347,16 +289,16 @@ fn create_generic_args<'tcx>( let generic_self_ty = ty::GenericArg::from(self_ty); let trait_args = ty::GenericArgs::identity_for_item(tcx, sig_id); - let trait_args = builder.build_from_args(trait_args); + let trait_args = build_generic_args(tcx, sig_id, def_id, trait_args); let args = std::iter::once(generic_self_ty).chain(trait_args.iter().skip(1)); tcx.mk_args_from_iter(args) } // For trait impl's `sig_id` is always equal to the corresponding trait method. + // For inherent methods delegation is not yet supported. (FnKind::AssocTraitImpl, _) | (_, FnKind::AssocTraitImpl) - // Delegation to inherent methods is not yet supported. | (_, FnKind::AssocInherentImpl) => unreachable!(), } } @@ -377,39 +319,31 @@ pub(crate) fn inherit_generics_for_delegation_item<'tcx>( def_id: LocalDefId, sig_id: DefId, ) -> ty::Generics { - let builder = GenericsBuilder::new(tcx, sig_id); - let caller_kind = fn_kind(tcx, def_id.into()); let callee_kind = fn_kind(tcx, sig_id); match (caller_kind, callee_kind) { - (FnKind::Free, FnKind::Free) - | (FnKind::Free, FnKind::AssocTrait) => builder.with_inheritance_kind(InheritanceKind::WithParent(true)).build(), + (FnKind::Free, FnKind::Free) | (FnKind::Free, FnKind::AssocTrait) => { + build_generics(tcx, sig_id, None, InheritanceKind::WithParent(true)) + } (FnKind::AssocTraitImpl, FnKind::AssocTrait) => { - builder - .with_parent(tcx.parent(def_id.into())) - .with_inheritance_kind(InheritanceKind::Own) - .build() + build_generics(tcx, sig_id, Some(tcx.parent(def_id.into())), InheritanceKind::Own) } (FnKind::AssocInherentImpl, FnKind::AssocTrait) - | (FnKind::AssocTrait, FnKind::AssocTrait) => { - builder - .with_parent(tcx.parent(def_id.into())) - .build() - } - - (FnKind::AssocInherentImpl, FnKind::Free) - | (FnKind::AssocTrait, FnKind::Free) => { - builder - .with_parent(tcx.parent(def_id.into())) - .build() - } + | (FnKind::AssocTrait, FnKind::AssocTrait) + | (FnKind::AssocInherentImpl, FnKind::Free) + | (FnKind::AssocTrait, FnKind::Free) => build_generics( + tcx, + sig_id, + Some(tcx.parent(def_id.into())), + InheritanceKind::WithParent(false), + ), // For trait impl's `sig_id` is always equal to the corresponding trait method. + // For inherent methods delegation is not yet supported. (FnKind::AssocTraitImpl, _) | (_, FnKind::AssocTraitImpl) - // Delegation to inherent methods is not yet supported. | (_, FnKind::AssocInherentImpl) => unreachable!(), } } @@ -420,36 +354,36 @@ pub(crate) fn inherit_predicates_for_delegation_item<'tcx>( sig_id: DefId, ) -> ty::GenericPredicates<'tcx> { let args = create_generic_args(tcx, def_id, sig_id); - let builder = PredicatesBuilder::new(tcx, args, sig_id); - let caller_kind = fn_kind(tcx, def_id.into()); let callee_kind = fn_kind(tcx, sig_id); match (caller_kind, callee_kind) { - (FnKind::Free, FnKind::Free) - | (FnKind::Free, FnKind::AssocTrait) => { - builder.with_inheritance_kind(InheritanceKind::WithParent(true)).build() + (FnKind::Free, FnKind::Free) | (FnKind::Free, FnKind::AssocTrait) => { + build_predicates(tcx, sig_id, None, InheritanceKind::WithParent(true), args) } - (FnKind::AssocTraitImpl, FnKind::AssocTrait) => { - builder - .with_parent(tcx.parent(def_id.into())) - .with_inheritance_kind(InheritanceKind::Own) - .build() - } + (FnKind::AssocTraitImpl, FnKind::AssocTrait) => build_predicates( + tcx, + sig_id, + Some(tcx.parent(def_id.into())), + InheritanceKind::Own, + args, + ), (FnKind::AssocInherentImpl, FnKind::AssocTrait) | (FnKind::AssocTrait, FnKind::AssocTrait) | (FnKind::AssocInherentImpl, FnKind::Free) - | (FnKind::AssocTrait, FnKind::Free) => { - builder - .with_parent(tcx.parent(def_id.into())) - .build() - } + | (FnKind::AssocTrait, FnKind::Free) => build_predicates( + tcx, + sig_id, + Some(tcx.parent(def_id.into())), + InheritanceKind::WithParent(false), + args, + ), // For trait impl's `sig_id` is always equal to the corresponding trait method. + // For inherent methods delegation is not yet supported. (FnKind::AssocTraitImpl, _) | (_, FnKind::AssocTraitImpl) - // Delegation to inherent methods is not yet supported. | (_, FnKind::AssocInherentImpl) => unreachable!(), } } diff --git a/compiler/rustc_hir_analysis/src/errors/pattern_types.rs b/compiler/rustc_hir_analysis/src/errors/pattern_types.rs index bb771d6ea17..272edbe841b 100644 --- a/compiler/rustc_hir_analysis/src/errors/pattern_types.rs +++ b/compiler/rustc_hir_analysis/src/errors/pattern_types.rs @@ -1,4 +1,5 @@ use rustc_macros::Diagnostic; +use rustc_middle::ty::Ty; use rustc_span::Span; #[derive(Diagnostic)] @@ -7,3 +8,14 @@ pub(crate) struct WildPatTy { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_invalid_base_type)] +pub(crate) struct InvalidBaseType<'tcx> { + pub ty: Ty<'tcx>, + #[primary_span] + pub ty_span: Span, + pub pat: &'static str, + #[note] + pub pat_span: Span, +} diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs index 67407349729..b2501d647a5 100644 --- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs @@ -495,6 +495,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { .iter() .any(|constraint| constraint.ident.name == item.name) }) + .filter(|item| !item.is_impl_trait_in_trait()) .map(|item| self.tcx.item_ident(item.def_id).to_string()) .collect() } else { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 36b214b6ae7..79aa2f4b8cc 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -3,7 +3,7 @@ use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordMap; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err, + Applicability, Diag, ErrorGuaranteed, MultiSpan, listify, pluralize, struct_span_code_err, }; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -808,14 +808,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .map(|(trait_, mut assocs)| { assocs.sort(); let trait_ = trait_.print_trait_sugared(); - format!("{} in `{trait_}`", match &assocs[..] { - [] => String::new(), - [only] => format!("`{only}`"), - [assocs @ .., last] => format!( - "{} and `{last}`", - assocs.iter().map(|a| format!("`{a}`")).collect::<Vec<_>>().join(", ") - ), - }) + format!( + "{} in `{trait_}`", + listify(&assocs[..], |a| format!("`{a}`")).unwrap_or_default() + ) }) .collect::<Vec<String>>(); names.sort(); @@ -1075,18 +1071,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } }) .collect(); - let this_type = match &types_and_spans[..] { - [.., _, (last, _)] => format!( - "{} and {last}", - types_and_spans[..types_and_spans.len() - 1] - .iter() - .map(|(x, _)| x.as_str()) - .intersperse(", ") - .collect::<String>() - ), - [(only, _)] => only.to_string(), - [] => bug!("expected one segment to deny"), - }; + let this_type = listify(&types_and_spans, |(t, _)| t.to_string()) + .expect("expected one segment to deny"); let arg_spans: Vec<Span> = segments .clone() @@ -1102,21 +1088,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ProhibitGenericsArg::Infer => kinds.push("generic"), }); - let (kind, s) = match kinds[..] { - [.., _, last] => ( - format!( - "{} and {last}", - kinds[..kinds.len() - 1] - .iter() - .map(|&x| x) - .intersperse(", ") - .collect::<String>() - ), - "s", - ), - [only] => (only.to_string(), ""), - [] => bug!("expected at least one generic to prohibit"), - }; + let s = pluralize!(kinds.len()); + let kind = + listify(&kinds, |k| k.to_string()).expect("expected at least one generic to prohibit"); let last_span = *arg_spans.last().unwrap(); let span: MultiSpan = arg_spans.into(); let mut err = struct_span_code_err!( diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index fe3dcb35639..43137397870 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -273,7 +273,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( // We lower to an infer even when the feature gate is not enabled // as it is useful for diagnostics to be able to see a `ConstKind::Infer` - args.push(ctx.provided_kind(&args, param, arg)); + args.push(ctx.provided_kind(param, arg)); args_iter.next(); params.next(); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 61d5869c19f..5813fdeae76 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -53,7 +53,7 @@ use tracing::{debug, instrument}; use crate::bounds::Bounds; use crate::check::check_abi_fn_ptr; -use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, WildPatTy}; +use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, InvalidBaseType, WildPatTy}; use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; use crate::middle::resolve_bound_vars as rbv; @@ -296,7 +296,6 @@ pub trait GenericArgsLowerer<'a, 'tcx> { fn provided_kind( &mut self, - preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx>; @@ -480,7 +479,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn provided_kind( &mut self, - _preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { @@ -2434,6 +2432,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.ty_infer(None, hir_ty.span) } hir::TyKind::Pat(ty, pat) => { + let ty_span = ty.span; let ty = self.lower_ty(ty); let pat_ty = match pat.kind { hir::PatKind::Wild => { @@ -2441,6 +2440,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ty::new_error(tcx, err) } hir::PatKind::Range(start, end, include_end) => { + let ty = match ty.kind() { + ty::Int(_) | ty::Uint(_) | ty::Char => ty, + _ => Ty::new_error( + tcx, + self.dcx().emit_err(InvalidBaseType { + ty, + pat: "range", + ty_span, + pat_span: pat.span, + }), + ), + }; let expr_to_const = |expr: &'tcx hir::PatExpr<'tcx>| -> ty::Const<'tcx> { let (c, c_ty) = match expr.kind { hir::PatExprKind::Lit { lit, negated } => { diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index fd5a7089b4c..c30b39dfe76 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -62,7 +62,7 @@ pub(crate) fn check_impl_wf( // Check that the args are constrained. We queryfied the check for ty/const params // since unconstrained type/const params cause ICEs in projection, so we want to // detect those specifically and project those to `TyKind::Error`. - let mut res = tcx.ensure().enforce_impl_non_lifetime_params_are_constrained(impl_def_id); + let mut res = tcx.ensure_ok().enforce_impl_non_lifetime_params_are_constrained(impl_def_id); res = res.and(enforce_impl_lifetime_params_are_constrained(tcx, impl_def_id)); if tcx.features().min_specialization() { diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 32694d5f4bc..af1107b499f 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -34,7 +34,7 @@ //! impl<T, I: Iterator<Item=T>> SpecExtend<T> for I { /* default impl */ } //! ``` //! -//! We get that the generic pamameters for `impl2` are `[T, std::vec::IntoIter<T>]`. +//! We get that the generic parameters for `impl2` are `[T, std::vec::IntoIter<T>]`. //! `T` is constrained to be `<I as Iterator>::Item`, so we check only //! `std::vec::IntoIter<T>` for repeated parameters, which it doesn't have. The //! predicates of `impl1` are only `T: Sized`, which is also a predicate of @@ -119,7 +119,6 @@ fn check_always_applicable( impl2_node: Node, ) -> Result<(), ErrorGuaranteed> { let span = tcx.def_span(impl1_def_id); - let mut res = check_has_items(tcx, impl1_def_id, impl2_node, span); let (impl1_args, impl2_args) = get_impl_args(tcx, impl1_def_id, impl2_node)?; let impl2_def_id = impl2_node.def_id(); @@ -131,11 +130,10 @@ fn check_always_applicable( unconstrained_parent_impl_args(tcx, impl2_def_id, impl2_args) }; - res = res.and(check_static_lifetimes(tcx, &parent_args, span)); - res = res.and(check_duplicate_params(tcx, impl1_args, parent_args, span)); - res = res.and(check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span)); - - res + check_has_items(tcx, impl1_def_id, impl2_node, span) + .and(check_static_lifetimes(tcx, &parent_args, span)) + .and(check_duplicate_params(tcx, impl1_args, parent_args, span)) + .and(check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span)) } fn check_has_items( diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index bc7d4365eee..3af4318544e 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -83,12 +83,11 @@ pub mod autoderef; mod bounds; mod check_unused; mod coherence; -mod delegation; -pub mod hir_ty_lowering; -// FIXME: This module shouldn't be public. -pub mod collect; +mod collect; mod constrained_generic_params; +mod delegation; mod errors; +pub mod hir_ty_lowering; pub mod hir_wf_check; mod impl_wf_check; mod outlives; @@ -101,10 +100,11 @@ use rustc_middle::middle; use rustc_middle::mir::interpret::GlobalId; use rustc_middle::query::Providers; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits; -use self::hir_ty_lowering::{FeedConstTy, HirTyLowerer}; +pub use crate::collect::suggest_impl_trait; +use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer}; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } @@ -139,24 +139,31 @@ pub fn check_crate(tcx: TyCtxt<'_>) { let _prof_timer = tcx.sess.timer("type_check_crate"); tcx.sess.time("coherence_checking", || { + // When discarding query call results, use an explicit type to indicate + // what we are intending to discard, to help future type-based refactoring. + type R = Result<(), ErrorGuaranteed>; + tcx.hir().par_for_each_module(|module| { - let _ = tcx.ensure().check_mod_type_wf(module); + let _: R = tcx.ensure_ok().check_mod_type_wf(module); }); for &trait_def_id in tcx.all_local_trait_impls(()).keys() { - let _ = tcx.ensure().coherent_trait(trait_def_id); + let _: R = tcx.ensure_ok().coherent_trait(trait_def_id); } // these queries are executed for side-effects (error reporting): - let _ = tcx.ensure().crate_inherent_impls_validity_check(()); - let _ = tcx.ensure().crate_inherent_impls_overlap_check(()); + let _: R = tcx.ensure_ok().crate_inherent_impls_validity_check(()); + let _: R = tcx.ensure_ok().crate_inherent_impls_overlap_check(()); }); if tcx.features().rustc_attrs() { - 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); - collect::dump::def_parents(tcx); + tcx.sess.time("dumping_rustc_attr_data", || { + outlives::dump::inferred_outlives(tcx); + variance::dump::variances(tcx); + collect::dump::opaque_hidden_types(tcx); + collect::dump::predicates_and_item_bounds(tcx); + collect::dump::def_parents(tcx); + collect::dump::vtables(tcx); + }); } // Make sure we evaluate all static and (non-associated) const items, even if unused. @@ -164,12 +171,12 @@ pub fn check_crate(tcx: TyCtxt<'_>) { tcx.hir().par_body_owners(|item_def_id| { let def_kind = tcx.def_kind(item_def_id); match def_kind { - DefKind::Static { .. } => tcx.ensure().eval_static_initializer(item_def_id), + DefKind::Static { .. } => tcx.ensure_ok().eval_static_initializer(item_def_id), DefKind::Const if tcx.generics_of(item_def_id).is_empty() => { let instance = ty::Instance::new(item_def_id.into(), ty::GenericArgs::empty()); let cid = GlobalId { instance, promoted: None }; let typing_env = ty::TypingEnv::fully_monomorphized(); - tcx.ensure().eval_to_const_value_raw(typing_env.as_query_input(cid)); + tcx.ensure_ok().eval_to_const_value_raw(typing_env.as_query_input(cid)); } _ => (), } @@ -182,11 +189,11 @@ pub fn check_crate(tcx: TyCtxt<'_>) { tcx.hir().par_body_owners(|item_def_id| { let def_kind = tcx.def_kind(item_def_id); if !matches!(def_kind, DefKind::AnonConst) { - tcx.ensure().typeck(item_def_id); + tcx.ensure_ok().typeck(item_def_id); } }); - tcx.ensure().check_unused_traits(()); + tcx.ensure_ok().check_unused_traits(()); } /// Lower a [`hir::Ty`] to a [`Ty`]. diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index c2377b4781c..036163b9f14 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -24,7 +24,7 @@ pub(super) fn infer_predicates( // If new predicates were added then we need to re-calculate // all crates since there could be new implied predicates. - 'outer: loop { + loop { let mut predicates_added = false; // Visit all the crates and infer predicates @@ -90,7 +90,7 @@ pub(super) fn infer_predicates( } if !predicates_added { - break 'outer; + break; } } diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 02cfb57b836..a7760326bb4 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -27,9 +27,6 @@ mod solve; pub(crate) mod dump; -/// Code for transforming variances. -mod xform; - pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { variances_of, crate_variances, ..*providers }; } diff --git a/compiler/rustc_hir_analysis/src/variance/solve.rs b/compiler/rustc_hir_analysis/src/variance/solve.rs index d0bdca86779..4106c1a5b63 100644 --- a/compiler/rustc_hir_analysis/src/variance/solve.rs +++ b/compiler/rustc_hir_analysis/src/variance/solve.rs @@ -12,8 +12,26 @@ use tracing::debug; use super::constraints::*; use super::terms::VarianceTerm::*; use super::terms::*; -use super::xform::*; +fn glb(v1: ty::Variance, v2: ty::Variance) -> ty::Variance { + // Greatest lower bound of the variance lattice as defined in The Paper: + // + // * + // - + + // o + match (v1, v2) { + (ty::Invariant, _) | (_, ty::Invariant) => ty::Invariant, + + (ty::Covariant, ty::Contravariant) => ty::Invariant, + (ty::Contravariant, ty::Covariant) => ty::Invariant, + + (ty::Covariant, ty::Covariant) => ty::Covariant, + + (ty::Contravariant, ty::Contravariant) => ty::Contravariant, + + (x, ty::Bivariant) | (ty::Bivariant, x) => x, + } +} struct SolveContext<'a, 'tcx> { terms_cx: TermsContext<'a, 'tcx>, constraints: Vec<Constraint<'a>>, diff --git a/compiler/rustc_hir_analysis/src/variance/xform.rs b/compiler/rustc_hir_analysis/src/variance/xform.rs deleted file mode 100644 index 2e9964788e6..00000000000 --- a/compiler/rustc_hir_analysis/src/variance/xform.rs +++ /dev/null @@ -1,22 +0,0 @@ -use rustc_middle::ty; - -pub(crate) fn glb(v1: ty::Variance, v2: ty::Variance) -> ty::Variance { - // Greatest lower bound of the variance lattice as - // defined in The Paper: - // - // * - // - + - // o - match (v1, v2) { - (ty::Invariant, _) | (_, ty::Invariant) => ty::Invariant, - - (ty::Covariant, ty::Contravariant) => ty::Invariant, - (ty::Contravariant, ty::Covariant) => ty::Invariant, - - (ty::Covariant, ty::Covariant) => ty::Covariant, - - (ty::Contravariant, ty::Contravariant) => ty::Contravariant, - - (x, ty::Bivariant) | (ty::Bivariant, x) => x, - } -} diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 28b1a823dae..edc3702d90b 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -49,7 +49,7 @@ pub(crate) fn check_legal_trait_for_method_call( }; return Err(tcx.dcx().emit_err(errors::ExplicitDestructorCall { span, sugg })); } - tcx.ensure().coherent_trait(trait_id) + tcx.ensure_ok().coherent_trait(trait_id) } #[derive(Debug)] diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 153fd6001bb..83acc7dd6af 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -50,7 +50,6 @@ use rustc_infer::traits::{ IfExpressionCause, MatchExpressionArmCause, Obligation, PredicateObligation, PredicateObligations, }; -use rustc_middle::lint::in_external_macro; use rustc_middle::span_bug; use rustc_middle::traits::BuiltinImplSource; use rustc_middle::ty::adjustment::{ @@ -1937,7 +1936,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { cond_expr.span.desugaring_kind(), None | Some(DesugaringKind::WhileLoop) ) - && !in_external_macro(fcx.tcx.sess, cond_expr.span) + && !cond_expr.span.in_external_macro(fcx.tcx.sess.source_map()) && !matches!( cond_expr.kind, hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_)) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index bc076670585..85e949952f8 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -1,4 +1,4 @@ -use rustc_errors::{Applicability, Diag, MultiSpan}; +use rustc_errors::{Applicability, Diag, MultiSpan, listify}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::intravisit::Visitor; @@ -1016,18 +1016,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, self.tcx.def_path_str(candidate.item.container_id(self.tcx)) ), - [.., last] if other_methods_in_scope.len() < 5 => { + _ if other_methods_in_scope.len() < 5 => { format!( - "the methods of the same name on {} and `{}`", - other_methods_in_scope[..other_methods_in_scope.len() - 1] - .iter() - .map(|c| format!( - "`{}`", - self.tcx.def_path_str(c.item.container_id(self.tcx)) - )) - .collect::<Vec<String>>() - .join(", "), - self.tcx.def_path_str(last.item.container_id(self.tcx)) + "the methods of the same name on {}", + listify( + &other_methods_in_scope[..other_methods_in_scope.len() - 1], + |c| format!("`{}`", self.tcx.def_path_str(c.item.container_id(self.tcx))) + ) + .unwrap_or_default(), ) } _ => format!( diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index f79667e59ba..a519e177fbc 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -11,7 +11,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::UnordMap; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, Subdiagnostic, pluralize, + Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, Subdiagnostic, listify, pluralize, struct_span_code_err, }; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -1658,8 +1658,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir_ty: Option<&'tcx hir::Ty<'tcx>>, expected: Expectation<'tcx>, ) -> Ty<'tcx> { - self.dcx().span_err(inner_expr.span, "unsafe binder casts are not fully implemented"); - match kind { hir::UnsafeBinderCastKind::Wrap => { let ascribed_ty = @@ -2190,13 +2188,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if !missing_mandatory_fields.is_empty() { let s = pluralize!(missing_mandatory_fields.len()); - let fields: Vec<_> = - missing_mandatory_fields.iter().map(|f| format!("`{f}`")).collect(); - let fields = match &fields[..] { - [] => unreachable!(), - [only] => only.to_string(), - [start @ .., last] => format!("{} and {last}", start.join(", ")), - }; + let fields = listify(&missing_mandatory_fields, |f| format!("`{f}`")).unwrap(); self.dcx() .struct_span_err( span.shrink_to_hi(), @@ -2553,25 +2545,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .partition(|field| field.2); err.span_labels(used_private_fields.iter().map(|(_, span, _)| *span), "private field"); if !remaining_private_fields.is_empty() { - let remaining_private_fields_len = remaining_private_fields.len(); - let names = match &remaining_private_fields - .iter() - .map(|(name, _, _)| name) - .collect::<Vec<_>>()[..] - { - _ if remaining_private_fields_len > 6 => String::new(), - [name] => format!("`{name}` "), - [names @ .., last] => { - let names = names.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>(); - format!("{} and `{last}` ", names.join(", ")) - } - [] => bug!("expected at least one private field to report"), + let names = if remaining_private_fields.len() > 6 { + String::new() + } else { + format!( + "{} ", + listify(&remaining_private_fields, |(name, _, _)| format!("`{name}`")) + .expect("expected at least one private field to report") + ) }; err.note(format!( "{}private field{s} {names}that {were} not provided", if used_fields.is_empty() { "" } else { "...and other " }, - s = pluralize!(remaining_private_fields_len), - were = pluralize!("was", remaining_private_fields_len), + s = pluralize!(remaining_private_fields.len()), + were = pluralize!("was", remaining_private_fields.len()), )); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 8e647ad3c6a..9277d71234f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -253,6 +253,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } + let mut expr_ty = self.typeck_results.borrow().expr_ty_adjusted(expr); + for a in &adj { match a.kind { Adjust::NeverToAny => { @@ -266,7 +268,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None, expr.span, overloaded_deref.method_call(self.tcx), - self.tcx.mk_args(&[a.target.into()]), + self.tcx.mk_args(&[expr_ty.into()]), ); } Adjust::Deref(None) => { @@ -283,6 +285,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // No effects to enforce here. } } + + expr_ty = a.target; } let autoborrow_mut = adj.iter().any(|adj| { @@ -1261,7 +1265,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn provided_kind( &mut self, - _preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 8e78fb3e219..bbe65371496 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -4,8 +4,7 @@ use itertools::Itertools; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, a_or_an, - display_list_with_comma_and, pluralize, + Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, a_or_an, listify, pluralize, }; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -1147,6 +1146,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(self.param_env.and(trace.values)), e, true, + None, ); } } @@ -2461,7 +2461,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { param.span, format!( "{} need{} to match the {} type of this parameter", - display_list_with_comma_and(&other_param_matched_names), + listify(&other_param_matched_names, |n| n.to_string()) + .unwrap_or_default(), pluralize!(if other_param_matched_names.len() == 1 { 0 } else { @@ -2476,7 +2477,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!( "this parameter needs to match the {} type of {}", matched_ty, - display_list_with_comma_and(&other_param_matched_names), + listify(&other_param_matched_names, |n| n.to_string()) + .unwrap_or_default(), ), ); } @@ -2522,7 +2524,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { generic_param.span, format!( "{} {} reference this parameter `{}`", - display_list_with_comma_and(¶m_idents_matching), + listify(¶m_idents_matching, |n| n.to_string()) + .unwrap_or_default(), if param_idents_matching.len() == 2 { "both" } else { "all" }, generic_param.name.ident().name, ), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index d432199f037..b77e6de52ff 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -31,12 +31,12 @@ use crate::{CoroutineTypes, Diverges, EnclosingBreakables, TypeckRootCtxt}; /// functions, closures, and `const`s, including performing type inference /// with [`InferCtxt`]. /// -/// This is in contrast to [`ItemCtxt`], which is used to type-check item *signatures* -/// and thus does not perform type inference. +/// This is in contrast to `rustc_hir_analysis::collect::ItemCtxt`, which is +/// used to type-check item *signatures* and thus does not perform type +/// inference. /// -/// See [`ItemCtxt`]'s docs for more. +/// See `ItemCtxt`'s docs for more. /// -/// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt /// [`InferCtxt`]: infer::InferCtxt pub(crate) struct FnCtxt<'a, 'tcx> { pub(super) body_id: LocalDefId, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index aea2e0fd3a3..217ebd9cd2b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -4,7 +4,7 @@ use core::iter; use hir::def_id::LocalDefId; use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::packed::Pu128; -use rustc_errors::{Applicability, Diag, MultiSpan}; +use rustc_errors::{Applicability, Diag, MultiSpan, listify}; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ @@ -12,9 +12,8 @@ use rustc_hir::{ GenericBound, HirId, Node, PatExpr, PatExprKind, Path, QPath, Stmt, StmtKind, TyKind, WherePredicateKind, expr_needs_parens, }; -use rustc_hir_analysis::collect::suggest_impl_trait; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; -use rustc_middle::lint::in_external_macro; +use rustc_hir_analysis::suggest_impl_trait; use rustc_middle::middle::stability::EvalResult; use rustc_middle::span_bug; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -770,7 +769,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If the expression is from an external macro, then do not suggest // adding a semicolon, because there's nowhere to put it. // See issue #81943. - && !in_external_macro(self.tcx.sess, expression.span) => + && !expression.span.in_external_macro(self.tcx.sess.source_map()) => { if needs_block { err.multipart_suggestion( @@ -1836,16 +1835,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error.obligation.predicate, )); } - [errors @ .., last] => { + _ => { diag.help(format!( "`Clone` is not implemented because the following trait bounds \ - could not be satisfied: {} and `{}`", - errors - .iter() - .map(|e| format!("`{}`", e.obligation.predicate)) - .collect::<Vec<_>>() - .join(", "), - last.obligation.predicate, + could not be satisfied: {}", + listify(&errors, |e| format!("`{}`", e.obligation.predicate)) + .unwrap(), )); } } @@ -2265,7 +2260,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, expr_ty: Ty<'tcx>, ) -> bool { - if in_external_macro(self.tcx.sess, expr.span) { + if expr.span.in_external_macro(self.tcx.sess.source_map()) { return false; } if let ty::Adt(expected_adt, args) = expected.kind() { @@ -2593,14 +2588,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )> { let sess = self.sess(); let sp = expr.span; + let sm = sess.source_map(); // If the span is from an external macro, there's no suggestion we can make. - if in_external_macro(sess, sp) { + if sp.in_external_macro(sm) { return None; } - let sm = sess.source_map(); - let replace_prefix = |s: &str, old: &str, new: &str| { s.strip_prefix(old).map(|stripped| new.to_string() + stripped) }; diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 880ee83c80a..5c1c38aeb95 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -413,7 +413,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { fn provided_kind( &mut self, - _preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index e4a6a0fedc5..920418407c0 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -5,6 +5,7 @@ use core::ops::ControlFlow; use std::borrow::Cow; +use std::path::PathBuf; use hir::Expr; use rustc_ast::ast::Mutability; @@ -362,14 +363,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn suggest_missing_writer(&self, rcvr_ty: Ty<'tcx>, rcvr_expr: &hir::Expr<'tcx>) -> Diag<'_> { let mut file = None; - let ty_str = self.tcx.short_ty_string(rcvr_ty, &mut file); let mut err = struct_span_code_err!( self.dcx(), rcvr_expr.span, E0599, "cannot write into `{}`", - ty_str + self.tcx.short_string(rcvr_ty, &mut file), ); + *err.long_ty_path() = file; err.span_note( rcvr_expr.span, "must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method", @@ -380,11 +381,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "a writer is needed before this format string", ); }; - if let Some(file) = file { - err.note(format!("the full type name has been written to '{}'", file.display())); - err.note("consider using `--verbose` to print the full type name to the console"); - } - err } @@ -595,7 +591,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (predicates.to_string(), with_forced_trimmed_paths!(predicates.to_string())) } else { ( - tcx.short_ty_string(rcvr_ty, &mut ty_file), + tcx.short_string(rcvr_ty, &mut ty_file), with_forced_trimmed_paths!(rcvr_ty.to_string()), ) }; @@ -624,6 +620,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, item_name, &short_ty_str, + &mut ty_file, ) { return guar; } @@ -635,6 +632,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_kind, item_name, &short_ty_str, + &mut ty_file, ) { return guar; } @@ -728,10 +726,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty_str = short_ty_str; } - if let Some(file) = ty_file { - err.note(format!("the full type name has been written to '{}'", file.display(),)); - err.note("consider using `--verbose` to print the full type name to the console"); - } if rcvr_ty.references_error() { err.downgrade_to_delayed_bug(); } @@ -1314,7 +1308,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bound_list.into_iter().map(|(_, path)| path).collect::<Vec<_>>().join("\n"); let actual_prefix = rcvr_ty.prefix_string(self.tcx); info!("unimplemented_traits.len() == {}", unimplemented_traits.len()); - let mut long_ty_file = None; let (primary_message, label, notes) = if unimplemented_traits.len() == 1 && unimplemented_traits_only { @@ -1329,7 +1322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let OnUnimplementedNote { message, label, notes, .. } = self .err_ctxt() - .on_unimplemented_note(trait_ref, &obligation, &mut long_ty_file); + .on_unimplemented_note(trait_ref, &obligation, &mut ty_file); (message, label, notes) }) .unwrap() @@ -1343,15 +1336,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) }); err.primary_message(primary_message); - if let Some(file) = long_ty_file { - err.note(format!( - "the full name for the type has been written to '{}'", - file.display(), - )); - err.note( - "consider using `--verbose` to print the full type name to the console", - ); - } if let Some(label) = label { custom_span_label = true; err.span_label(span, label); @@ -2403,6 +2387,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, item_name: Ident, ty_str: &str, + long_ty_path: &mut Option<PathBuf>, ) -> Result<(), ErrorGuaranteed> { if let SelfSource::MethodCall(expr) = source { for (_, parent) in tcx.hir().parent_iter(expr.hir_id).take(5) { @@ -2460,7 +2445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); if pick.is_ok() { let range_span = parent_expr.span.with_hi(expr.span.hi()); - return Err(self.dcx().emit_err(errors::MissingParenthesesInRange { + let mut err = self.dcx().create_err(errors::MissingParenthesesInRange { span, ty_str: ty_str.to_string(), method_name: item_name.as_str().to_string(), @@ -2469,7 +2454,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { left: range_span.shrink_to_lo(), right: range_span.shrink_to_hi(), }), - })); + }); + *err.long_ty_path() = long_ty_path.take(); + return Err(err.emit()); } } } @@ -2486,6 +2473,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_kind: &str, item_name: Ident, ty_str: &str, + long_ty_path: &mut Option<PathBuf>, ) -> Result<(), ErrorGuaranteed> { let found_candidate = all_traits(self.tcx) .into_iter() @@ -2526,6 +2514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_name, ty_str ); + *err.long_ty_path() = long_ty_path.take(); let concrete_type = if actual.is_integral() { "i32" } else { "f32" }; match expr.kind { ExprKind::Lit(lit) => { diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 0aa2f1110fb..c947ecde656 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -243,8 +243,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn downgrade_mut_inside_shared(&self) -> bool { // NB: RFC 3627 proposes stabilizing Rule 3 in all editions. If we adopt the same behavior // across all editions, this may be removed. - self.tcx.features().ref_pat_eat_one_layer_2024() - || self.tcx.features().ref_pat_eat_one_layer_2024_structural() + self.tcx.features().ref_pat_eat_one_layer_2024_structural() } /// Experimental pattern feature: when do reference patterns match against inherited references? @@ -435,7 +434,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { max_ref_mutbl: MutblCap, ) -> (Ty<'tcx>, ByRef, MutblCap) { #[cfg(debug_assertions)] - if def_br == ByRef::Yes(Mutability::Mut) && max_ref_mutbl != MutblCap::Mut { + if def_br == ByRef::Yes(Mutability::Mut) + && max_ref_mutbl != MutblCap::Mut + && self.downgrade_mut_inside_shared() + { span_bug!(pat.span, "Pattern mutability cap violated!"); } match adjust_mode { @@ -2328,22 +2330,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // (RFC 3627, Rule 5). If we implement a pattern typing ruleset with Rule 4E // but not Rule 5, we'll need to check that here. debug_assert!(ref_pat_matches_mut_ref); - let err_msg = "mismatched types"; - let err = if let Some(span) = pat_prefix_span { - let mut err = self.dcx().struct_span_err(span, err_msg); - err.code(E0308); - err.note("cannot match inherited `&` with `&mut` pattern"); - err.span_suggestion_verbose( - span, - "replace this `&mut` pattern with `&`", - "&", - Applicability::MachineApplicable, - ); - err - } else { - self.dcx().struct_span_err(pat.span, err_msg) - }; - err.emit(); + self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span); } pat_info.binding_mode = ByRef::No; @@ -2352,28 +2339,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return expected; } InheritedRefMatchRule::EatInner => { - if let ty::Ref(_, _, r_mutbl) = *expected.kind() { + if let ty::Ref(_, _, r_mutbl) = *expected.kind() + && pat_mutbl <= r_mutbl + { // Match against the reference type; don't consume the inherited ref. - pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(r_mutbl); + // NB: The check for compatible pattern and ref type mutability assumes that + // `&` patterns can match against mutable references (RFC 3627, Rule 5). If + // we implement a pattern typing ruleset with Rule 4 (including the fallback + // to matching the inherited ref when the inner ref can't match) but not + // Rule 5, we'll need to check that here. + debug_assert!(ref_pat_matches_mut_ref); + // NB: For RFC 3627's Rule 3, we limit the default binding mode's ref + // mutability to `pat_info.max_ref_mutbl`. If we implement a pattern typing + // ruleset with Rule 4 but not Rule 3, we'll need to check that here. + debug_assert!(self.downgrade_mut_inside_shared()); + let mutbl_cap = cmp::min(r_mutbl, pat_info.max_ref_mutbl.as_mutbl()); + pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(mutbl_cap); } else { - // The expected type isn't a reference, so match against the inherited ref. + // The reference pattern can't match against the expected type, so try + // matching against the inherited ref instead. if pat_mutbl > inh_mut { - // We can't match an inherited shared reference with `&mut`. This will - // be a type error later, since we're matching a reference pattern - // against a non-reference type. + // We can't match an inherited shared reference with `&mut`. // NB: This assumes that `&` patterns can match against mutable // references (RFC 3627, Rule 5). If we implement a pattern typing // ruleset with Rule 4 but not Rule 5, we'll need to check that here. debug_assert!(ref_pat_matches_mut_ref); - } else { - pat_info.binding_mode = ByRef::No; - self.typeck_results - .borrow_mut() - .skipped_ref_pats_mut() - .insert(pat.hir_id); - self.check_pat(inner, expected, pat_info); - return expected; + self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span); } + + pat_info.binding_mode = ByRef::No; + self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id); + self.check_pat(inner, expected, pat_info); + return expected; } } InheritedRefMatchRule::EatBoth => { @@ -2447,6 +2444,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ty::new_ref(self.tcx, region, ty, mutbl) } + fn error_inherited_ref_mutability_mismatch( + &self, + pat: &'tcx Pat<'tcx>, + pat_prefix_span: Option<Span>, + ) -> ErrorGuaranteed { + let err_msg = "mismatched types"; + let err = if let Some(span) = pat_prefix_span { + let mut err = self.dcx().struct_span_err(span, err_msg); + err.code(E0308); + err.note("cannot match inherited `&` with `&mut` pattern"); + err.span_suggestion_verbose( + span, + "replace this `&mut` pattern with `&`", + "&", + Applicability::MachineApplicable, + ); + err + } else { + self.dcx().struct_span_err(pat.span, err_msg) + }; + err.emit() + } + fn try_resolve_slice_ty_to_array_ty( &self, before: &'tcx [Pat<'tcx>], diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index 6dab6468870..563ed7614c6 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -24,7 +24,7 @@ use rustc_middle::util::Providers; #[allow(missing_docs)] pub fn provide(providers: &mut Providers) { providers.hooks.save_dep_graph = - |tcx| tcx.sess.time("serialize_dep_graph", || persist::save_dep_graph(tcx.tcx)); + |tcx| tcx.sess.time("serialize_dep_graph", || persist::save_dep_graph(tcx)); } rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 12e2bbc968f..ad15b764bcc 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -402,6 +402,18 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> { } } +impl<'tcx> ToTrace<'tcx> for ty::ExistentialTraitRef<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { + TypeTrace { + cause: cause.clone(), + values: ValuePairs::ExistentialTraitRef(ExpectedFound::new( + ty::Binder::dummy(a), + ty::Binder::dummy(b), + )), + } + } +} + impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> { fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { @@ -410,3 +422,15 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> { } } } + +impl<'tcx> ToTrace<'tcx> for ty::ExistentialProjection<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { + TypeTrace { + cause: cause.clone(), + values: ValuePairs::ExistentialProjection(ExpectedFound::new( + ty::Binder::dummy(a), + ty::Binder::dummy(b), + )), + } + } +} diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index 28eac5b7496..74c8b463fc8 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -170,7 +170,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> { } ty::ConstKind::Param(_) - | ty::ConstKind::Value(_, _) + | ty::ConstKind::Value(_) | ty::ConstKind::Unevaluated(..) | ty::ConstKind::Expr(..) | ty::ConstKind::Error(_) => ct.super_fold_with(self), diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 283ebdfa236..c2513a1af19 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -26,7 +26,6 @@ use rustc_macros::extension; pub use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::bug; use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues}; -use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::select; pub use rustc_middle::ty::IntVarValue; @@ -46,6 +45,7 @@ use tracing::{debug, instrument}; use type_variable::TypeVariableOrigin; use crate::infer::region_constraints::UndoLog; +use crate::infer::unify_key::{ConstVariableOrigin, ConstVariableValue, ConstVidKey}; use crate::traits::{ self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine, }; @@ -64,6 +64,7 @@ pub mod relate; pub mod resolve; pub(crate) mod snapshot; mod type_variable; +mod unify_key; /// `InferOk<'tcx, ()>` is used a lot. It may seem like a useless wrapper /// around `PredicateObligations<'tcx>`, but it has one important property: @@ -1055,7 +1056,7 @@ impl<'tcx> InferCtxt<'tcx> { | ty::ConstKind::Bound(_, _) | ty::ConstKind::Placeholder(_) | ty::ConstKind::Unevaluated(_) - | ty::ConstKind::Value(_, _) + | ty::ConstKind::Value(_) | ty::ConstKind::Error(_) | ty::ConstKind::Expr(_) => ct, } diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 6496f38269a..57555db37ab 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -8,7 +8,6 @@ use rustc_data_structures::undo_log::UndoLogs; use rustc_data_structures::unify as ut; use rustc_index::IndexVec; use rustc_macros::{TypeFoldable, TypeVisitable}; -use rustc_middle::infer::unify_key::{RegionVariableValue, RegionVidKey}; use rustc_middle::ty::{self, ReBound, ReStatic, ReVar, Region, RegionVid, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use tracing::{debug, instrument}; @@ -17,6 +16,7 @@ use self::CombineMapType::*; use self::UndoLog::*; use super::{MiscVariable, RegionVariableOrigin, Rollback, SubregionOrigin}; use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, Snapshot}; +use crate::infer::unify_key::{RegionVariableValue, RegionVidKey}; mod leak_check; diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 21c47967ead..ce2d07f4af9 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -4,7 +4,6 @@ use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::DefId; use rustc_middle::bug; -use rustc_middle::infer::unify_key::ConstVariableValue; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::visit::MaxUniverse; use rustc_middle::ty::{ @@ -18,6 +17,7 @@ use super::{ PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation, }; use crate::infer::type_variable::TypeVariableValue; +use crate::infer::unify_key::ConstVariableValue; use crate::infer::{InferCtxt, RegionVariableOrigin, relate}; impl<'tcx> InferCtxt<'tcx> { diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs index 394e07a81e7..3a47b13665d 100644 --- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs +++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs @@ -1,7 +1,6 @@ use std::ops::Range; use rustc_data_structures::{snapshot_vec as sv, unify as ut}; -use rustc_middle::infer::unify_key::{ConstVariableValue, ConstVidKey}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid}; use rustc_type_ir::visit::TypeVisitableExt; @@ -10,6 +9,7 @@ use ut::UnifyKey; use super::VariableLengths; use crate::infer::type_variable::TypeVariableOrigin; +use crate::infer::unify_key::{ConstVariableValue, ConstVidKey}; use crate::infer::{ConstVariableOrigin, InferCtxt, RegionVariableOrigin, UnificationTable}; fn vars_since_snapshot<'tcx, T>( diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs index 713389f4618..ba7d8f588e6 100644 --- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs +++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs @@ -2,10 +2,10 @@ use std::marker::PhantomData; use rustc_data_structures::undo_log::{Rollback, UndoLogs}; use rustc_data_structures::{snapshot_vec as sv, unify as ut}; -use rustc_middle::infer::unify_key::{ConstVidKey, RegionVidKey}; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey}; use tracing::debug; +use crate::infer::unify_key::{ConstVidKey, RegionVidKey}; use crate::infer::{InferCtxtInner, region_constraints, type_variable}; use crate::traits; diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_infer/src/infer/unify_key.rs index 7f9211043d6..3ba8aea1d3a 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_infer/src/infer/unify_key.rs @@ -2,23 +2,18 @@ use std::cmp; use std::marker::PhantomData; use rustc_data_structures::unify::{NoError, UnifyKey, UnifyValue}; +use rustc_middle::{bug, ty}; use rustc_span::Span; use rustc_span::def_id::DefId; -use crate::ty::{self, Ty, TyCtxt}; - -pub trait ToType { - fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; -} - #[derive(Copy, Clone, Debug)] -pub enum RegionVariableValue<'tcx> { +pub(crate) enum RegionVariableValue<'tcx> { Known { value: ty::Region<'tcx> }, Unknown { universe: ty::UniverseIndex }, } #[derive(PartialEq, Copy, Clone, Debug)] -pub struct RegionVidKey<'tcx> { +pub(crate) struct RegionVidKey<'tcx> { pub vid: ty::RegionVid, pub phantom: PhantomData<RegionVariableValue<'tcx>>, } @@ -44,7 +39,8 @@ impl<'tcx> UnifyKey for RegionVidKey<'tcx> { } } -pub struct RegionUnificationError; +pub(crate) struct RegionUnificationError; + impl<'tcx> UnifyValue for RegionVariableValue<'tcx> { type Error = RegionUnificationError; @@ -100,7 +96,7 @@ pub struct ConstVariableOrigin { } #[derive(Copy, Clone, Debug)] -pub enum ConstVariableValue<'tcx> { +pub(crate) enum ConstVariableValue<'tcx> { Known { value: ty::Const<'tcx> }, Unknown { origin: ConstVariableOrigin, universe: ty::UniverseIndex }, } @@ -108,7 +104,7 @@ pub enum ConstVariableValue<'tcx> { impl<'tcx> ConstVariableValue<'tcx> { /// If this value is known, returns the const it is known to be. /// Otherwise, `None`. - pub fn known(&self) -> Option<ty::Const<'tcx>> { + pub(crate) fn known(&self) -> Option<ty::Const<'tcx>> { match *self { ConstVariableValue::Unknown { .. } => None, ConstVariableValue::Known { value } => Some(value), @@ -117,7 +113,7 @@ impl<'tcx> ConstVariableValue<'tcx> { } #[derive(PartialEq, Copy, Clone, Debug)] -pub struct ConstVidKey<'tcx> { +pub(crate) struct ConstVidKey<'tcx> { pub vid: ty::ConstVid, pub phantom: PhantomData<ty::Const<'tcx>>, } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 241bc35857a..8a121c5a865 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -26,7 +26,6 @@ use rustc_parse::{ }; use rustc_passes::{abi_test, input_stats, layout_test}; use rustc_resolve::Resolver; -use rustc_session::code_stats::VTableSizeInfo; use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType}; use rustc_session::cstore::Untracked; use rustc_session::output::{collect_crate_types, filename_for_input, find_crate_name}; @@ -269,6 +268,7 @@ fn configure_and_expand( resolver.resolve_crate(&krate); + CStore::from_tcx(tcx).report_incompatible_target_modifiers(tcx, &krate); krate } @@ -833,20 +833,20 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { sess.time("misc_checking_1", || { parallel!( { - sess.time("looking_for_entry_point", || tcx.ensure().entry_fn(())); + sess.time("looking_for_entry_point", || tcx.ensure_ok().entry_fn(())); sess.time("looking_for_derive_registrar", || { - tcx.ensure().proc_macro_decls_static(()) + tcx.ensure_ok().proc_macro_decls_static(()) }); CStore::from_tcx(tcx).report_unused_deps(tcx); }, { tcx.hir().par_for_each_module(|module| { - tcx.ensure().check_mod_loops(module); - tcx.ensure().check_mod_attrs(module); - tcx.ensure().check_mod_naked_functions(module); - tcx.ensure().check_mod_unstable_api_usage(module); + tcx.ensure_ok().check_mod_loops(module); + tcx.ensure_ok().check_mod_attrs(module); + tcx.ensure_ok().check_mod_naked_functions(module); + tcx.ensure_ok().check_mod_unstable_api_usage(module); }); }, { @@ -859,8 +859,8 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { // since they might not otherwise get called. // This marks the corresponding crate-level attributes // as used, and ensures that their values are valid. - tcx.ensure().limits(()); - tcx.ensure().stability_index(()); + tcx.ensure_ok().limits(()); + tcx.ensure_ok().stability_index(()); } ); }); @@ -869,7 +869,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { sess.time("MIR_coroutine_by_move_body", || { tcx.hir().par_body_owners(|def_id| { if tcx.needs_coroutine_by_move_body_def_id(def_id.to_def_id()) { - tcx.ensure_with_value().coroutine_by_move_body_def_id(def_id); + tcx.ensure_done().coroutine_by_move_body_def_id(def_id); } }); }); @@ -884,13 +884,13 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { tcx.hir().par_body_owners(|def_id| { // Run unsafety check because it's responsible for stealing and // deallocating THIR. - tcx.ensure().check_unsafety(def_id); - tcx.ensure().mir_borrowck(def_id) + tcx.ensure_ok().check_unsafety(def_id); + tcx.ensure_ok().mir_borrowck(def_id) }); }); sess.time("MIR_effect_checking", || { tcx.hir().par_body_owners(|def_id| { - tcx.ensure().has_ffi_unwind_calls(def_id); + tcx.ensure_ok().has_ffi_unwind_calls(def_id); // If we need to codegen, ensure that we emit all errors from // `mir_drops_elaborated_and_const_checked` now, to avoid discovering @@ -898,15 +898,15 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { if tcx.sess.opts.output_types.should_codegen() || tcx.hir().body_const_context(def_id).is_some() { - tcx.ensure().mir_drops_elaborated_and_const_checked(def_id); + tcx.ensure_ok().mir_drops_elaborated_and_const_checked(def_id); } }); }); sess.time("coroutine_obligations", || { tcx.hir().par_body_owners(|def_id| { if tcx.is_coroutine(def_id.to_def_id()) { - tcx.ensure().mir_coroutine_witnesses(def_id); - tcx.ensure().check_coroutine_obligations( + tcx.ensure_ok().mir_coroutine_witnesses(def_id); + tcx.ensure_ok().check_coroutine_obligations( tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(), ); } @@ -951,15 +951,16 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) { sess.time("misc_checking_3", || { parallel!( { - tcx.ensure().effective_visibilities(()); + tcx.ensure_ok().effective_visibilities(()); parallel!( { - tcx.ensure().check_private_in_public(()); + tcx.ensure_ok().check_private_in_public(()); }, { - tcx.hir() - .par_for_each_module(|module| tcx.ensure().check_mod_deathness(module)); + tcx.hir().par_for_each_module(|module| { + tcx.ensure_ok().check_mod_deathness(module) + }); }, { sess.time("lint_checking", || { @@ -967,14 +968,14 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) { }); }, { - tcx.ensure().clashing_extern_declarations(()); + tcx.ensure_ok().clashing_extern_declarations(()); } ); }, { sess.time("privacy_checking_modules", || { tcx.hir().par_for_each_module(|module| { - tcx.ensure().check_mod_privacy(module); + tcx.ensure_ok().check_mod_privacy(module); }); }); } @@ -982,97 +983,13 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) { // This check has to be run after all lints are done processing. We don't // define a lint filter, as all lint checks should have finished at this point. - sess.time("check_lint_expectations", || tcx.ensure().check_expectations(None)); + sess.time("check_lint_expectations", || tcx.ensure_ok().check_expectations(None)); // This query is only invoked normally if a diagnostic is emitted that needs any // diagnostic item. If the crate compiles without checking any diagnostic items, // we will fail to emit overlap diagnostics. Thus we invoke it here unconditionally. let _ = tcx.all_diagnostic_items(()); }); - - if sess.opts.unstable_opts.print_vtable_sizes { - let traits = tcx.traits(LOCAL_CRATE); - - for &tr in traits { - if !tcx.is_dyn_compatible(tr) { - continue; - } - - let name = ty::print::with_no_trimmed_paths!(tcx.def_path_str(tr)); - - let mut first_dsa = true; - - // Number of vtable entries, if we didn't have upcasting - let mut entries_ignoring_upcasting = 0; - // Number of vtable entries needed solely for upcasting - let mut entries_for_upcasting = 0; - - let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, tr)); - - // A slightly edited version of the code in - // `rustc_trait_selection::traits::vtable::vtable_entries`, that works without self - // type and just counts number of entries. - // - // Note that this is technically wrong, for traits which have associated types in - // supertraits: - // - // trait A: AsRef<Self::T> + AsRef<()> { type T; } - // - // Without self type we can't normalize `Self::T`, so we can't know if `AsRef<Self::T>` - // and `AsRef<()>` are the same trait, thus we assume that those are different, and - // potentially over-estimate how many vtable entries there are. - // - // Similarly this is wrong for traits that have methods with possibly-impossible bounds. - // For example: - // - // trait B<T> { fn f(&self) where T: Copy; } - // - // Here `dyn B<u8>` will have 4 entries, while `dyn B<String>` will only have 3. - // However, since we don't know `T`, we can't know if `T: Copy` holds or not, - // thus we lean on the bigger side and say it has 4 entries. - traits::vtable::prepare_vtable_segments(tcx, trait_ref, |segment| { - match segment { - traits::vtable::VtblSegment::MetadataDSA => { - // If this is the first dsa, it would be included either way, - // otherwise it's needed for upcasting - if std::mem::take(&mut first_dsa) { - entries_ignoring_upcasting += 3; - } else { - entries_for_upcasting += 3; - } - } - - traits::vtable::VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { - // Lookup the shape of vtable for the trait. - let own_existential_entries = - tcx.own_existential_vtable_entries(trait_ref.def_id()); - - // The original code here ignores the method if its predicates are - // impossible. We can't really do that as, for example, all not trivial - // bounds on generic parameters are impossible (since we don't know the - // parameters...), see the comment above. - entries_ignoring_upcasting += own_existential_entries.len(); - - if emit_vptr { - entries_for_upcasting += 1; - } - } - } - - std::ops::ControlFlow::Continue::<std::convert::Infallible>(()) - }); - - sess.code_stats.record_vtable_size(tr, &name, VTableSizeInfo { - trait_name: name.clone(), - entries: entries_ignoring_upcasting + entries_for_upcasting, - entries_ignoring_upcasting, - entries_for_upcasting, - upcasting_cost_percent: entries_for_upcasting as f64 - / entries_ignoring_upcasting as f64 - * 100., - }) - } - } } /// Check for the `#[rustc_error]` annotation, which forces an error in codegen. This is used @@ -1091,7 +1008,7 @@ fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) { ) }) => { - tcx.ensure().trigger_delayed_bug(def_id); + tcx.ensure_ok().trigger_delayed_bug(def_id); } // Bare `#[rustc_error]`. @@ -1153,12 +1070,6 @@ pub(crate) fn start_codegen<'tcx>( tcx.sess.code_stats.print_type_sizes(); } - if tcx.sess.opts.unstable_opts.print_vtable_sizes { - let crate_name = tcx.crate_name(LOCAL_CRATE); - - tcx.sess.code_stats.print_vtable_sizes(crate_name); - } - codegen } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 9495030f124..fb69dd54811 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -8,12 +8,12 @@ use rustc_data_structures::profiling::TimePassesFormat; use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::{ColorConfig, registry}; use rustc_session::config::{ - BranchProtection, CFGuard, Cfg, CollapseMacroDebuginfo, CoverageLevel, CoverageOptions, - DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs, - FmtDebug, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, - LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, MirIncludeSpans, NextSolverConfig, - OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, - PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, + AutoDiff, BranchProtection, CFGuard, Cfg, CollapseMacroDebuginfo, CoverageLevel, + CoverageOptions, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, + Externs, FmtDebug, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, + InstrumentXRay, LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, MirIncludeSpans, + NextSolverConfig, OomStrategy, Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, + Passes, PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, build_configuration, build_session_options, rustc_optgroups, }; @@ -760,6 +760,7 @@ fn test_unstable_options_tracking_hash() { tracked!(allow_features, Some(vec![String::from("lang_items")])); tracked!(always_encode_mir, true); tracked!(assume_incomplete_release, true); + tracked!(autodiff, vec![AutoDiff::Print]); tracked!(binary_dep_depinfo, true); tracked!(box_noalias, false); tracked!( diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index e8a4e9a84c4..e2bafbed6e1 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -29,7 +29,6 @@ use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_hir::intravisit::FnKind as HirFnKind; use rustc_hir::{Body, FnDecl, GenericParamKind, PatKind, PredicateOrigin}; use rustc_middle::bug; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Upcast, VariantDef}; @@ -2029,7 +2028,7 @@ impl ExplicitOutlivesRequirements { } let span = bound.span().find_ancestor_inside(predicate_span)?; - if in_external_macro(tcx.sess, span) { + if span.in_external_macro(tcx.sess.source_map()) { return None; } diff --git a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs index da6dd8161ee..946dbc34f71 100644 --- a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs +++ b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs @@ -135,7 +135,7 @@ pub(super) fn unexpected_cfg_name( }; let is_from_cargo = rustc_session::utils::was_invoked_from_cargo(); - let is_from_external_macro = rustc_middle::lint::in_external_macro(sess, name_span); + let is_from_external_macro = name_span.in_external_macro(sess.source_map()); let mut is_feature_cfg = name == sym::feature; let code_sugg = if is_feature_cfg && is_from_cargo { @@ -281,7 +281,7 @@ pub(super) fn unexpected_cfg_value( .collect(); let is_from_cargo = rustc_session::utils::was_invoked_from_cargo(); - let is_from_external_macro = rustc_middle::lint::in_external_macro(sess, name_span); + let is_from_external_macro = name_span.in_external_macro(sess.source_map()); // Show the full list if all possible values for a given name, but don't do it // for names as the possibilities could be very long diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index c6d7b839e19..826ecc22c24 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -458,7 +458,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) { || { tcx.sess.time("module_lints", || { // Run per-module lints - tcx.hir().par_for_each_module(|module| tcx.ensure().lint_mod(module)); + tcx.hir().par_for_each_module(|module| tcx.ensure_ok().lint_mod(module)); }); }, ); diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index 9fde35f82d8..35db8632625 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -37,7 +37,7 @@ declare_lint_pass!(MultipleSupertraitUpcastable => [MULTIPLE_SUPERTRAIT_UPCASTAB impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { let def_id = item.owner_id.to_def_id(); - // NOTE(nbdd0121): use `object_safety_violations` instead of `is_dyn_compatible` because + // NOTE(nbdd0121): use `dyn_compatibility_violations` instead of `is_dyn_compatible` because // the latter will report `where_clause_object_safety` lint. if let hir::ItemKind::Trait(_, _, _, _, _) = item.kind && cx.tcx.is_dyn_compatible(def_id) diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 6f047b4da49..648d0675627 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -2,7 +2,6 @@ use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir::{self as hir, LangItem}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_middle::lint::in_external_macro; use rustc_middle::{bug, ty}; use rustc_parse_format::{ParseMode, Parser, Piece}; use rustc_session::lint::FutureIncompatibilityReason; @@ -100,7 +99,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc let (span, panic, symbol) = panic_call(cx, f); - if in_external_macro(cx.sess(), span) { + if span.in_external_macro(cx.sess().source_map()) { // Nothing that can be done about it in the current crate. return; } @@ -229,14 +228,15 @@ fn check_panic_str<'tcx>( let (span, _, _) = panic_call(cx, f); - if in_external_macro(cx.sess(), span) && in_external_macro(cx.sess(), arg.span) { + let sm = cx.sess().source_map(); + if span.in_external_macro(sm) && arg.span.in_external_macro(sm) { // Nothing that can be done about it in the current crate. return; } let fmt_span = arg.span.source_callsite(); - let (snippet, style) = match cx.sess().psess.source_map().span_to_snippet(fmt_span) { + let (snippet, style) = match sm.span_to_snippet(fmt_span) { Ok(snippet) => { // Count the number of `#`s between the `r` and `"`. let style = snippet.strip_prefix('r').and_then(|s| s.find('"')); @@ -283,7 +283,7 @@ fn check_panic_str<'tcx>( /// Given the span of `some_macro!(args);`, gives the span of `(` and `)`, /// and the type of (opening) delimiter used. fn find_delimiters(cx: &LateContext<'_>, span: Span) -> Option<(Span, Span, char)> { - let snippet = cx.sess().psess.source_map().span_to_snippet(span).ok()?; + let snippet = cx.sess().source_map().span_to_snippet(span).ok()?; let (open, open_ch) = snippet.char_indices().find(|&(_, c)| "([{".contains(c))?; let close = snippet.rfind(|c| ")]}".contains(c))?; Some(( diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 3f1e98556ef..7ffe4e4e490 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -42,6 +42,23 @@ macro_rules! pluralize { }; } +/// Grammatical tool for displaying messages to end users in a nice form. +/// +/// Take a list of items and a function to turn those items into a `String`, and output a display +/// friendly comma separated list of those items. +// FIXME(estebank): this needs to be changed to go through the translation machinery. +pub fn listify<T>(list: &[T], fmt: impl Fn(&T) -> String) -> Option<String> { + Some(match list { + [only] => fmt(&only), + [others @ .., last] => format!( + "{} and {}", + others.iter().map(|i| fmt(i)).collect::<Vec<_>>().join(", "), + fmt(&last), + ), + [] => return None, + }) +} + /// Indicates the confidence in the correctness of a suggestion. /// /// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 35186778671..7ff316ba83a 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -319,7 +319,11 @@ static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) { case LLVMRustAttributeKind::NoAlias: return Attribute::NoAlias; case LLVMRustAttributeKind::NoCapture: +#if LLVM_VERSION_GE(21, 0) + report_fatal_error("NoCapture doesn't exist in LLVM 21"); +#else return Attribute::NoCapture; +#endif case LLVMRustAttributeKind::NoCfCheck: return Attribute::NoCfCheck; case LLVMRustAttributeKind::NoInline: @@ -431,6 +435,12 @@ extern "C" void LLVMRustEraseInstFromParent(LLVMValueRef Instr) { extern "C" LLVMAttributeRef LLVMRustCreateAttrNoValue(LLVMContextRef C, LLVMRustAttributeKind RustAttr) { +#if LLVM_VERSION_GE(21, 0) + // LLVM 21 replaced the NoCapture attribute with Captures(none). + if (RustAttr == LLVMRustAttributeKind::NoCapture) { + return wrap(Attribute::getWithCaptureInfo(*unwrap(C), CaptureInfo::none())); + } +#endif return wrap(Attribute::get(*unwrap(C), fromRust(RustAttr))); } @@ -667,8 +677,6 @@ extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints, unwrap<FunctionType>(Ty), StringRef(Constraints, ConstraintsLen))); } -typedef DIBuilder *LLVMRustDIBuilderRef; - template <typename DIT> DIT *unwrapDIPtr(LLVMMetadataRef Ref) { return (DIT *)(Ref ? unwrap<MDNode>(Ref) : nullptr); } @@ -677,12 +685,6 @@ template <typename DIT> DIT *unwrapDIPtr(LLVMMetadataRef Ref) { #define DIArray DINodeArray #define unwrapDI unwrapDIPtr -// FIXME(Zalathar): This is a temporary typedef to avoid churning dozens of -// bindings that are going to be deleted and replaced with their LLVM-C -// equivalents, as part of #134009. After that happens, the remaining bindings -// can be adjusted to use `LLVMDIFlags` instead of relying on this typedef. -typedef LLVMDIFlags LLVMRustDIFlags; - // Statically assert that `LLVMDIFlags` (C) and `DIFlags` (C++) have the same // layout, at least for the flags we know about. This isn't guaranteed, but is // likely to remain true, and as long as it is true it makes conversions easy. @@ -955,7 +957,8 @@ extern "C" LLVMValueRef LLVMRustGetLastInstruction(LLVMBasicBlockRef BB) { return nullptr; } -extern "C" void LLVMRustEraseInstBefore(LLVMBasicBlockRef bb, LLVMValueRef I) { +extern "C" void LLVMRustEraseInstUntilInclusive(LLVMBasicBlockRef bb, + LLVMValueRef I) { auto &BB = *unwrap(bb); auto &Inst = *unwrap<Instruction>(I); auto It = BB.begin(); @@ -963,8 +966,6 @@ extern "C" void LLVMRustEraseInstBefore(LLVMBasicBlockRef bb, LLVMValueRef I) { ++It; // Make sure we found the Instruction. assert(It != BB.end()); - // We don't want to erase the instruction itself. - It--; // Delete in rev order to ensure no dangling references. while (It != BB.begin()) { auto Prev = std::prev(It); @@ -994,34 +995,34 @@ extern "C" void LLVMRustGlobalAddMetadata(LLVMValueRef Global, unsigned Kind, unwrap<GlobalObject>(Global)->addMetadata(Kind, *unwrap<MDNode>(MD)); } -extern "C" LLVMRustDIBuilderRef LLVMRustDIBuilderCreate(LLVMModuleRef M) { - return new DIBuilder(*unwrap(M)); +extern "C" LLVMDIBuilderRef LLVMRustDIBuilderCreate(LLVMModuleRef M) { + return wrap(new DIBuilder(*unwrap(M))); } -extern "C" void LLVMRustDIBuilderDispose(LLVMRustDIBuilderRef Builder) { - delete Builder; +extern "C" void LLVMRustDIBuilderDispose(LLVMDIBuilderRef Builder) { + delete unwrap(Builder); } -extern "C" void LLVMRustDIBuilderFinalize(LLVMRustDIBuilderRef Builder) { - Builder->finalize(); +extern "C" void LLVMRustDIBuilderFinalize(LLVMDIBuilderRef Builder) { + unwrap(Builder)->finalize(); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateCompileUnit( - LLVMRustDIBuilderRef Builder, unsigned Lang, LLVMMetadataRef FileRef, + LLVMDIBuilderRef Builder, unsigned Lang, LLVMMetadataRef FileRef, const char *Producer, size_t ProducerLen, bool isOptimized, const char *Flags, unsigned RuntimeVer, const char *SplitName, size_t SplitNameLen, LLVMRustDebugEmissionKind Kind, uint64_t DWOId, bool SplitDebugInlining, LLVMRustDebugNameTableKind TableKind) { auto *File = unwrapDI<DIFile>(FileRef); - return wrap(Builder->createCompileUnit( + return wrap(unwrap(Builder)->createCompileUnit( Lang, File, StringRef(Producer, ProducerLen), isOptimized, Flags, RuntimeVer, StringRef(SplitName, SplitNameLen), fromRust(Kind), DWOId, SplitDebugInlining, false, fromRust(TableKind))); } extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateFile(LLVMRustDIBuilderRef Builder, const char *Filename, +LLVMRustDIBuilderCreateFile(LLVMDIBuilderRef Builder, const char *Filename, size_t FilenameLen, const char *Directory, size_t DirectoryLen, LLVMRustChecksumKind CSKind, const char *Checksum, size_t ChecksumLen, @@ -1034,29 +1035,29 @@ LLVMRustDIBuilderCreateFile(LLVMRustDIBuilderRef Builder, const char *Filename, std::optional<StringRef> oSource{}; if (Source) oSource = StringRef(Source, SourceLen); - return wrap(Builder->createFile(StringRef(Filename, FilenameLen), - StringRef(Directory, DirectoryLen), CSInfo, - oSource)); + return wrap(unwrap(Builder)->createFile(StringRef(Filename, FilenameLen), + StringRef(Directory, DirectoryLen), + CSInfo, oSource)); } extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateSubroutineType(LLVMRustDIBuilderRef Builder, +LLVMRustDIBuilderCreateSubroutineType(LLVMDIBuilderRef Builder, LLVMMetadataRef ParameterTypes) { - return wrap(Builder->createSubroutineType( + return wrap(unwrap(Builder)->createSubroutineType( DITypeRefArray(unwrap<MDTuple>(ParameterTypes)))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, const char *LinkageName, size_t LinkageNameLen, LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, - unsigned ScopeLine, LLVMRustDIFlags Flags, LLVMRustDISPFlags SPFlags, + unsigned ScopeLine, LLVMDIFlags Flags, LLVMRustDISPFlags SPFlags, LLVMValueRef MaybeFn, LLVMMetadataRef TParam, LLVMMetadataRef Decl) { DITemplateParameterArray TParams = DITemplateParameterArray(unwrap<MDTuple>(TParam)); DISubprogram::DISPFlags llvmSPFlags = fromRust(SPFlags); DINode::DIFlags llvmFlags = fromRust(Flags); - DISubprogram *Sub = Builder->createFunction( + DISubprogram *Sub = unwrap(Builder)->createFunction( unwrapDI<DIScope>(Scope), StringRef(Name, NameLen), StringRef(LinkageName, LinkageNameLen), unwrapDI<DIFile>(File), LineNo, unwrapDI<DISubroutineType>(Ty), ScopeLine, llvmFlags, llvmSPFlags, @@ -1067,15 +1068,15 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction( } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMethod( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, const char *LinkageName, size_t LinkageNameLen, LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, - LLVMRustDIFlags Flags, LLVMRustDISPFlags SPFlags, LLVMMetadataRef TParam) { + LLVMDIFlags Flags, LLVMRustDISPFlags SPFlags, LLVMMetadataRef TParam) { DITemplateParameterArray TParams = DITemplateParameterArray(unwrap<MDTuple>(TParam)); DISubprogram::DISPFlags llvmSPFlags = fromRust(SPFlags); DINode::DIFlags llvmFlags = fromRust(Flags); - DISubprogram *Sub = Builder->createMethod( + DISubprogram *Sub = unwrap(Builder)->createMethod( unwrapDI<DIScope>(Scope), StringRef(Name, NameLen), StringRef(LinkageName, LinkageNameLen), unwrapDI<DIFile>(File), LineNo, unwrapDI<DISubroutineType>(Ty), 0, 0, @@ -1085,39 +1086,39 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMethod( } extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateBasicType(LLVMRustDIBuilderRef Builder, const char *Name, +LLVMRustDIBuilderCreateBasicType(LLVMDIBuilderRef Builder, const char *Name, size_t NameLen, uint64_t SizeInBits, unsigned Encoding) { - return wrap( - Builder->createBasicType(StringRef(Name, NameLen), SizeInBits, Encoding)); + return wrap(unwrap(Builder)->createBasicType(StringRef(Name, NameLen), + SizeInBits, Encoding)); } extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateTypedef(LLVMRustDIBuilderRef Builder, - LLVMMetadataRef Type, const char *Name, - size_t NameLen, LLVMMetadataRef File, - unsigned LineNo, LLVMMetadataRef Scope) { - return wrap(Builder->createTypedef( +LLVMRustDIBuilderCreateTypedef(LLVMDIBuilderRef Builder, LLVMMetadataRef Type, + const char *Name, size_t NameLen, + LLVMMetadataRef File, unsigned LineNo, + LLVMMetadataRef Scope) { + return wrap(unwrap(Builder)->createTypedef( unwrap<DIType>(Type), StringRef(Name, NameLen), unwrap<DIFile>(File), LineNo, unwrapDIPtr<DIScope>(Scope))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreatePointerType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef PointeeTy, - uint64_t SizeInBits, uint32_t AlignInBits, unsigned AddressSpace, - const char *Name, size_t NameLen) { - return wrap(Builder->createPointerType(unwrapDI<DIType>(PointeeTy), - SizeInBits, AlignInBits, AddressSpace, - StringRef(Name, NameLen))); + LLVMDIBuilderRef Builder, LLVMMetadataRef PointeeTy, uint64_t SizeInBits, + uint32_t AlignInBits, unsigned AddressSpace, const char *Name, + size_t NameLen) { + return wrap(unwrap(Builder)->createPointerType( + unwrapDI<DIType>(PointeeTy), SizeInBits, AlignInBits, AddressSpace, + StringRef(Name, NameLen))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStructType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, - uint64_t SizeInBits, uint32_t AlignInBits, LLVMRustDIFlags Flags, + uint64_t SizeInBits, uint32_t AlignInBits, LLVMDIFlags Flags, LLVMMetadataRef DerivedFrom, LLVMMetadataRef Elements, unsigned RunTimeLang, LLVMMetadataRef VTableHolder, const char *UniqueId, size_t UniqueIdLen) { - return wrap(Builder->createStructType( + return wrap(unwrap(Builder)->createStructType( unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIFile>(File), LineNumber, SizeInBits, AlignInBits, fromRust(Flags), unwrapDI<DIType>(DerivedFrom), @@ -1126,12 +1127,12 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStructType( } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantPart( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, - uint64_t SizeInBits, uint32_t AlignInBits, LLVMRustDIFlags Flags, + uint64_t SizeInBits, uint32_t AlignInBits, LLVMDIFlags Flags, LLVMMetadataRef Discriminator, LLVMMetadataRef Elements, const char *UniqueId, size_t UniqueIdLen) { - return wrap(Builder->createVariantPart( + return wrap(unwrap(Builder)->createVariantPart( unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIFile>(File), LineNumber, SizeInBits, AlignInBits, fromRust(Flags), unwrapDI<DIDerivedType>(Discriminator), @@ -1140,36 +1141,36 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantPart( } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMemberType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits, - uint32_t AlignInBits, uint64_t OffsetInBits, LLVMRustDIFlags Flags, + uint32_t AlignInBits, uint64_t OffsetInBits, LLVMDIFlags Flags, LLVMMetadataRef Ty) { - return wrap(Builder->createMemberType( + return wrap(unwrap(Builder)->createMemberType( unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIFile>(File), LineNo, SizeInBits, AlignInBits, OffsetInBits, fromRust(Flags), unwrapDI<DIType>(Ty))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, LLVMValueRef Discriminant, - LLVMRustDIFlags Flags, LLVMMetadataRef Ty) { + LLVMDIFlags Flags, LLVMMetadataRef Ty) { llvm::ConstantInt *D = nullptr; if (Discriminant) { D = unwrap<llvm::ConstantInt>(Discriminant); } - return wrap(Builder->createVariantMemberType( + return wrap(unwrap(Builder)->createVariantMemberType( unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIFile>(File), LineNo, SizeInBits, AlignInBits, OffsetInBits, D, fromRust(Flags), unwrapDI<DIType>(Ty))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticMemberType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, - LLVMRustDIFlags Flags, LLVMValueRef val, uint32_t AlignInBits) { - return wrap(Builder->createStaticMemberType( + LLVMDIFlags Flags, LLVMValueRef val, uint32_t AlignInBits) { + return wrap(unwrap(Builder)->createStaticMemberType( unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), fromRust(Flags), unwrap<llvm::ConstantInt>(val), llvm::dwarf::DW_TAG_member, AlignInBits)); @@ -1183,21 +1184,21 @@ LLVMRustDIBuilderCreateQualifiedType(LLVMDIBuilderRef Builder, unsigned Tag, } extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateLexicalBlock(LLVMRustDIBuilderRef Builder, +LLVMRustDIBuilderCreateLexicalBlock(LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, LLVMMetadataRef File, unsigned Line, unsigned Col) { - return wrap(Builder->createLexicalBlock(unwrapDI<DIDescriptor>(Scope), - unwrapDI<DIFile>(File), Line, Col)); + return wrap(unwrap(Builder)->createLexicalBlock( + unwrapDI<DIDescriptor>(Scope), unwrapDI<DIFile>(File), Line, Col)); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateLexicalBlockFile( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, LLVMMetadataRef File) { - return wrap(Builder->createLexicalBlockFile(unwrapDI<DIDescriptor>(Scope), - unwrapDI<DIFile>(File))); + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, LLVMMetadataRef File) { + return wrap(unwrap(Builder)->createLexicalBlockFile( + unwrapDI<DIDescriptor>(Scope), unwrapDI<DIFile>(File))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Context, const char *Name, + LLVMDIBuilderRef Builder, LLVMMetadataRef Context, const char *Name, size_t NameLen, const char *LinkageName, size_t LinkageNameLen, LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, bool IsLocalToUnit, LLVMValueRef V, LLVMMetadataRef Decl = nullptr, @@ -1206,16 +1207,16 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable( llvm::DIExpression *InitExpr = nullptr; if (llvm::ConstantInt *IntVal = llvm::dyn_cast<llvm::ConstantInt>(InitVal)) { - InitExpr = Builder->createConstantValueExpression( + InitExpr = unwrap(Builder)->createConstantValueExpression( IntVal->getValue().getSExtValue()); } else if (llvm::ConstantFP *FPVal = llvm::dyn_cast<llvm::ConstantFP>(InitVal)) { - InitExpr = Builder->createConstantValueExpression( + InitExpr = unwrap(Builder)->createConstantValueExpression( FPVal->getValueAPF().bitcastToAPInt().getZExtValue()); } llvm::DIGlobalVariableExpression *VarExpr = - Builder->createGlobalVariableExpression( + unwrap(Builder)->createGlobalVariableExpression( unwrapDI<DIDescriptor>(Context), StringRef(Name, NameLen), StringRef(LinkageName, LinkageNameLen), unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), IsLocalToUnit, @@ -1228,17 +1229,17 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable( } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable( - LLVMRustDIBuilderRef Builder, unsigned Tag, LLVMMetadataRef Scope, + LLVMDIBuilderRef Builder, unsigned Tag, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo, - LLVMMetadataRef Ty, bool AlwaysPreserve, LLVMRustDIFlags Flags, - unsigned ArgNo, uint32_t AlignInBits) { + LLVMMetadataRef Ty, bool AlwaysPreserve, LLVMDIFlags Flags, unsigned ArgNo, + uint32_t AlignInBits) { if (Tag == 0x100) { // DW_TAG_auto_variable - return wrap(Builder->createAutoVariable( + return wrap(unwrap(Builder)->createAutoVariable( unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), AlwaysPreserve, fromRust(Flags), AlignInBits)); } else { - return wrap(Builder->createParameterVariable( + return wrap(unwrap(Builder)->createParameterVariable( unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), ArgNo, unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), AlwaysPreserve, fromRust(Flags))); @@ -1246,53 +1247,56 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable( } extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateArrayType(LLVMRustDIBuilderRef Builder, uint64_t Size, +LLVMRustDIBuilderCreateArrayType(LLVMDIBuilderRef Builder, uint64_t Size, uint32_t AlignInBits, LLVMMetadataRef Ty, LLVMMetadataRef Subscripts) { - return wrap( - Builder->createArrayType(Size, AlignInBits, unwrapDI<DIType>(Ty), - DINodeArray(unwrapDI<MDTuple>(Subscripts)))); + return wrap(unwrap(Builder)->createArrayType( + Size, AlignInBits, unwrapDI<DIType>(Ty), + DINodeArray(unwrapDI<MDTuple>(Subscripts)))); } extern "C" LLVMMetadataRef -LLVMRustDIBuilderGetOrCreateSubrange(LLVMRustDIBuilderRef Builder, int64_t Lo, +LLVMRustDIBuilderGetOrCreateSubrange(LLVMDIBuilderRef Builder, int64_t Lo, int64_t Count) { - return wrap(Builder->getOrCreateSubrange(Lo, Count)); + return wrap(unwrap(Builder)->getOrCreateSubrange(Lo, Count)); } extern "C" LLVMMetadataRef -LLVMRustDIBuilderGetOrCreateArray(LLVMRustDIBuilderRef Builder, +LLVMRustDIBuilderGetOrCreateArray(LLVMDIBuilderRef Builder, LLVMMetadataRef *Ptr, unsigned Count) { Metadata **DataValue = unwrap(Ptr); - return wrap( - Builder->getOrCreateArray(ArrayRef<Metadata *>(DataValue, Count)).get()); + return wrap(unwrap(Builder) + ->getOrCreateArray(ArrayRef<Metadata *>(DataValue, Count)) + .get()); } -extern "C" void LLVMRustDIBuilderInsertDeclareAtEnd( - LLVMRustDIBuilderRef Builder, LLVMValueRef V, LLVMMetadataRef VarInfo, - uint64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL, - LLVMBasicBlockRef InsertAtEnd) { - Builder->insertDeclare(unwrap(V), unwrap<DILocalVariable>(VarInfo), - Builder->createExpression( - llvm::ArrayRef<uint64_t>(AddrOps, AddrOpsCount)), - DebugLoc(cast<MDNode>(unwrap(DL))), - unwrap(InsertAtEnd)); +extern "C" void +LLVMRustDIBuilderInsertDeclareAtEnd(LLVMDIBuilderRef Builder, LLVMValueRef V, + LLVMMetadataRef VarInfo, uint64_t *AddrOps, + unsigned AddrOpsCount, LLVMMetadataRef DL, + LLVMBasicBlockRef InsertAtEnd) { + unwrap(Builder)->insertDeclare( + unwrap(V), unwrap<DILocalVariable>(VarInfo), + unwrap(Builder)->createExpression( + llvm::ArrayRef<uint64_t>(AddrOps, AddrOpsCount)), + DebugLoc(cast<MDNode>(unwrap(DL))), unwrap(InsertAtEnd)); } -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerator( - LLVMRustDIBuilderRef Builder, const char *Name, size_t NameLen, - const uint64_t Value[2], unsigned SizeInBits, bool IsUnsigned) { - return wrap(Builder->createEnumerator( +extern "C" LLVMMetadataRef +LLVMRustDIBuilderCreateEnumerator(LLVMDIBuilderRef Builder, const char *Name, + size_t NameLen, const uint64_t Value[2], + unsigned SizeInBits, bool IsUnsigned) { + return wrap(unwrap(Builder)->createEnumerator( StringRef(Name, NameLen), APSInt(APInt(SizeInBits, ArrayRef<uint64_t>(Value, 2)), IsUnsigned))); } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerationType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint32_t AlignInBits, LLVMMetadataRef Elements, LLVMMetadataRef ClassTy, bool IsScoped) { - return wrap(Builder->createEnumerationType( + return wrap(unwrap(Builder)->createEnumerationType( unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIFile>(File), LineNumber, SizeInBits, AlignInBits, DINodeArray(unwrapDI<MDTuple>(Elements)), unwrapDI<DIType>(ClassTy), @@ -1300,12 +1304,12 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerationType( } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, - uint64_t SizeInBits, uint32_t AlignInBits, LLVMRustDIFlags Flags, + uint64_t SizeInBits, uint32_t AlignInBits, LLVMDIFlags Flags, LLVMMetadataRef Elements, unsigned RunTimeLang, const char *UniqueId, size_t UniqueIdLen) { - return wrap(Builder->createUnionType( + return wrap(unwrap(Builder)->createUnionType( unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIFile>(File), LineNumber, SizeInBits, AlignInBits, fromRust(Flags), DINodeArray(unwrapDI<MDTuple>(Elements)), RunTimeLang, @@ -1313,28 +1317,28 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType( } extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef Ty) { bool IsDefault = false; // FIXME: should we ever set this true? - return wrap(Builder->createTemplateTypeParameter( + return wrap(unwrap(Builder)->createTemplateTypeParameter( unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty), IsDefault)); } extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateNameSpace(LLVMRustDIBuilderRef Builder, +LLVMRustDIBuilderCreateNameSpace(LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, bool ExportSymbols) { - return wrap(Builder->createNameSpace( + return wrap(unwrap(Builder)->createNameSpace( unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), ExportSymbols)); } extern "C" void LLVMRustDICompositeTypeReplaceArrays( - LLVMRustDIBuilderRef Builder, LLVMMetadataRef CompositeTy, + LLVMDIBuilderRef Builder, LLVMMetadataRef CompositeTy, LLVMMetadataRef Elements, LLVMMetadataRef Params) { DICompositeType *Tmp = unwrapDI<DICompositeType>(CompositeTy); - Builder->replaceArrays(Tmp, DINodeArray(unwrap<MDTuple>(Elements)), - DINodeArray(unwrap<MDTuple>(Params))); + unwrap(Builder)->replaceArrays(Tmp, DINodeArray(unwrap<MDTuple>(Elements)), + DINodeArray(unwrap<MDTuple>(Params))); } extern "C" LLVMMetadataRef diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 88ea6e07d6e..62bf34ad5ad 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -118,11 +118,17 @@ struct QueryModifiers { /// Generate a `feed` method to set the query's value from another query. feedable: Option<Ident>, - /// Forward the result on ensure if the query gets recomputed, and - /// return `Ok(())` otherwise. Only applicable to queries returning - /// `Result<T, ErrorGuaranteed>`. The `T` is not returned from `ensure` - /// invocations. - ensure_forwards_result_if_red: Option<Ident>, + /// When this query is called via `tcx.ensure_ok()`, it returns + /// `Result<(), ErrorGuaranteed>` instead of `()`. If the query needs to + /// be executed, and that execution returns an error, the error result is + /// returned to the caller. + /// + /// If execution is skipped, a synthetic `Ok(())` is returned, on the + /// assumption that a query with all-green inputs must have succeeded. + /// + /// Can only be applied to queries with a return value of + /// `Result<_, ErrorGuaranteed>`. + return_result_from_ensure_ok: Option<Ident>, } fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> { @@ -138,7 +144,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> { let mut depth_limit = None; let mut separate_provide_extern = None; let mut feedable = None; - let mut ensure_forwards_result_if_red = None; + let mut return_result_from_ensure_ok = None; while !input.is_empty() { let modifier: Ident = input.parse()?; @@ -200,8 +206,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> { try_insert!(separate_provide_extern = modifier); } else if modifier == "feedable" { try_insert!(feedable = modifier); - } else if modifier == "ensure_forwards_result_if_red" { - try_insert!(ensure_forwards_result_if_red = modifier); + } else if modifier == "return_result_from_ensure_ok" { + try_insert!(return_result_from_ensure_ok = modifier); } else { return Err(Error::new(modifier.span(), "unknown query modifier")); } @@ -222,7 +228,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> { depth_limit, separate_provide_extern, feedable, - ensure_forwards_result_if_red, + return_result_from_ensure_ok, }) } @@ -354,7 +360,7 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream { eval_always, depth_limit, separate_provide_extern, - ensure_forwards_result_if_red, + return_result_from_ensure_ok, ); if modifiers.cache.is_some() { diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index d2b5ae53185..6fc84b06647 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -113,6 +113,14 @@ metadata_incompatible_rustc = found crate `{$crate_name}` compiled by an incompatible version of rustc{$add_info} .help = please recompile that crate using this compiler ({$rustc_version}) (consider running `cargo clean` first) +metadata_incompatible_target_modifiers = + mixing `{$flag_name_prefixed}` will cause an ABI mismatch in crate `{$local_crate}` + .note = `{$flag_name_prefixed}={$flag_local_value}` in this crate is incompatible with `{$flag_name_prefixed}={$flag_extern_value}` in dependency `{$extern_crate}` + .help = the `{$flag_name_prefixed}` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely + +metadata_incompatible_target_modifiers_help_allow = if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch={$flag_name}` to silence this error +metadata_incompatible_target_modifiers_help_fix = set `{$flag_name_prefixed}={$flag_extern_value}` in this crate or `{$flag_name_prefixed}={$flag_local_value}` in `{$extern_crate}` + metadata_incompatible_wasm_link = `wasm_import_module` is incompatible with other arguments in `#[link]` attributes @@ -284,6 +292,8 @@ metadata_unknown_link_kind = metadata_unknown_link_modifier = unknown linking modifier `{$modifier}`, expected one of: bundle, verbatim, whole-archive, as-needed +metadata_unknown_target_modifier_unsafe_allowed = unknown target modifier `{$flag_name}`, requested by `-Cunsafe-allow-abi-mismatch={$flag_name}` + metadata_unsupported_abi = ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index a6cd0ecafd0..6bad8312790 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -23,7 +23,10 @@ use rustc_hir::definitions::Definitions; use rustc_index::IndexVec; use rustc_middle::bug; use rustc_middle::ty::{TyCtxt, TyCtxtFeed}; -use rustc_session::config::{self, CrateType, ExternLocation}; +use rustc_session::config::{ + self, CrateType, ExtendedTargetModifierInfo, ExternLocation, OptionsTargetModifiers, + TargetModifier, +}; use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource}; use rustc_session::lint::{self, BuiltinLintDiag}; use rustc_session::output::validate_crate_name; @@ -35,7 +38,9 @@ use tracing::{debug, info, trace}; use crate::errors; use crate::locator::{CrateError, CrateLocator, CratePaths}; -use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob}; +use crate::rmeta::{ + CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob, TargetModifiers, +}; /// The backend's way to give the crate store access to the metadata in a library. /// Note that it returns the raw metadata bytes stored in the library file, whether @@ -296,6 +301,94 @@ impl CStore { } } + fn report_target_modifiers_extended( + tcx: TyCtxt<'_>, + krate: &Crate, + mods: &TargetModifiers, + dep_mods: &TargetModifiers, + data: &CrateMetadata, + ) { + let span = krate.spans.inner_span.shrink_to_lo(); + let allowed_flag_mismatches = &tcx.sess.opts.cg.unsafe_allow_abi_mismatch; + let name = tcx.crate_name(LOCAL_CRATE); + let tmod_extender = |tmod: &TargetModifier| (tmod.extend(), tmod.clone()); + let report_diff = |prefix: &String, + opt_name: &String, + flag_local_value: &String, + flag_extern_value: &String| { + if allowed_flag_mismatches.contains(&opt_name) { + return; + } + tcx.dcx().emit_err(errors::IncompatibleTargetModifiers { + span, + extern_crate: data.name(), + local_crate: name, + flag_name: opt_name.clone(), + flag_name_prefixed: format!("-{}{}", prefix, opt_name), + flag_local_value: flag_local_value.to_string(), + flag_extern_value: flag_extern_value.to_string(), + }); + }; + let mut it1 = mods.iter().map(tmod_extender); + let mut it2 = dep_mods.iter().map(tmod_extender); + let mut left_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None; + let mut right_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None; + let no_val = "*".to_string(); + loop { + left_name_val = left_name_val.or_else(|| it1.next()); + right_name_val = right_name_val.or_else(|| it2.next()); + match (&left_name_val, &right_name_val) { + (Some(l), Some(r)) => match l.1.opt.cmp(&r.1.opt) { + cmp::Ordering::Equal => { + if l.0.tech_value != r.0.tech_value { + report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &r.1.value_name); + } + left_name_val = None; + right_name_val = None; + } + cmp::Ordering::Greater => { + report_diff(&r.0.prefix, &r.0.name, &no_val, &r.1.value_name); + right_name_val = None; + } + cmp::Ordering::Less => { + report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &no_val); + left_name_val = None; + } + }, + (Some(l), None) => { + report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &no_val); + left_name_val = None; + } + (None, Some(r)) => { + report_diff(&r.0.prefix, &r.0.name, &no_val, &r.1.value_name); + right_name_val = None; + } + (None, None) => break, + } + } + } + + pub fn report_incompatible_target_modifiers(&self, tcx: TyCtxt<'_>, krate: &Crate) { + for flag_name in &tcx.sess.opts.cg.unsafe_allow_abi_mismatch { + if !OptionsTargetModifiers::is_target_modifier(flag_name) { + tcx.dcx().emit_err(errors::UnknownTargetModifierUnsafeAllowed { + span: krate.spans.inner_span.shrink_to_lo(), + flag_name: flag_name.clone(), + }); + } + } + let mods = tcx.sess.opts.gather_target_modifiers(); + for (_cnum, data) in self.iter_crate_data() { + if data.is_proc_macro_crate() { + continue; + } + let dep_mods = data.target_modifiers(); + if mods != dep_mods { + Self::report_target_modifiers_extended(tcx, krate, &mods, &dep_mods, data); + } + } + } + pub fn new(metadata_loader: Box<MetadataLoaderDyn>) -> CStore { CStore { metadata_loader, diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index cefc6498f68..a77f9bc623b 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -739,3 +739,28 @@ pub(crate) struct WasmCAbi { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(metadata_incompatible_target_modifiers)] +#[help] +#[note] +#[help(metadata_incompatible_target_modifiers_help_fix)] +#[help(metadata_incompatible_target_modifiers_help_allow)] +pub struct IncompatibleTargetModifiers { + #[primary_span] + pub span: Span, + pub extern_crate: Symbol, + pub local_crate: Symbol, + pub flag_name: String, + pub flag_name_prefixed: String, + pub flag_local_value: String, + pub flag_extern_value: String, +} + +#[derive(Diagnostic)] +#[diag(metadata_unknown_target_modifier_unsafe_allowed)] +pub struct UnknownTargetModifierUnsafeAllowed { + #[primary_span] + pub span: Span, + pub flag_name: String, +} diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index e02c4871f35..2ae4a6a6066 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -29,6 +29,7 @@ use rustc_middle::{bug, implement_ty_decoder}; use rustc_serialize::opaque::MemDecoder; use rustc_serialize::{Decodable, Decoder}; use rustc_session::Session; +use rustc_session::config::TargetModifier; use rustc_session::cstore::{CrateSource, ExternCrate}; use rustc_span::hygiene::HygieneDecodeContext; use rustc_span::{BytePos, DUMMY_SP, Pos, SpanData, SpanDecoder, SyntaxContext, kw}; @@ -73,6 +74,9 @@ impl MetadataBlob { /// own crate numbers. pub(crate) type CrateNumMap = IndexVec<CrateNum, CrateNum>; +/// Target modifiers - abi or exploit mitigations flags +pub(crate) type TargetModifiers = Vec<TargetModifier>; + pub(crate) struct CrateMetadata { /// The primary crate data - binary metadata blob. blob: MetadataBlob, @@ -961,6 +965,13 @@ impl CrateRoot { ) -> impl ExactSizeIterator<Item = CrateDep> + Captures<'a> { self.crate_deps.decode(metadata) } + + pub(crate) fn decode_target_modifiers<'a>( + &self, + metadata: &'a MetadataBlob, + ) -> impl ExactSizeIterator<Item = TargetModifier> + Captures<'a> { + self.target_modifiers.decode(metadata) + } } impl<'a> CrateMetadataRef<'a> { @@ -1883,6 +1894,10 @@ impl CrateMetadata { self.dependencies.push(cnum); } + pub(crate) fn target_modifiers(&self) -> TargetModifiers { + self.root.decode_target_modifiers(&self.blob).collect() + } + pub(crate) fn update_extern_crate(&mut self, new_extern_crate: ExternCrate) -> bool { let update = Some(new_extern_crate.rank()) > self.extern_crate.as_ref().map(ExternCrate::rank); diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index da07ad8f6c0..028ff56155f 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -165,7 +165,7 @@ macro_rules! provide_one { // doesn't need to do this (and can't, as it would cause a query cycle). use rustc_middle::dep_graph::dep_kinds; if dep_kinds::$name != dep_kinds::crate_hash && $tcx.dep_graph.is_fully_enabled() { - $tcx.ensure().crate_hash($def_id.krate); + $tcx.ensure_ok().crate_hash($def_id.krate); } let cdata = rustc_data_structures::sync::FreezeReadGuard::map(CStore::from_tcx($tcx), |c| { @@ -689,7 +689,7 @@ fn provide_cstore_hooks(providers: &mut Providers) { providers.hooks.def_path_hash_to_def_id_extern = |tcx, hash, stable_crate_id| { // If this is a DefPathHash from an upstream crate, let the CrateStore map // it to a DefId. - let cstore = CStore::from_tcx(tcx.tcx); + let cstore = CStore::from_tcx(tcx); let cnum = *tcx .untracked() .stable_crate_ids @@ -702,11 +702,11 @@ fn provide_cstore_hooks(providers: &mut Providers) { }; providers.hooks.expn_hash_to_expn_id = |tcx, cnum, index_guess, hash| { - let cstore = CStore::from_tcx(tcx.tcx); + let cstore = CStore::from_tcx(tcx); cstore.get_crate_data(cnum).expn_hash_to_expn_id(tcx.sess, index_guess, hash) }; providers.hooks.import_source_files = |tcx, cnum| { - let cstore = CStore::from_tcx(tcx.tcx); + let cstore = CStore::from_tcx(tcx); let cdata = cstore.get_crate_data(cnum); for file_index in 0..cdata.root.source_map.size() { cdata.imported_source_file(file_index as u32, tcx.sess); diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 904409dd777..db41a33dcc5 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -9,6 +9,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::memmap::{Mmap, MmapMut}; use rustc_data_structures::sync::{Lrc, join, par_for_each_in}; use rustc_data_structures::temp_dir::MaybeTempDir; +use rustc_data_structures::thousands::format_with_underscores; use rustc_feature::Features; use rustc_hir as hir; use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE, LocalDefId, LocalDefIdSet}; @@ -22,10 +23,9 @@ use rustc_middle::traits::specialization_graph; use rustc_middle::ty::codec::TyEncoder; use rustc_middle::ty::fast_reject::{self, TreatParams}; use rustc_middle::ty::{AssocItemContainer, SymbolName}; -use rustc_middle::util::common::to_readable_str; use rustc_middle::{bug, span_bug}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque}; -use rustc_session::config::{CrateType, OptLevel}; +use rustc_session::config::{CrateType, OptLevel, TargetModifier}; use rustc_span::hygiene::HygieneEncodeContext; use rustc_span::{ ExternalSource, FileName, SourceFile, SpanData, SpanEncoder, StableSourceFileId, SyntaxContext, @@ -692,6 +692,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Encode source_map. This needs to be done last, because encoding `Span`s tells us which // `SourceFiles` we actually need to encode. let source_map = stat!("source-map", || self.encode_source_map()); + let target_modifiers = stat!("target-modifiers", || self.encode_target_modifiers()); let root = stat!("final", || { let attrs = tcx.hir().krate_attrs(); @@ -735,6 +736,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { native_libraries, foreign_modules, source_map, + target_modifiers, traits, impls, incoherent_impls, @@ -782,7 +784,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { "{} {:<23}{:>10} ({:4.1}%)", prefix, label, - to_readable_str(size), + format_with_underscores(size), perc(size) ); } @@ -791,7 +793,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { "{} {:<23}{:>10} (of which {:.1}% are zero bytes)", prefix, "Total", - to_readable_str(total_bytes), + format_with_underscores(total_bytes), perc(zero_bytes) ); eprintln!("{prefix}"); @@ -2009,6 +2011,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy_array(deps.iter().map(|(_, dep)| dep)) } + fn encode_target_modifiers(&mut self) -> LazyArray<TargetModifier> { + empty_proc_macro!(self); + let tcx = self.tcx; + self.lazy_array(tcx.sess.opts.gather_target_modifiers()) + } + fn encode_lib_features(&mut self) -> LazyArray<(Symbol, FeatureStability)> { empty_proc_macro!(self); let tcx = self.tcx; @@ -2191,13 +2199,13 @@ fn prefetch_mir(tcx: TyCtxt<'_>) { let (encode_const, encode_opt) = should_encode_mir(tcx, reachable_set, def_id); if encode_const { - tcx.ensure_with_value().mir_for_ctfe(def_id); + tcx.ensure_done().mir_for_ctfe(def_id); } if encode_opt { - tcx.ensure_with_value().optimized_mir(def_id); + tcx.ensure_done().optimized_mir(def_id); } if encode_opt || encode_const { - tcx.ensure_with_value().promoted_mir(def_id); + tcx.ensure_done().promoted_mir(def_id); } }) } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index d1d356c5220..7b34e605c53 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -1,7 +1,7 @@ use std::marker::PhantomData; use std::num::NonZero; -pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob}; +pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob, TargetModifiers}; use decoder::{DecodeContext, Metadata}; use def_path_hash_map::DefPathHashMapRef; use encoder::EncodeContext; @@ -32,7 +32,7 @@ use rustc_middle::ty::{ use rustc_middle::util::Providers; use rustc_middle::{mir, trivially_parameterized_over_tcx}; use rustc_serialize::opaque::FileEncoder; -use rustc_session::config::SymbolManglingVersion; +use rustc_session::config::{SymbolManglingVersion, TargetModifier}; use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib}; use rustc_span::edition::Edition; use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextData}; @@ -282,6 +282,7 @@ pub(crate) struct CrateRoot { def_path_hash_map: LazyValue<DefPathHashMapRef<'static>>, source_map: LazyTable<u32, Option<LazyValue<rustc_span::SourceFile>>>, + target_modifiers: LazyArray<TargetModifier>, compiler_builtins: bool, needs_allocator: bool, diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index 8dc529b4d7a..ded1c580572 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -17,6 +17,9 @@ middle_assert_gen_resume_after_panic = `gen` fn or block cannot be further itera middle_assert_misaligned_ptr_deref = misaligned pointer dereference: address must be a multiple of {$required} but is {$found} +middle_assert_null_ptr_deref = + null pointer dereference occurred + middle_assert_op_overflow = attempt to compute `{$left} {$op} {$right}`, which would overflow @@ -32,6 +35,8 @@ middle_assert_shl_overflow = middle_assert_shr_overflow = attempt to shift right by `{$val}`, which would overflow +middle_autodiff_unsafe_inner_const_ref = reading from a `Duplicated` const {$ty} is unsafe + middle_bounds_check = index out of bounds: the length is {$len} but the index is {$index} @@ -107,6 +112,8 @@ middle_type_length_limit = reached the type-length limit while instantiating `{$ middle_unknown_layout = the type `{$ty}` has an unknown layout +middle_unsupported_union = we don't support unions yet: '{$ty_name}' + middle_values_too_big = values of the type `{$ty}` are too big for the target architecture diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 750531b638e..eaccd8c360e 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -87,6 +87,7 @@ macro_rules! arena_types { [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<'tcx>, [decode] attribute: rustc_hir::Attribute, [] name_set: rustc_data_structures::unord::UnordSet<rustc_span::Symbol>, + [] autodiff_item: rustc_ast::expand::autodiff_attrs::AutoDiffItem, [] ordered_name_set: rustc_data_structures::fx::FxIndexSet<rustc_span::Symbol>, [] pats: rustc_middle::ty::PatternKind<'tcx>, diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index b0187a1848c..b30d3a950c6 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -37,6 +37,20 @@ pub struct OpaqueHiddenTypeMismatch<'tcx> { pub sub: TypeMismatchReason, } +#[derive(Diagnostic)] +#[diag(middle_unsupported_union)] +pub struct UnsupportedUnion { + pub ty_name: String, +} + +#[derive(Diagnostic)] +#[diag(middle_autodiff_unsafe_inner_const_ref)] +pub struct AutodiffUnsafeInnerConstRef { + #[primary_span] + pub span: Span, + pub ty: String, +} + #[derive(Subdiagnostic)] pub enum TypeMismatchReason { #[label(middle_conflict_types)] diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index 92fa64b0987..276a02b4e0f 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -1,16 +1,14 @@ -//! "Hooks" provide a way for `tcx` functionality to be provided by some downstream crate without -//! everything in rustc having to depend on that crate. This is somewhat similar to queries, but -//! queries come with a lot of machinery for caching and incremental compilation, whereas hooks are -//! just plain function pointers without any of the query magic. +//! "Hooks" let you write `tcx` methods in downstream crates and call them in this crate, reducing +//! the amount of code that needs to be in this crate (which is already very big). This is somewhat +//! similar to queries, but queries come with a lot of machinery for caching and incremental +//! compilation, whereas hooks are just plain function pointers without any of the query magic. use rustc_hir::def_id::{DefId, DefPathHash}; use rustc_session::StableCrateId; use rustc_span::def_id::{CrateNum, LocalDefId}; -use rustc_span::{DUMMY_SP, ExpnHash, ExpnId}; -use tracing::instrument; +use rustc_span::{ExpnHash, ExpnId}; use crate::mir; -use crate::query::TyCtxtAt; use crate::ty::{Ty, TyCtxt}; macro_rules! declare_hooks { @@ -22,26 +20,14 @@ macro_rules! declare_hooks { #[inline(always)] pub fn $name(self, $($arg: $K,)*) -> $V { - self.at(DUMMY_SP).$name($($arg,)*) - } - )* - } - - impl<'tcx> TyCtxtAt<'tcx> { - $( - $(#[$attr])* - #[inline(always)] - #[instrument(level = "debug", skip(self), ret)] - pub fn $name(self, $($arg: $K,)*) -> $V - { - (self.tcx.hooks.$name)(self, $($arg,)*) + (self.hooks.$name)(self, $($arg,)*) } )* } pub struct Providers { $(pub $name: for<'tcx> fn( - TyCtxtAt<'tcx>, + TyCtxt<'tcx>, $($arg: $K,)* ) -> $V,)* } @@ -75,12 +61,6 @@ declare_hooks! { /// (Eligible functions might nevertheless be skipped for other reasons.) hook is_eligible_for_coverage(key: LocalDefId) -> bool; - /// Create the MIR for a given `DefId` - this includes - /// unreachable code. - /// You do not want to call this yourself, instead use the cached version - /// via `mir_built` - hook build_mir(key: LocalDefId) -> mir::Body<'tcx>; - /// Imports all `SourceFile`s from the given crate into the current session. /// This normally happens automatically when we decode a `Span` from /// that crate's metadata - however, the incr comp cache needs @@ -99,14 +79,11 @@ declare_hooks! { /// Will fetch a DefId from a DefPathHash for a foreign crate. hook def_path_hash_to_def_id_extern(hash: DefPathHash, stable_crate_id: StableCrateId) -> DefId; - /// Create a THIR tree for debugging. - hook thir_tree(key: LocalDefId) -> String; - - /// Create a list-like THIR representation for debugging. - hook thir_flat(key: LocalDefId) -> String; - /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we /// can just link to the upstream crate and therefore don't need a mono item. + /// + /// Note: this hook isn't called within `rustc_middle` but #127779 suggests it's a hook instead + /// of a normal function because external tools might want to override it. hook should_codegen_locally(instance: crate::ty::Instance<'tcx>) -> bool; hook alloc_self_profile_query_strings() -> (); diff --git a/compiler/rustc_middle/src/infer/mod.rs b/compiler/rustc_middle/src/infer/mod.rs index 3dfcf90cb93..73e8971c3bd 100644 --- a/compiler/rustc_middle/src/infer/mod.rs +++ b/compiler/rustc_middle/src/infer/mod.rs @@ -1,2 +1 @@ pub mod canonical; -pub mod unify_key; diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index cae980cde61..ab711aca573 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -8,8 +8,7 @@ use rustc_macros::{Decodable, Encodable, HashStable}; use rustc_session::Session; use rustc_session::lint::builtin::{self, FORBIDDEN_LINT_GROUPS}; use rustc_session::lint::{FutureIncompatibilityReason, Level, Lint, LintExpectationId, LintId}; -use rustc_span::hygiene::{ExpnKind, MacroKind}; -use rustc_span::{DUMMY_SP, DesugaringKind, Span, Symbol, kw}; +use rustc_span::{DUMMY_SP, Span, Symbol, kw}; use tracing::instrument; use crate::ty::TyCtxt; @@ -201,7 +200,7 @@ impl LintExpectation { } } -pub fn explain_lint_level_source( +fn explain_lint_level_source( lint: &'static Lint, level: Level, src: LintLevelSource, @@ -325,7 +324,7 @@ pub fn lint_level( // If this code originates in a foreign macro, aka something that this crate // did not itself author, then it's likely that there's nothing this crate // can do about it. We probably want to skip the lint entirely. - if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) { + if err.span.primary_spans().iter().any(|s| s.in_external_macro(sess.source_map())) { // Any suggestions made here are likely to be incorrect, so anything we // emit shouldn't be automatically fixed by rustfix. err.disable_suggestions(); @@ -422,36 +421,3 @@ pub fn lint_level( } lint_level_impl(sess, lint, level, src, span, Box::new(decorate)) } - -/// Returns whether `span` originates in a foreign crate's external macro. -/// -/// This is used to test whether a lint should not even begin to figure out whether it should -/// be reported on the current node. -pub fn in_external_macro(sess: &Session, span: Span) -> bool { - let expn_data = span.ctxt().outer_expn_data(); - match expn_data.kind { - ExpnKind::Root - | ExpnKind::Desugaring( - DesugaringKind::ForLoop - | DesugaringKind::WhileLoop - | DesugaringKind::OpaqueTy - | DesugaringKind::Async - | DesugaringKind::Await, - ) => false, - ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external" - ExpnKind::Macro(MacroKind::Bang, _) => { - // Dummy span for the `def_site` means it's an external macro. - expn_data.def_site.is_dummy() || sess.source_map().is_imported(expn_data.def_site) - } - ExpnKind::Macro { .. } => true, // definitely a plugin - } -} - -/// Return whether `span` is generated by `async` or `await`. -pub fn is_from_async_await(span: Span) -> bool { - let expn_data = span.ctxt().outer_expn_data(); - match expn_data.kind { - ExpnKind::Desugaring(DesugaringKind::Async | DesugaringKind::Await) => true, - _ => false, - } -} diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index 39816c17b98..b3064d8fe25 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -4,8 +4,8 @@ /// /// If you have a span available, you should use [`span_bug`] instead. /// -/// If the bug should only be emitted when compilation didn't fail, [`DiagCtxtHandle::span_delayed_bug`] -/// may be useful. +/// If the bug should only be emitted when compilation didn't fail, +/// [`DiagCtxtHandle::span_delayed_bug`] may be useful. /// /// [`DiagCtxtHandle::span_delayed_bug`]: rustc_errors::DiagCtxtHandle::span_delayed_bug /// [`span_bug`]: crate::span_bug @@ -14,14 +14,8 @@ macro_rules! bug { () => ( $crate::bug!("impossible case reached") ); - ($msg:expr) => ( - $crate::util::bug::bug_fmt(::std::format_args!($msg)) - ); - ($msg:expr,) => ( - $crate::bug!($msg) - ); - ($fmt:expr, $($arg:tt)+) => ( - $crate::util::bug::bug_fmt(::std::format_args!($fmt, $($arg)+)) + ($($arg:tt)+) => ( + $crate::util::bug::bug_fmt(::std::format_args!($($arg)+)) ); } @@ -30,20 +24,14 @@ macro_rules! bug { /// at the code the compiler was compiling when it ICEd. This is the preferred way to trigger /// ICEs. /// -/// If the bug should only be emitted when compilation didn't fail, [`DiagCtxtHandle::span_delayed_bug`] -/// may be useful. +/// If the bug should only be emitted when compilation didn't fail, +/// [`DiagCtxtHandle::span_delayed_bug`] may be useful. /// /// [`DiagCtxtHandle::span_delayed_bug`]: rustc_errors::DiagCtxtHandle::span_delayed_bug #[macro_export] macro_rules! span_bug { - ($span:expr, $msg:expr) => ( - $crate::util::bug::span_bug_fmt($span, ::std::format_args!($msg)) - ); - ($span:expr, $msg:expr,) => ( - $crate::span_bug!($span, $msg) - ); - ($span:expr, $fmt:expr, $($arg:tt)+) => ( - $crate::util::bug::span_bug_fmt($span, ::std::format_args!($fmt, $($arg)+)) + ($span:expr, $($arg:tt)+) => ( + $crate::util::bug::span_bug_fmt($span, ::std::format_args!($($arg)+)) ); } @@ -53,7 +41,6 @@ macro_rules! span_bug { // When possible, use one of these (relatively) convenient macros to write // the impls for you. -#[macro_export] macro_rules! TrivialLiftImpls { ($($ty:ty),+ $(,)?) => { $( @@ -69,7 +56,6 @@ macro_rules! TrivialLiftImpls { /// Used for types that are `Copy` and which **do not care about arena /// allocated data** (i.e., don't need to be folded). -#[macro_export] macro_rules! TrivialTypeTraversalImpls { ($($ty:ty),+ $(,)?) => { $( @@ -104,7 +90,6 @@ macro_rules! TrivialTypeTraversalImpls { }; } -#[macro_export] macro_rules! TrivialTypeTraversalAndLiftImpls { ($($t:tt)*) => { TrivialTypeTraversalImpls! { $($t)* } diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index cc980f6e62a..1784665bcae 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -1,4 +1,5 @@ use rustc_abi::Align; +use rustc_ast::expand::autodiff_attrs::AutoDiffAttrs; use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_span::Symbol; @@ -52,6 +53,8 @@ pub struct CodegenFnAttrs { /// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around /// the function entry. pub patchable_function_entry: Option<PatchableFunctionEntry>, + /// For the `#[autodiff]` macros. + pub autodiff_item: Option<AutoDiffAttrs>, } #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] @@ -160,6 +163,7 @@ impl CodegenFnAttrs { instruction_set: None, alignment: None, patchable_function_entry: None, + autodiff_item: None, } } diff --git a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs index 111ac990bc7..51a079e8bc1 100644 --- a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs +++ b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs @@ -45,15 +45,22 @@ pub enum ObjectLifetimeDefault { Param(DefId), } -/// Maps the id of each lifetime reference to the lifetime decl +/// Maps the id of each bound variable reference to the variable decl /// that it corresponds to. -#[derive(HashStable, Debug)] +#[derive(Debug, Default, HashStable)] pub struct ResolveBoundVars { - /// Maps from every use of a named (not anonymous) lifetime to a - /// `Region` describing how that region is bound + // Maps from every use of a named (not anonymous) bound var to a + // `ResolvedArg` describing how that variable is bound. pub defs: SortedMap<ItemLocalId, ResolvedArg>, + // Maps relevant hir items to the bound vars on them. These include: + // - function defs + // - function pointers + // - closures + // - trait refs + // - bound types (like `T` in `for<'a> T<'a>: Foo`) pub late_bound_vars: SortedMap<ItemLocalId, Vec<ty::BoundVariableKind>>, + // List captured variables for each opaque type. pub opaque_captured_lifetimes: LocalDefIdMap<Vec<(ResolvedArg, LocalDefId)>>, } diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 66d97fda433..923160cc0cc 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -250,7 +250,7 @@ impl<'tcx> Const<'tcx> { // Dont use the outer ty as on invalid code we can wind up with them not being the same. // this then results in allowing const eval to add `1_i64 + 1_usize` in cases where the mir // was originally `({N: usize} + 1_usize)` under `generic_const_exprs`. - ty::ConstKind::Value(ty, _) => ty, + ty::ConstKind::Value(cv) => cv.ty, _ => *ty, } } @@ -264,7 +264,7 @@ impl<'tcx> Const<'tcx> { pub fn is_required_const(&self) -> bool { match self { Const::Ty(_, c) => match c.kind() { - ty::ConstKind::Value(_, _) => false, // already a value, cannot error + ty::ConstKind::Value(_) => false, // already a value, cannot error _ => true, }, Const::Val(..) => false, // already a value, cannot error @@ -276,11 +276,11 @@ impl<'tcx> Const<'tcx> { pub fn try_to_scalar(self) -> Option<Scalar> { match self { Const::Ty(_, c) => match c.kind() { - ty::ConstKind::Value(ty, valtree) if ty.is_primitive() => { + ty::ConstKind::Value(cv) if cv.ty.is_primitive() => { // A valtree of a type where leaves directly represent the scalar const value. // Just checking whether it is a leaf is insufficient as e.g. references are leafs // but the leaf value is the value they point to, not the reference itself! - Some(valtree.unwrap_leaf().into()) + Some(cv.valtree.unwrap_leaf().into()) } _ => None, }, @@ -295,9 +295,7 @@ impl<'tcx> Const<'tcx> { match self { Const::Val(ConstValue::Scalar(Scalar::Int(x)), _) => Some(x), Const::Ty(_, c) => match c.kind() { - ty::ConstKind::Value(ty, valtree) if ty.is_primitive() => { - Some(valtree.unwrap_leaf()) - } + ty::ConstKind::Value(cv) if cv.ty.is_primitive() => Some(cv.valtree.unwrap_leaf()), _ => None, }, _ => None, @@ -328,7 +326,7 @@ impl<'tcx> Const<'tcx> { } match c.kind() { - ConstKind::Value(ty, val) => Ok(tcx.valtree_to_const_val((ty, val))), + ConstKind::Value(cv) => Ok(tcx.valtree_to_const_val(cv)), ConstKind::Expr(_) => { bug!("Normalization of `ty::ConstKind::Expr` is unimplemented") } @@ -353,13 +351,13 @@ impl<'tcx> Const<'tcx> { typing_env: ty::TypingEnv<'tcx>, ) -> Option<Scalar> { if let Const::Ty(_, c) = self - && let ty::ConstKind::Value(ty, val) = c.kind() - && ty.is_primitive() + && let ty::ConstKind::Value(cv) = c.kind() + && cv.ty.is_primitive() { // Avoid the `valtree_to_const_val` query. Can only be done on primitive types that // are valtree leaves, and *not* on references. (References should return the // pointer here, which valtrees don't represent.) - Some(val.unwrap_leaf().into()) + Some(cv.valtree.unwrap_leaf().into()) } else { self.eval(tcx, typing_env, DUMMY_SP).ok()?.try_to_scalar() } @@ -473,7 +471,7 @@ impl<'tcx> Const<'tcx> { // A valtree may be a reference. Valtree references correspond to a // different allocation each time they are evaluated. Valtrees for primitive // types are fine though. - ty::ConstKind::Value(ty, _) => ty.is_primitive(), + ty::ConstKind::Value(cv) => cv.ty.is_primitive(), ty::ConstKind::Unevaluated(..) | ty::ConstKind::Expr(..) => false, // This can happen if evaluation of a constant failed. The result does not matter // much since compilation is doomed. diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 4c47d9636d3..78749428c6d 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -9,7 +9,7 @@ use super::{ ReportedErrorInfo, }; use crate::mir; -use crate::query::TyCtxtEnsure; +use crate::query::TyCtxtEnsureOk; use crate::ty::visit::TypeVisitableExt; use crate::ty::{self, GenericArgs, TyCtxt}; @@ -198,7 +198,7 @@ impl<'tcx> TyCtxt<'tcx> { } } -impl<'tcx> TyCtxtEnsure<'tcx> { +impl<'tcx> TyCtxtEnsureOk<'tcx> { /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts /// that can't take any generic arguments like const items or enum discriminants. If a /// generic parameter is used within the constant `ErrorHandled::TooGeneric` will be returned. diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 0f3fca434ee..cfb78e5dddf 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -27,7 +27,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisit use rustc_serialize::{Decodable, Encodable}; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Span, Symbol}; -use tracing::trace; +use tracing::{debug, trace}; pub use self::query::*; use self::visit::TyContext; @@ -1796,6 +1796,47 @@ impl DefLocation { } } +/// Checks if the specified `local` is used as the `self` parameter of a method call +/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is +/// returned. +pub fn find_self_call<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + local: Local, + block: BasicBlock, +) -> Option<(DefId, GenericArgsRef<'tcx>)> { + debug!("find_self_call(local={:?}): terminator={:?}", local, body[block].terminator); + if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) = + &body[block].terminator + && let Operand::Constant(box ConstOperand { const_, .. }) = func + && let ty::FnDef(def_id, fn_args) = *const_.ty().kind() + && let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) = + tcx.opt_associated_item(def_id) + && let [Spanned { node: Operand::Move(self_place) | Operand::Copy(self_place), .. }, ..] = + **args + { + if self_place.as_local() == Some(local) { + return Some((def_id, fn_args)); + } + + // Handle the case where `self_place` gets reborrowed. + // This happens when the receiver is `&T`. + for stmt in &body[block].statements { + if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind + && let Some(reborrow_local) = place.as_local() + && self_place.as_local() == Some(reborrow_local) + && let Rvalue::Ref(_, _, deref_place) = rvalue + && let PlaceRef { local: deref_local, projection: [ProjectionElem::Deref] } = + deref_place.as_ref() + && deref_local == local + { + return Some((def_id, fn_args)); + } + } + } + None +} + // Some nodes are used a lot. Make sure they don't unintentionally get bigger. #[cfg(target_pointer_width = "64")] mod size_asserts { diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 6fa3fa2432d..75931956310 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -1,6 +1,7 @@ use std::fmt; use std::hash::Hash; +use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_attr_parsing::InlineAttr; use rustc_data_structures::base_n::{BaseNString, CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::fingerprint::Fingerprint; @@ -91,51 +92,88 @@ impl<'tcx> MonoItem<'tcx> { } pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode { - let generate_cgu_internal_copies = - (tcx.sess.opts.optimize != OptLevel::No) && !tcx.sess.link_dead_code(); + // The case handling here is written in the same style as cross_crate_inlinable, we first + // handle the cases where we must use a particular instantiation mode, then cascade down + // through a sequence of heuristics. - match *self { - MonoItem::Fn(ref instance) => { - let entry_def_id = tcx.entry_fn(()).map(|(id, _)| id); - // If this function isn't inlined or otherwise has an extern - // indicator, then we'll be creating a globally shared version. - let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id()); - if codegen_fn_attrs.contains_extern_indicator() - || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) - || !instance.def.generates_cgu_internal_copy(tcx) - || Some(instance.def_id()) == entry_def_id - { - return InstantiationMode::GloballyShared { may_conflict: false }; - } - - if let InlineAttr::Never = tcx.codegen_fn_attrs(instance.def_id()).inline - && self.is_generic_fn() - { - // Upgrade inline(never) to a globally shared instance. - return InstantiationMode::GloballyShared { may_conflict: true }; - } - - // At this point we don't have explicit linkage and we're an - // inlined function. If this crate's build settings permit, - // we'll be creating a local copy per CGU. - if generate_cgu_internal_copies { - return InstantiationMode::LocalCopy; - } - - // Finally, if this is `#[inline(always)]` we're sure to respect - // that with an inline copy per CGU, but otherwise we'll be - // creating one copy of this `#[inline]` function which may - // conflict with upstream crates as it could be an exported - // symbol. - if tcx.codegen_fn_attrs(instance.def_id()).inline.always() { - InstantiationMode::LocalCopy - } else { - InstantiationMode::GloballyShared { may_conflict: true } - } - } + // The first thing we do is detect MonoItems which we must instantiate exactly once in the + // whole program. + + // Statics and global_asm! must be instantiated exactly once. + let instance = match *self { + MonoItem::Fn(instance) => instance, MonoItem::Static(..) | MonoItem::GlobalAsm(..) => { - InstantiationMode::GloballyShared { may_conflict: false } + return InstantiationMode::GloballyShared { may_conflict: false }; } + }; + + // Similarly, the executable entrypoint must be instantiated exactly once. + if let Some((entry_def_id, _)) = tcx.entry_fn(()) { + if instance.def_id() == entry_def_id { + return InstantiationMode::GloballyShared { may_conflict: false }; + } + } + + // If the function is #[naked] or contains any other attribute that requires exactly-once + // instantiation: + let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id()); + if codegen_fn_attrs.contains_extern_indicator() + || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) + { + return InstantiationMode::GloballyShared { may_conflict: false }; + } + + // FIXME: The logic for which functions are permitted to get LocalCopy is actually spread + // across 4 functions: + // * cross_crate_inlinable(def_id) + // * InstanceKind::requires_inline + // * InstanceKind::generate_cgu_internal_copy + // * MonoItem::instantiation_mode + // Since reachable_non_generics calls InstanceKind::generates_cgu_internal_copy to decide + // which symbols this crate exports, we are obligated to only generate LocalCopy when + // generates_cgu_internal_copy returns true. + if !instance.def.generates_cgu_internal_copy(tcx) { + return InstantiationMode::GloballyShared { may_conflict: false }; + } + + // Beginning of heuristics. The handling of link-dead-code and inline(always) are QoL only, + // the compiler should not crash and linkage should work, but codegen may be undesirable. + + // -Clink-dead-code was given an unfortunate name; the point of the flag is to assist + // coverage tools which rely on having every function in the program appear in the + // generated code. If we select LocalCopy, functions which are not used because they are + // missing test coverage will disappear from such coverage reports, defeating the point. + // Note that -Cinstrument-coverage does not require such assistance from us, only coverage + // tools implemented without compiler support ironically require a special compiler flag. + if tcx.sess.link_dead_code() { + return InstantiationMode::GloballyShared { may_conflict: true }; + } + + // To ensure that #[inline(always)] can be inlined as much as possible, especially in unoptimized + // builds, we always select LocalCopy. + if codegen_fn_attrs.inline.always() { + return InstantiationMode::LocalCopy; + } + + // #[inline(never)] functions in general are poor candidates for inlining and thus since + // LocalCopy generally increases code size for the benefit of optimizations from inlining, + // we want to give them GloballyShared codegen. + // The slight problem is that generic functions need to always support cross-crate + // compilation, so all previous stages of the compiler are obligated to treat generic + // functions the same as those that unconditionally get LocalCopy codegen. It's only when + // we get here that we can at least not codegen a #[inline(never)] generic function in all + // of our CGUs. + if let InlineAttr::Never = tcx.codegen_fn_attrs(instance.def_id()).inline + && self.is_generic_fn() + { + return InstantiationMode::GloballyShared { may_conflict: true }; + } + + // The fallthrough case is to generate LocalCopy for all optimized builds, and + // GloballyShared with conflict prevention when optimizations are disabled. + match tcx.sess.opts.optimize { + OptLevel::No => InstantiationMode::GloballyShared { may_conflict: true }, + _ => InstantiationMode::LocalCopy, } } @@ -246,6 +284,7 @@ impl ToStableHashKey<StableHashingContext<'_>> for MonoItem<'_> { pub struct MonoItemPartitions<'tcx> { pub codegen_units: &'tcx [CodegenUnit<'tcx>], pub all_mono_items: &'tcx DefIdSet, + pub autodiff_items: &'tcx [AutoDiffItem], } #[derive(Debug, HashStable)] diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 3b4fba97e60..09d7e60e199 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1248,6 +1248,10 @@ impl<'tcx> Debug for Rvalue<'tcx> { ShallowInitBox(ref place, ref ty) => { with_no_trimmed_paths!(write!(fmt, "ShallowInitBox({place:?}, {ty})")) } + + WrapUnsafeBinder(ref op, ty) => { + with_no_trimmed_paths!(write!(fmt, "wrap_binder!({op:?}; {ty})")) + } } } } @@ -1308,6 +1312,9 @@ fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {} + ProjectionElem::UnwrapUnsafeBinder(_) => { + write!(fmt, "unwrap_binder!(")?; + } } } @@ -1356,6 +1363,9 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> ProjectionElem::Subslice { from, to, from_end: false } => { write!(fmt, "[{from:?}..{to:?}]")?; } + ProjectionElem::UnwrapUnsafeBinder(ty) => { + write!(fmt, "; {ty})")?; + } } } @@ -1441,7 +1451,9 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { ty::ConstKind::Unevaluated(uv) => { format!("ty::Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,) } - ty::ConstKind::Value(_, val) => format!("ty::Valtree({})", fmt_valtree(&val)), + ty::ConstKind::Value(cv) => { + format!("ty::Valtree({})", fmt_valtree(&cv.valtree)) + } // No `ty::` prefix since we also use this to represent errors from `mir::Unevaluated`. ty::ConstKind::Error(_) => "Error".to_string(), // These variants shouldn't exist in the MIR. diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 609d5647d04..d345c99f902 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -62,7 +62,8 @@ impl<V, T> ProjectionElem<V, T> { | Self::Subtype(_) | Self::ConstantIndex { .. } | Self::Subslice { .. } - | Self::Downcast(_, _) => false, + | Self::Downcast(_, _) + | Self::UnwrapUnsafeBinder(..) => false, } } @@ -76,7 +77,8 @@ impl<V, T> ProjectionElem<V, T> { | Self::Subtype(_) | Self::ConstantIndex { .. } | Self::Subslice { .. } - | Self::Downcast(_, _) => true, + | Self::Downcast(_, _) + | Self::UnwrapUnsafeBinder(..) => true, } } @@ -102,6 +104,9 @@ impl<V, T> ProjectionElem<V, T> { | Self::Subtype(_) | Self::OpaqueCast(_) | Self::Subslice { .. } => false, + + // FIXME(unsafe_binders): Figure this out. + Self::UnwrapUnsafeBinder(..) => false, } } } @@ -443,7 +448,8 @@ impl<'tcx> Rvalue<'tcx> { | Rvalue::UnaryOp(_, _) | Rvalue::Discriminant(_) | Rvalue::Aggregate(_, _) - | Rvalue::ShallowInitBox(_, _) => true, + | Rvalue::ShallowInitBox(_, _) + | Rvalue::WrapUnsafeBinder(_, _) => true, } } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 5868b64f6b5..2da25f480c6 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1076,6 +1076,7 @@ pub enum AssertKind<O> { ResumedAfterReturn(CoroutineKind), ResumedAfterPanic(CoroutineKind), MisalignedPointerDereference { required: O, found: O }, + NullPointerDereference, } #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] @@ -1275,6 +1276,10 @@ pub enum ProjectionElem<V, T> { /// requiring an intermediate variable. OpaqueCast(T), + /// A transmute from an unsafe binder to the type that it wraps. This is a projection + /// of a place, so it doesn't necessarily constitute a move out of the binder. + UnwrapUnsafeBinder(T), + /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping /// explicit during optimizations and codegen. @@ -1492,6 +1497,9 @@ pub enum Rvalue<'tcx> { /// optimizations and codegen backends that previously had to handle deref operations anywhere /// in a place. CopyForDeref(Place<'tcx>), + + /// Wraps a value in an unsafe binder. + WrapUnsafeBinder(Operand<'tcx>, Ty<'tcx>), } #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 4d11492e94d..49449426fa4 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -146,6 +146,11 @@ impl<'tcx> PlaceTy<'tcx> { ProjectionElem::Subtype(ty) => { PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty)) } + + // FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general. + ProjectionElem::UnwrapUnsafeBinder(ty) => { + PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty)) + } }; debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer); answer @@ -241,6 +246,7 @@ impl<'tcx> Rvalue<'tcx> { }, Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty), Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty, + Rvalue::WrapUnsafeBinder(_, ty) => ty, } } diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index c04a8251fbc..2fe116212eb 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -206,6 +206,7 @@ impl<O> AssertKind<O> { ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => { LangItem::PanicGenFnNonePanic } + NullPointerDereference => LangItem::PanicNullPointerDereference, BoundsCheck { .. } | MisalignedPointerDereference { .. } => { bug!("Unexpected AssertKind") @@ -271,6 +272,7 @@ impl<O> AssertKind<O> { "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {required:?}, {found:?}" ) } + NullPointerDereference => write!(f, "\"null pointer dereference occured\""), ResumedAfterReturn(CoroutineKind::Coroutine(_)) => { write!(f, "\"coroutine resumed after completion\"") } @@ -341,7 +343,7 @@ impl<O> AssertKind<O> { ResumedAfterPanic(CoroutineKind::Coroutine(_)) => { middle_assert_coroutine_resume_after_panic } - + NullPointerDereference => middle_assert_null_ptr_deref, MisalignedPointerDereference { .. } => middle_assert_misaligned_ptr_deref, } } @@ -374,7 +376,7 @@ impl<O> AssertKind<O> { add!("left", format!("{left:#?}")); add!("right", format!("{right:#?}")); } - ResumedAfterReturn(_) | ResumedAfterPanic(_) => {} + ResumedAfterReturn(_) | ResumedAfterPanic(_) | NullPointerDereference => {} MisalignedPointerDereference { required, found } => { add!("required", format!("{required:#?}")); add!("found", format!("{found:#?}")); diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index b59b9e55fe8..9893dd0484c 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -1,6 +1,7 @@ //! `TypeFoldable` implementations for MIR types use rustc_ast::InlineAsmTemplatePiece; +use rustc_hir::UnsafeBinderCastKind; use rustc_hir::def_id::LocalDefId; use super::*; @@ -21,6 +22,7 @@ TrivialTypeTraversalImpls! { SwitchTargets, CoroutineKind, CoroutineSavedLocal, + UnsafeBinderCastKind, } TrivialTypeTraversalImpls! { diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 95de08ce9c8..8d04bbb95bd 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -636,7 +636,7 @@ macro_rules! make_mir_visitor { OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => { self.visit_operand(op, location); } - ResumedAfterReturn(_) | ResumedAfterPanic(_) => { + ResumedAfterReturn(_) | ResumedAfterPanic(_) | NullPointerDereference => { // Nothing to visit } MisalignedPointerDereference { required, found } => { @@ -781,6 +781,11 @@ macro_rules! make_mir_visitor { self.visit_operand(operand, location); self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); } + + Rvalue::WrapUnsafeBinder(op, ty) => { + self.visit_operand(op, location); + self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); + } } } @@ -1151,6 +1156,11 @@ macro_rules! visit_place_fns { self.visit_ty(&mut new_ty, TyContext::Location(location)); if ty != new_ty { Some(PlaceElem::Subtype(new_ty)) } else { None } } + PlaceElem::UnwrapUnsafeBinder(ty) => { + let mut new_ty = ty; + self.visit_ty(&mut new_ty, TyContext::Location(location)); + if ty != new_ty { Some(PlaceElem::UnwrapUnsafeBinder(new_ty)) } else { None } + } PlaceElem::Deref | PlaceElem::ConstantIndex { .. } | PlaceElem::Subslice { .. } @@ -1219,7 +1229,8 @@ macro_rules! visit_place_fns { match elem { ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) - | ProjectionElem::Field(_, ty) => { + | ProjectionElem::Field(_, ty) + | ProjectionElem::UnwrapUnsafeBinder(ty) => { self.visit_ty(ty, TyContext::Location(location)); } ProjectionElem::Index(local) => { diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index e243425c0b7..949d8303385 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -95,7 +95,7 @@ impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { } } -impl<'tcx> Key for (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) { +impl<'tcx> Key for (Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>) { type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _: TyCtxt<'_>) -> Span { @@ -550,7 +550,7 @@ impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>) { } } -impl<'tcx> Key for (Ty<'tcx>, ty::ValTree<'tcx>) { +impl<'tcx> Key for ty::Value<'tcx> { type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _: TyCtxt<'_>) -> Span { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d83bc19a6a2..6c442fc1047 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -91,7 +91,7 @@ pub use keys::{AsLocalKey, Key, LocalCrate}; pub mod on_disk_cache; #[macro_use] pub mod plumbing; -pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsure, TyCtxtEnsureWithValue}; +pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsureDone, TyCtxtEnsureOk}; // Each of these queries corresponds to a function pointer field in the // `Providers` struct for requesting a value of that type, and a method @@ -1087,7 +1087,7 @@ rustc_queries! { query check_mod_type_wf(key: LocalModDefId) -> Result<(), ErrorGuaranteed> { desc { |tcx| "checking that types are well-formed in {}", describe_as_module(key, tcx) } - ensure_forwards_result_if_red + return_result_from_ensure_ok } /// Caches `CoerceUnsized` kinds for impls on custom types. @@ -1095,7 +1095,7 @@ rustc_queries! { desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern - ensure_forwards_result_if_red + return_result_from_ensure_ok } query typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> { @@ -1110,7 +1110,7 @@ rustc_queries! { query coherent_trait(def_id: DefId) -> Result<(), ErrorGuaranteed> { desc { |tcx| "coherence checking all impls of trait `{}`", tcx.def_path_str(def_id) } - ensure_forwards_result_if_red + return_result_from_ensure_ok } /// Borrow-checks the function body. If this is a closure, returns @@ -1140,7 +1140,7 @@ rustc_queries! { /// </div> query crate_inherent_impls_validity_check(_: ()) -> Result<(), ErrorGuaranteed> { desc { "check for inherent impls that should not be defined in crate" } - ensure_forwards_result_if_red + return_result_from_ensure_ok } /// Checks all types in the crate for overlap in their inherent impls. Reports errors. @@ -1152,7 +1152,7 @@ rustc_queries! { /// </div> query crate_inherent_impls_overlap_check(_: ()) -> Result<(), ErrorGuaranteed> { desc { "check for overlap between inherent impls defined in this crate" } - ensure_forwards_result_if_red + return_result_from_ensure_ok } /// Checks whether all impls in the crate pass the overlap check, returning @@ -1162,7 +1162,7 @@ rustc_queries! { "checking whether impl `{}` follows the orphan rules", tcx.def_path_str(key), } - ensure_forwards_result_if_red + return_result_from_ensure_ok } /// Check whether the function has any recursion that could cause the inliner to trigger @@ -1256,9 +1256,9 @@ rustc_queries! { desc { "evaluating type-level constant" } } - /// Converts a type level constant value into `ConstValue` - query valtree_to_const_val(key: (Ty<'tcx>, ty::ValTree<'tcx>)) -> mir::ConstValue<'tcx> { - desc { "converting type-level constant value to mir constant value"} + /// Converts a type-level constant value into a MIR constant value. + query valtree_to_const_val(key: ty::Value<'tcx>) -> mir::ConstValue<'tcx> { + desc { "converting type-level constant value to MIR constant value"} } /// Destructures array, ADT or tuple constants into the constants @@ -1437,9 +1437,9 @@ rustc_queries! { desc { |tcx| "finding all existential vtable entries for trait `{}`", tcx.def_path_str(key) } } - query vtable_entries(key: ty::PolyTraitRef<'tcx>) + query vtable_entries(key: ty::TraitRef<'tcx>) -> &'tcx [ty::VtblEntry<'tcx>] { - desc { |tcx| "finding all vtable entries for trait `{}`", tcx.def_path_str(key.def_id()) } + desc { |tcx| "finding all vtable entries for trait `{}`", tcx.def_path_str(key.def_id) } } query first_method_vtable_slot(key: ty::TraitRef<'tcx>) -> usize { @@ -1451,7 +1451,7 @@ rustc_queries! { key.1, key.0 } } - query vtable_allocation(key: (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>)) -> mir::interpret::AllocId { + query vtable_allocation(key: (Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>)) -> mir::interpret::AllocId { desc { |tcx| "vtable const allocation for <{} as {}>", key.0, key.1.map(|trait_ref| format!("{trait_ref}")).unwrap_or("_".to_owned()) @@ -1479,7 +1479,7 @@ rustc_queries! { query specialization_graph_of(trait_id: DefId) -> Result<&'tcx specialization_graph::Graph, ErrorGuaranteed> { desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) } cache_on_disk_if { true } - ensure_forwards_result_if_red + return_result_from_ensure_ok } query dyn_compatibility_violations(trait_id: DefId) -> &'tcx [DynCompatibilityViolation] { desc { |tcx| "determining dyn-compatibility of trait `{}`", tcx.def_path_str(trait_id) } @@ -1715,12 +1715,12 @@ rustc_queries! { query check_well_formed(key: LocalDefId) -> Result<(), ErrorGuaranteed> { desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key) } - ensure_forwards_result_if_red + return_result_from_ensure_ok } query enforce_impl_non_lifetime_params_are_constrained(key: LocalDefId) -> Result<(), ErrorGuaranteed> { desc { |tcx| "checking that `{}`'s generics are constrained by the impl header", tcx.def_path_str(key) } - ensure_forwards_result_if_red + return_result_from_ensure_ok } // The `DefId`s of all non-generic functions and statics in the given crate @@ -2442,7 +2442,7 @@ rustc_queries! { /// Any other def id will ICE. query compare_impl_item(key: LocalDefId) -> Result<(), ErrorGuaranteed> { desc { |tcx| "checking assoc item `{}` is compatible with trait definition", tcx.def_path_str(key) } - ensure_forwards_result_if_red + return_result_from_ensure_ok } query deduced_param_attrs(def_id: DefId) -> &'tcx [ty::DeducedParamAttrs] { diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 1c157f33a81..6c019b427db 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -88,30 +88,68 @@ impl<'tcx> Deref for TyCtxtAt<'tcx> { } #[derive(Copy, Clone)] -pub struct TyCtxtEnsure<'tcx> { +#[must_use] +pub struct TyCtxtEnsureOk<'tcx> { pub tcx: TyCtxt<'tcx>, } #[derive(Copy, Clone)] -pub struct TyCtxtEnsureWithValue<'tcx> { +#[must_use] +pub struct TyCtxtEnsureDone<'tcx> { pub tcx: TyCtxt<'tcx>, } impl<'tcx> TyCtxt<'tcx> { - /// Returns a transparent wrapper for `TyCtxt`, which ensures queries - /// are executed instead of just returning their results. + /// Wrapper that calls queries in a special "ensure OK" mode, for callers + /// that don't need the return value and just want to invoke a query for + /// its potential side-effect of emitting fatal errors. + /// + /// This can be more efficient than a normal query call, because if the + /// query's inputs are all green, the call can return immediately without + /// needing to obtain a value (by decoding one from disk or by executing + /// the query). + /// + /// (As with all query calls, execution is also skipped if the query result + /// is already cached in memory.) + /// + /// ## WARNING + /// A subsequent normal call to the same query might still cause it to be + /// executed! This can occur when the inputs are all green, but the query's + /// result is not cached on disk, so the query must be executed to obtain a + /// return value. + /// + /// Therefore, this call mode is not appropriate for callers that want to + /// ensure that the query is _never_ executed in the future. + /// + /// ## `return_result_from_ensure_ok` + /// If a query has the `return_result_from_ensure_ok` modifier, calls via + /// `ensure_ok` will instead return `Result<(), ErrorGuaranteed>`. If the + /// query needs to be executed, and execution returns an error, that error + /// is returned to the caller. #[inline(always)] - pub fn ensure(self) -> TyCtxtEnsure<'tcx> { - TyCtxtEnsure { tcx: self } + pub fn ensure_ok(self) -> TyCtxtEnsureOk<'tcx> { + TyCtxtEnsureOk { tcx: self } } - /// Returns a transparent wrapper for `TyCtxt`, which ensures queries - /// are executed instead of just returning their results. + /// Wrapper that calls queries in a special "ensure done" mode, for callers + /// that don't need the return value and just want to guarantee that the + /// query won't be executed in the future, by executing it now if necessary. /// - /// This version verifies that the computed result exists in the cache before returning. + /// This is useful for queries that read from a [`Steal`] value, to ensure + /// that they are executed before the query that will steal the value. + /// + /// Unlike [`Self::ensure_ok`], a query with all-green inputs will only be + /// skipped if its return value is stored in the disk-cache. This is still + /// more efficient than a regular query, because in that situation the + /// return value doesn't necessarily need to be decoded. + /// + /// (As with all query calls, execution is also skipped if the query result + /// is already cached in memory.) + /// + /// [`Steal`]: rustc_data_structures::steal::Steal #[inline(always)] - pub fn ensure_with_value(self) -> TyCtxtEnsureWithValue<'tcx> { - TyCtxtEnsureWithValue { tcx: self } + pub fn ensure_done(self) -> TyCtxtEnsureDone<'tcx> { + TyCtxtEnsureDone { tcx: self } } /// Returns a transparent wrapper for `TyCtxt` which uses @@ -193,7 +231,7 @@ macro_rules! query_ensure { ([]$($args:tt)*) => { query_ensure($($args)*) }; - ([(ensure_forwards_result_if_red) $($rest:tt)*]$($args:tt)*) => { + ([(return_result_from_ensure_ok) $($rest:tt)*]$($args:tt)*) => { query_ensure_error_guaranteed($($args)*).map(|_| ()) }; ([$other:tt $($modifiers:tt)*]$($args:tt)*) => { @@ -248,15 +286,15 @@ macro_rules! separate_provide_extern_decl { }; } -macro_rules! ensure_result { - ([][$ty:ty]) => { +macro_rules! ensure_ok_result { + ( [] ) => { () }; - ([(ensure_forwards_result_if_red) $($rest:tt)*][$ty:ty]) => { + ( [(return_result_from_ensure_ok) $($rest:tt)*] ) => { Result<(), ErrorGuaranteed> }; - ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { - ensure_result!([$($modifiers)*][$($args)*]) + ( [$other:tt $($modifiers:tt)*] ) => { + ensure_ok_result!( [$($modifiers)*] ) }; } @@ -383,10 +421,13 @@ macro_rules! define_callbacks { $($(#[$attr])* pub $name: queries::$name::Storage<'tcx>,)* } - impl<'tcx> TyCtxtEnsure<'tcx> { + impl<'tcx> TyCtxtEnsureOk<'tcx> { $($(#[$attr])* #[inline(always)] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> ensure_result!([$($modifiers)*][$V]) { + pub fn $name( + self, + key: query_helper_param_ty!($($K)*), + ) -> ensure_ok_result!([$($modifiers)*]) { query_ensure!( [$($modifiers)*] self.tcx, @@ -398,7 +439,7 @@ macro_rules! define_callbacks { })* } - impl<'tcx> TyCtxtEnsureWithValue<'tcx> { + impl<'tcx> TyCtxtEnsureDone<'tcx> { $($(#[$attr])* #[inline(always)] pub fn $name(self, key: query_helper_param_ty!($($K)*)) { diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 86014c34b45..5490f1f53ea 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -18,7 +18,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd}; use rustc_index::{IndexVec, newtype_index}; -use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeVisitable}; +use rustc_macros::{HashStable, TypeVisitable}; use rustc_middle::middle::region; use rustc_middle::mir::interpret::AllocId; use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, UnOp}; @@ -53,7 +53,7 @@ macro_rules! thir_with_elements { /// A container for a THIR body. /// /// This can be indexed directly by any THIR index (e.g. [`ExprId`]). - #[derive(Debug, HashStable, Clone)] + #[derive(Debug, HashStable)] pub struct Thir<'tcx> { $( pub $field_name: $field_ty, @@ -98,14 +98,14 @@ thir_with_elements! { params: ParamId => Param<'tcx> => "p{}", } -#[derive(Debug, HashStable, Clone)] +#[derive(Debug, HashStable)] pub enum BodyTy<'tcx> { Const(Ty<'tcx>), Fn(FnSig<'tcx>), } /// Description of a type-checked function parameter. -#[derive(Clone, Debug, HashStable)] +#[derive(Debug, HashStable)] pub struct Param<'tcx> { /// The pattern that appears in the parameter list, or None for implicit parameters. pub pat: Option<Box<Pat<'tcx>>>, @@ -125,7 +125,7 @@ pub enum LintLevel { Explicit(HirId), } -#[derive(Clone, Debug, HashStable)] +#[derive(Debug, HashStable)] pub struct Block { /// Whether the block itself has a label. Used by `label: {}` /// and `try` blocks. @@ -145,7 +145,7 @@ pub struct Block { type UserTy<'tcx> = Option<Box<CanonicalUserType<'tcx>>>; -#[derive(Clone, Debug, HashStable)] +#[derive(Debug, HashStable)] pub struct AdtExpr<'tcx> { /// The ADT we're constructing. pub adt_def: AdtDef<'tcx>, @@ -162,7 +162,7 @@ pub struct AdtExpr<'tcx> { pub base: AdtExprBase<'tcx>, } -#[derive(Clone, Debug, HashStable)] +#[derive(Debug, HashStable)] pub enum AdtExprBase<'tcx> { /// A struct expression where all the fields are explicitly enumerated: `Foo { a, b }`. None, @@ -175,7 +175,7 @@ pub enum AdtExprBase<'tcx> { DefaultFields(Box<[Ty<'tcx>]>), } -#[derive(Clone, Debug, HashStable)] +#[derive(Debug, HashStable)] pub struct ClosureExpr<'tcx> { pub closure_id: LocalDefId, pub args: UpvarArgs<'tcx>, @@ -184,7 +184,7 @@ pub struct ClosureExpr<'tcx> { pub fake_reads: Vec<(ExprId, FakeReadCause, HirId)>, } -#[derive(Clone, Debug, HashStable)] +#[derive(Debug, HashStable)] pub struct InlineAsmExpr<'tcx> { pub asm_macro: AsmMacro, pub template: &'tcx [InlineAsmTemplatePiece], @@ -202,12 +202,12 @@ pub enum BlockSafety { ExplicitUnsafe(HirId), } -#[derive(Clone, Debug, HashStable)] +#[derive(Debug, HashStable)] pub struct Stmt<'tcx> { pub kind: StmtKind<'tcx>, } -#[derive(Clone, Debug, HashStable)] +#[derive(Debug, HashStable)] pub enum StmtKind<'tcx> { /// An expression with a trailing semicolon. Expr { @@ -247,11 +247,11 @@ pub enum StmtKind<'tcx> { }, } -#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, HashStable)] pub struct LocalVarId(pub HirId); /// A THIR expression. -#[derive(Clone, Debug, HashStable)] +#[derive(Debug, HashStable)] pub struct Expr<'tcx> { /// kind of expression pub kind: ExprKind<'tcx>, @@ -278,7 +278,7 @@ pub struct TempLifetime { pub backwards_incompatible: Option<region::Scope>, } -#[derive(Clone, Debug, HashStable)] +#[derive(Debug, HashStable)] pub enum ExprKind<'tcx> { /// `Scope`s are used to explicitly mark destruction scopes, /// and to track the `HirId` of the expressions within the scope. @@ -489,6 +489,19 @@ pub enum ExprKind<'tcx> { user_ty: UserTy<'tcx>, user_ty_span: Span, }, + /// An unsafe binder cast on a place, e.g. `unwrap_binder!(*ptr)`. + PlaceUnwrapUnsafeBinder { + source: ExprId, + }, + /// An unsafe binder cast on a value, e.g. `unwrap_binder!(rvalue())`, + /// which makes a temporary. + ValueUnwrapUnsafeBinder { + source: ExprId, + }, + /// Construct an unsafe binder, e.g. `wrap_binder(&ref)`. + WrapUnsafeBinder { + source: ExprId, + }, /// A closure definition. Closure(Box<ClosureExpr<'tcx>>), /// A literal. @@ -543,20 +556,20 @@ pub enum ExprKind<'tcx> { /// Represents the association of a field identifier and an expression. /// /// This is used in struct constructors. -#[derive(Clone, Debug, HashStable)] +#[derive(Debug, HashStable)] pub struct FieldExpr { pub name: FieldIdx, pub expr: ExprId, } -#[derive(Clone, Debug, HashStable)] +#[derive(Debug, HashStable)] pub struct FruInfo<'tcx> { pub base: ExprId, pub field_types: Box<[Ty<'tcx>]>, } /// A `match` arm. -#[derive(Clone, Debug, HashStable)] +#[derive(Debug, HashStable)] pub struct Arm<'tcx> { pub pattern: Box<Pat<'tcx>>, pub guard: Option<ExprId>, @@ -574,7 +587,7 @@ pub enum LogicalOp { Or, } -#[derive(Clone, Debug, HashStable)] +#[derive(Debug, HashStable)] pub enum InlineAsmOperand<'tcx> { In { reg: InlineAsmRegOrRegClass, @@ -612,13 +625,13 @@ pub enum InlineAsmOperand<'tcx> { }, } -#[derive(Clone, Debug, HashStable, TypeVisitable)] +#[derive(Debug, HashStable, TypeVisitable)] pub struct FieldPat<'tcx> { pub field: FieldIdx, pub pattern: Box<Pat<'tcx>>, } -#[derive(Clone, Debug, HashStable, TypeVisitable)] +#[derive(Debug, HashStable, TypeVisitable)] pub struct Pat<'tcx> { pub ty: Ty<'tcx>, pub span: Span, @@ -726,7 +739,7 @@ impl<'tcx> Pat<'tcx> { } } -#[derive(Clone, Debug, HashStable, TypeVisitable)] +#[derive(Debug, HashStable, TypeVisitable)] pub struct Ascription<'tcx> { pub annotation: CanonicalUserTypeAnnotation<'tcx>, /// Variance to use when relating the `user_ty` to the **type of the value being @@ -750,7 +763,7 @@ pub struct Ascription<'tcx> { pub variance: ty::Variance, } -#[derive(Clone, Debug, HashStable, TypeVisitable)] +#[derive(Debug, HashStable, TypeVisitable)] pub enum PatKind<'tcx> { /// A wildcard pattern: `_`. Wild, diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 64bac12b266..2aeb13942a3 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -136,6 +136,9 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( | ValueTypeAscription { source, user_ty: _, user_ty_span: _ } => { visitor.visit_expr(&visitor.thir()[source]) } + PlaceUnwrapUnsafeBinder { source } + | ValueUnwrapUnsafeBinder { source } + | WrapUnsafeBinder { source } => visitor.visit_expr(&visitor.thir()[source]), Closure(box ClosureExpr { closure_id: _, args: _, diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 8a9110f842a..28a6eba75aa 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -428,7 +428,7 @@ pub enum IsConstable { Ctor, } -crate::TrivialTypeTraversalAndLiftImpls! { +TrivialTypeTraversalAndLiftImpls! { IsConstable, } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 31055276422..d77fb1cc91e 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -5,7 +5,6 @@ use rustc_error_messages::MultiSpan; use rustc_macros::HashStable; use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo}; -use crate::mir::interpret::Scalar; use crate::ty::{self, Ty, TyCtxt}; mod int; @@ -110,8 +109,8 @@ impl<'tcx> Const<'tcx> { } #[inline] - pub fn new_value(tcx: TyCtxt<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Value(ty, val)) + pub fn new_value(tcx: TyCtxt<'tcx>, valtree: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Value(ty::Value { ty, valtree })) } #[inline] @@ -214,47 +213,31 @@ impl<'tcx> Const<'tcx> { Self::from_bits(tcx, n as u128, ty::TypingEnv::fully_monomorphized(), tcx.types.usize) } - /// Panics if self.kind != ty::ConstKind::Value - pub fn to_valtree(self) -> (ty::ValTree<'tcx>, Ty<'tcx>) { + /// Panics if `self.kind != ty::ConstKind::Value`. + pub fn to_value(self) -> ty::Value<'tcx> { match self.kind() { - ty::ConstKind::Value(ty, valtree) => (valtree, ty), + ty::ConstKind::Value(cv) => cv, _ => bug!("expected ConstKind::Value, got {:?}", self.kind()), } } - /// Attempts to convert to a `ValTree` - pub fn try_to_valtree(self) -> Option<(ty::ValTree<'tcx>, Ty<'tcx>)> { + /// Attempts to convert to a value. + /// + /// Note that this does not evaluate the constant. + pub fn try_to_value(self) -> Option<ty::Value<'tcx>> { match self.kind() { - ty::ConstKind::Value(ty, valtree) => Some((valtree, ty)), + ty::ConstKind::Value(cv) => Some(cv), _ => None, } } - #[inline] - pub fn try_to_scalar(self) -> Option<(Scalar, Ty<'tcx>)> { - let (valtree, ty) = self.try_to_valtree()?; - Some((valtree.try_to_scalar()?, ty)) - } - - pub fn try_to_bool(self) -> Option<bool> { - self.try_to_valtree()?.0.try_to_scalar_int()?.try_to_bool().ok() - } - + /// Convenience method to extract the value of a usize constant, + /// useful to get the length of an array type. + /// + /// Note that this does not evaluate the constant. #[inline] pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> { - self.try_to_valtree()?.0.try_to_target_usize(tcx) - } - - /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of - /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it - /// contains const generic parameters or pointers). - #[inline] - pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option<u128> { - let (scalar, ty) = self.try_to_scalar()?; - let scalar = scalar.try_to_scalar_int().ok()?; - let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(ty); - let size = tcx.layout_of(input).ok()?.size; - Some(scalar.to_bits(size)) + self.try_to_value()?.try_to_target_usize(tcx) } pub fn is_ct_infer(self) -> bool { diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 9f9bf41c335..d914b7576dc 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -1,11 +1,9 @@ -use rustc_macros::{HashStable, TyDecodable, TyEncodable}; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use super::ScalarInt; use crate::mir::interpret::Scalar; use crate::ty::{self, Ty, TyCtxt}; -#[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq)] -#[derive(HashStable)] /// This datastructure is used to represent the value of constants used in the type system. /// /// We explicitly choose a different datastructure from the way values are processed within @@ -18,6 +16,8 @@ use crate::ty::{self, Ty, TyCtxt}; /// /// `ValTree` does not have this problem with representation, as it only contains integers or /// lists of (nested) `ValTree`. +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] +#[derive(HashStable, TyEncodable, TyDecodable)] pub enum ValTree<'tcx> { /// integers, `bool`, `char` are represented as scalars. /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values @@ -79,10 +79,6 @@ impl<'tcx> ValTree<'tcx> { } } - pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> { - self.try_to_scalar_int().map(|s| s.to_target_usize(tcx)) - } - /// Get the values inside the ValTree as a slice of bytes. This only works for /// constants with types &str, &[u8], or [u8; _]. pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx [u8]> { @@ -107,3 +103,54 @@ impl<'tcx> ValTree<'tcx> { ) } } + +/// A type-level constant value. +/// +/// Represents a typed, fully evaluated constant. +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] +#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)] +pub struct Value<'tcx> { + pub ty: Ty<'tcx>, + pub valtree: ValTree<'tcx>, +} + +impl<'tcx> Value<'tcx> { + /// Attempts to extract the raw bits from the constant. + /// + /// Fails if the value can't be represented as bits (e.g. because it is a reference + /// or an aggregate). + #[inline] + pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option<u128> { + let (ty::Bool | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Float(_)) = self.ty.kind() else { + return None; + }; + let scalar = self.valtree.try_to_scalar_int()?; + let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(self.ty); + let size = tcx.layout_of(input).ok()?.size; + Some(scalar.to_bits(size)) + } + + pub fn try_to_bool(self) -> Option<bool> { + if !self.ty.is_bool() { + return None; + } + self.valtree.try_to_scalar_int()?.try_to_bool().ok() + } + + pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> { + if !self.ty.is_usize() { + return None; + } + self.valtree.try_to_scalar_int().map(|s| s.to_target_usize(tcx)) + } +} + +impl<'tcx> rustc_type_ir::inherent::ValueConst<TyCtxt<'tcx>> for Value<'tcx> { + fn ty(self) -> Ty<'tcx> { + self.ty + } + + fn valtree(self) -> ValTree<'tcx> { + self.valtree + } +} diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0c22c056dab..522a553d243 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -142,10 +142,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type ParamConst = ty::ParamConst; type BoundConst = ty::BoundVar; - type ValueConst = ty::ValTree<'tcx>; + type ValueConst = ty::Value<'tcx>; type ExprConst = ty::Expr<'tcx>; - type Region = Region<'tcx>; + type ValTree = ty::ValTree<'tcx>; + type Region = Region<'tcx>; type EarlyParamRegion = ty::EarlyParamRegion; type LateParamRegion = ty::LateParamRegion; type BoundRegion = ty::BoundRegion; @@ -1118,15 +1119,18 @@ impl<'tcx> CommonConsts<'tcx> { }; CommonConsts { - unit: mk_const(ty::ConstKind::Value(types.unit, ty::ValTree::zst())), - true_: mk_const(ty::ConstKind::Value( - types.bool, - ty::ValTree::Leaf(ty::ScalarInt::TRUE), - )), - false_: mk_const(ty::ConstKind::Value( - types.bool, - ty::ValTree::Leaf(ty::ScalarInt::FALSE), - )), + unit: mk_const(ty::ConstKind::Value(ty::Value { + ty: types.unit, + valtree: ty::ValTree::zst(), + })), + true_: mk_const(ty::ConstKind::Value(ty::Value { + ty: types.bool, + valtree: ty::ValTree::Leaf(ty::ScalarInt::TRUE), + })), + false_: mk_const(ty::ConstKind::Value(ty::Value { + ty: types.bool, + valtree: ty::ValTree::Leaf(ty::ScalarInt::FALSE), + })), } } } @@ -1953,7 +1957,7 @@ impl<'tcx> TyCtxt<'tcx> { ) -> &'tcx rustc_hir::def_path_hash_map::DefPathHashMap { // Create a dependency to the crate to be sure we re-execute this when the amount of // definitions change. - self.ensure().hir_crate(()); + self.ensure_ok().hir_crate(()); // Freeze definitions once we start iterating on them, to prevent adding new ones // while iterating. If some query needs to add definitions, it should be `ensure`d above. self.untracked.definitions.freeze().def_path_hash_to_def_index_map() diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index b4b66a8133a..cb218a27e62 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -5,7 +5,7 @@ use std::ops::ControlFlow; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{ - Applicability, Diag, DiagArgValue, IntoDiagArg, into_diag_arg_using_display, pluralize, + Applicability, Diag, DiagArgValue, IntoDiagArg, into_diag_arg_using_display, listify, pluralize, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -362,11 +362,8 @@ pub fn suggest_constraining_type_params<'a>( let n = trait_names.len(); let stable = if all_stable { "" } else { "unstable " }; let trait_ = if all_known { format!("trait{}", pluralize!(n)) } else { String::new() }; - format!("{stable}{trait_}{}", match &trait_names[..] { - [t] => format!(" {t}"), - [ts @ .., last] => format!(" {} and {last}", ts.join(", ")), - [] => return false, - },) + let Some(trait_names) = listify(&trait_names, |n| n.to_string()) else { return false }; + format!("{stable}{trait_} {trait_names}") } else { // We're more explicit when there's a mix of stable and unstable traits. let mut trait_names = constraints @@ -378,10 +375,9 @@ pub fn suggest_constraining_type_params<'a>( .collect::<Vec<_>>(); trait_names.sort(); trait_names.dedup(); - match &trait_names[..] { - [t] => t.to_string(), - [ts @ .., last] => format!("{} and {last}", ts.join(", ")), - [] => return false, + match listify(&trait_names, |t| t.to_string()) { + Some(names) => names, + None => return false, } }; let constraint = constraint.join(" + "); diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 35fbaa99569..8c1991ddb36 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -10,8 +10,8 @@ use rustc_hir::def::{CtorOf, DefKind}; use rustc_macros::extension; pub use rustc_type_ir::error::ExpectedFound; -use crate::ty::print::{FmtPrinter, PrettyPrinter, with_forced_trimmed_paths}; -use crate::ty::{self, Ty, TyCtxt}; +use crate::ty::print::{FmtPrinter, Print, with_forced_trimmed_paths}; +use crate::ty::{self, Lift, Ty, TyCtxt}; pub type TypeError<'tcx> = rustc_type_ir::error::TypeError<TyCtxt<'tcx>>; @@ -159,8 +159,8 @@ impl<'tcx> Ty<'tcx> { ty::Error(_) => "type error".into(), _ => { let width = tcx.sess.diagnostic_width(); - let length_limit = std::cmp::max(width / 4, 15); - format!("`{}`", tcx.ty_string_with_limit(self, length_limit)).into() + let length_limit = std::cmp::max(width / 4, 40); + format!("`{}`", tcx.string_with_limit(self, length_limit)).into() } } } @@ -213,10 +213,14 @@ impl<'tcx> Ty<'tcx> { } impl<'tcx> TyCtxt<'tcx> { - pub fn ty_string_with_limit(self, ty: Ty<'tcx>, length_limit: usize) -> String { + pub fn string_with_limit<'a, T>(self, p: T, length_limit: usize) -> String + where + T: Print<'tcx, FmtPrinter<'a, 'tcx>> + Lift<TyCtxt<'tcx>> + Copy, + <T as Lift<TyCtxt<'tcx>>>::Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>, + { let mut type_limit = 50; let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |cx| { - cx.pretty_print_type(ty) + self.lift(p).expect("could not lift for printing").print(cx) }) .expect("could not write to `String`"); if regular.len() <= length_limit { @@ -231,7 +235,10 @@ impl<'tcx> TyCtxt<'tcx> { hir::def::Namespace::TypeNS, rustc_session::Limit(type_limit), ); - cx.pretty_print_type(ty).expect("could not write to `String`"); + self.lift(p) + .expect("could not lift for printing") + .print(&mut cx) + .expect("could not print type"); cx.into_buffer() }); if short.len() <= length_limit || type_limit == 0 { @@ -242,9 +249,17 @@ impl<'tcx> TyCtxt<'tcx> { short } - pub fn short_ty_string(self, ty: Ty<'tcx>, path: &mut Option<PathBuf>) -> String { + /// When calling this after a `Diag` is constructed, the preferred way of doing so is + /// `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that keeps + /// the existence of a "long type" anywhere in the diagnostic, so the note telling the user + /// where we wrote the file to is only printed once. + pub fn short_string<'a, T>(self, p: T, path: &mut Option<PathBuf>) -> String + where + T: Print<'tcx, FmtPrinter<'a, 'tcx>> + Lift<TyCtxt<'tcx>> + Copy + Hash, + <T as Lift<TyCtxt<'tcx>>>::Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>, + { let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |cx| { - cx.pretty_print_type(ty) + self.lift(p).expect("could not lift for printing").print(cx) }) .expect("could not write to `String`"); @@ -257,13 +272,13 @@ impl<'tcx> TyCtxt<'tcx> { if regular.len() <= width * 2 / 3 { return regular; } - let short = self.ty_string_with_limit(ty, length_limit); + let short = self.string_with_limit(p, length_limit); if regular == short { return regular; } // Ensure we create an unique file for the type passed in when we create a file. let mut s = DefaultHasher::new(); - ty.hash(&mut s); + p.hash(&mut s); let hash = s.finish(); *path = Some(path.take().unwrap_or_else(|| { self.output_filenames(()).temp_path_ext(&format!("long-type-{hash}.txt"), None) diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 0af57f636aa..ec0498b168c 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -381,7 +381,7 @@ impl FlagComputation { self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER); self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } - ty::ConstKind::Value(ty, _) => self.add_ty(ty), + ty::ConstKind::Value(cv) => self.add_ty(cv.ty), ty::ConstKind::Expr(e) => self.add_args(e.args()), ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR), } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 0d41a1d7dbf..3ced64b5b80 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -504,6 +504,9 @@ impl<'tcx> SizeSkeleton<'tcx> { } } + // Pattern types are always the same size as their base. + ty::Pat(base, _) => SizeSkeleton::compute(base, tcx, typing_env), + _ => Err(err), } } @@ -855,7 +858,12 @@ where } let mk_dyn_vtable = |principal: Option<ty::PolyExistentialTraitRef<'tcx>>| { - let min_count = ty::vtable_min_entries(tcx, principal); + let min_count = ty::vtable_min_entries( + tcx, + principal.map(|principal| { + tcx.instantiate_bound_regions_with_erased(principal) + }), + ); Ty::new_imm_ref( tcx, tcx.lifetimes.re_static, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 8cd632790a8..88eea6101b5 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -60,7 +60,7 @@ pub use self::closure::{ place_to_string_for_capture, }; pub use self::consts::{ - Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, + Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, Value, }; pub use self::context::{ CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 6b6c6f3c72f..8eaf0a58f70 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -101,6 +101,7 @@ trivially_parameterized_over_tcx! { rustc_session::cstore::ForeignModule, rustc_session::cstore::LinkagePreference, rustc_session::cstore::NativeLib, + rustc_session::config::TargetModifier, rustc_span::ExpnData, rustc_span::ExpnHash, rustc_span::ExpnId, diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 72f353f06ff..dc2040aa5cf 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -105,6 +105,10 @@ pub trait Printer<'tcx>: Sized { args: &[GenericArg<'tcx>], ) -> Result<(), PrintError>; + fn should_truncate(&mut self) -> bool { + false + } + // Defaults (should not be overridden): #[instrument(skip(self), level = "debug")] diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 027a4315b4b..6c8591dae89 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -865,7 +865,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { p!(write("{{")); if !self.tcx().sess.verbose_internals() { p!("coroutine witness"); - // FIXME(eddyb) should use `def_span`. if let Some(did) = did.as_local() { let span = self.tcx().def_span(did); p!(write( @@ -887,26 +886,30 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { p!(write("{{")); if !self.should_print_verbose() { p!(write("closure")); - // FIXME(eddyb) should use `def_span`. - if let Some(did) = did.as_local() { - if self.tcx().sess.opts.unstable_opts.span_free_formats { - p!("@", print_def_path(did.to_def_id(), args)); - } else { - let span = self.tcx().def_span(did); - let preference = if with_forced_trimmed_paths() { - FileNameDisplayPreference::Short + if self.should_truncate() { + write!(self, "@...}}")?; + return Ok(()); + } else { + if let Some(did) = did.as_local() { + if self.tcx().sess.opts.unstable_opts.span_free_formats { + p!("@", print_def_path(did.to_def_id(), args)); } else { - FileNameDisplayPreference::Remapped - }; - p!(write( - "@{}", - // This may end up in stderr diagnostics but it may also be emitted - // into MIR. Hence we use the remapped path if available - self.tcx().sess.source_map().span_to_string(span, preference) - )); + let span = self.tcx().def_span(did); + let preference = if with_forced_trimmed_paths() { + FileNameDisplayPreference::Short + } else { + FileNameDisplayPreference::Remapped + }; + p!(write( + "@{}", + // This may end up in stderr diagnostics but it may also be emitted + // into MIR. Hence we use the remapped path if available + self.tcx().sess.source_map().span_to_string(span, preference) + )); + } + } else { + p!(write("@"), print_def_path(did, args)); } - } else { - p!(write("@"), print_def_path(did, args)); } } else { p!(print_def_path(did, args)); @@ -942,7 +945,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { "coroutine from coroutine-closure should have CoroutineSource::Closure" ), } - // FIXME(eddyb) should use `def_span`. if let Some(did) = did.as_local() { if self.tcx().sess.opts.unstable_opts.span_free_formats { p!("@", print_def_path(did.to_def_id(), args)); @@ -1484,8 +1486,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { _ => write!(self, "_")?, }, ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)), - ty::ConstKind::Value(ty, value) => { - return self.pretty_print_const_valtree(value, ty, print_ty); + ty::ConstKind::Value(cv) => { + return self.pretty_print_const_valtree(cv.valtree, cv.ty, print_ty); } ty::ConstKind::Bound(debruijn, bound_var) => { @@ -1637,33 +1639,32 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { match ty.kind() { // Byte strings (&[u8; N]) ty::Ref(_, inner, _) => { - if let ty::Array(elem, len) = inner.kind() { - if let ty::Uint(ty::UintTy::U8) = elem.kind() { - if let ty::ConstKind::Value(_, ty::ValTree::Leaf(int)) = len.kind() { - match self.tcx().try_get_global_alloc(prov.alloc_id()) { - Some(GlobalAlloc::Memory(alloc)) => { - let len = int.to_bits(self.tcx().data_layout.pointer_size); - let range = - AllocRange { start: offset, size: Size::from_bytes(len) }; - if let Ok(byte_str) = - alloc.inner().get_bytes_strip_provenance(&self.tcx(), range) - { - p!(pretty_print_byte_str(byte_str)) - } else { - p!("<too short allocation>") - } - } - // FIXME: for statics, vtables, and functions, we could in principle print more detail. - Some(GlobalAlloc::Static(def_id)) => { - p!(write("<static({:?})>", def_id)) - } - Some(GlobalAlloc::Function { .. }) => p!("<function>"), - Some(GlobalAlloc::VTable(..)) => p!("<vtable>"), - None => p!("<dangling pointer>"), + if let ty::Array(elem, len) = inner.kind() + && let ty::Uint(ty::UintTy::U8) = elem.kind() + && let ty::ConstKind::Value(cv) = len.kind() + && let ty::ValTree::Leaf(int) = cv.valtree + { + match self.tcx().try_get_global_alloc(prov.alloc_id()) { + Some(GlobalAlloc::Memory(alloc)) => { + let len = int.to_bits(self.tcx().data_layout.pointer_size); + let range = AllocRange { start: offset, size: Size::from_bytes(len) }; + if let Ok(byte_str) = + alloc.inner().get_bytes_strip_provenance(&self.tcx(), range) + { + p!(pretty_print_byte_str(byte_str)) + } else { + p!("<too short allocation>") } - return Ok(()); } + // FIXME: for statics, vtables, and functions, we could in principle print more detail. + Some(GlobalAlloc::Static(def_id)) => { + p!(write("<static({:?})>", def_id)) + } + Some(GlobalAlloc::Function { .. }) => p!("<function>"), + Some(GlobalAlloc::VTable(..)) => p!("<vtable>"), + None => p!("<dangling pointer>"), } + return Ok(()); } } ty::FnPtr(..) => { @@ -1786,6 +1787,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { Ok(()) } + // FIXME(valtrees): Accept `ty::Value` instead of `Ty` and `ty::ValTree` separately. fn pretty_print_const_valtree( &mut self, valtree: ty::ValTree<'tcx>, @@ -1994,7 +1996,6 @@ pub struct FmtPrinterData<'a, 'tcx> { binder_depth: usize, printed_type_count: usize, type_length_limit: Limit, - truncated: bool, pub region_highlight_mode: RegionHighlightMode<'tcx>, @@ -2046,7 +2047,6 @@ impl<'a, 'tcx> FmtPrinter<'a, 'tcx> { binder_depth: 0, printed_type_count: 0, type_length_limit, - truncated: false, region_highlight_mode: RegionHighlightMode::default(), ty_infer_name_resolver: None, const_infer_name_resolver: None, @@ -2183,16 +2183,49 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { } fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> { - if self.type_length_limit.value_within_limit(self.printed_type_count) { - self.printed_type_count += 1; - self.pretty_print_type(ty) - } else { - self.truncated = true; - write!(self, "...")?; - Ok(()) + match ty.kind() { + ty::Tuple(tys) if tys.len() == 0 && self.should_truncate() => { + // Don't truncate `()`. + self.printed_type_count += 1; + self.pretty_print_type(ty) + } + ty::Adt(..) + | ty::Foreign(_) + | ty::Pat(..) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::UnsafeBinder(..) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Tuple(_) + | ty::Alias(..) + | ty::Param(_) + | ty::Bound(..) + | ty::Placeholder(_) + | ty::Error(_) + if self.should_truncate() => + { + // We only truncate types that we know are likely to be much longer than 3 chars. + // There's no point in replacing `i32` or `!`. + write!(self, "...")?; + Ok(()) + } + _ => { + self.printed_type_count += 1; + self.pretty_print_type(ty) + } } } + fn should_truncate(&mut self) -> bool { + !self.type_length_limit.value_within_limit(self.printed_type_count) + } + fn print_dyn_existential( &mut self, predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, @@ -2942,7 +2975,7 @@ impl<'tcx> ty::TraitPredicate<'tcx> { } } -#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)] +#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift, Hash)] pub struct TraitPredPrintWithBoundConstness<'tcx>( ty::TraitPredicate<'tcx>, Option<ty::BoundConstness>, diff --git a/compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs b/compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs index cbc02097d82..568e504b940 100644 --- a/compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs +++ b/compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs @@ -4,7 +4,7 @@ use crate::ty::{self, ExistentialPredicateStableCmpExt, TyCtxt}; impl<'tcx> TyCtxt<'tcx> { /// Given a `def_id` of a trait or impl method, compute whether that method needs to - /// have an RPITIT shim applied to it for it to be object safe. If so, return the + /// have an RPITIT shim applied to it for it to be dyn compatible. If so, return the /// `def_id` of the RPITIT, and also the args of trait method that returns the RPITIT. /// /// NOTE that these args are not, in general, the same as than the RPITIT's args. They diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 68cb56f3583..9e9de4fb064 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -162,16 +162,15 @@ impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> { impl<'tcx> fmt::Debug for ty::Const<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // If this is a value, we spend some effort to make it look nice. - if let ConstKind::Value(_, _) = self.kind() { + if let ConstKind::Value(_) = self.kind() { return ty::tls::with(move |tcx| { - // Somehow trying to lift the valtree results in lifetime errors, so we lift the - // entire constant. + // ValTrees aren't interned, so we lift the entire constant. let lifted = tcx.lift(*self).unwrap(); - let ConstKind::Value(ty, valtree) = lifted.kind() else { + let ConstKind::Value(cv) = lifted.kind() else { bug!("we checked that this is a valtree") }; let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); - cx.pretty_print_const_valtree(valtree, ty, /*print_ty*/ true)?; + cx.pretty_print_const_valtree(cv.valtree, cv.ty, /*print_ty*/ true)?; f.write_str(&cx.into_buffer()) }); } @@ -589,9 +588,7 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> { } ConstKind::Placeholder(p) => ConstKind::Placeholder(p.try_fold_with(folder)?), ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.try_fold_with(folder)?), - ConstKind::Value(t, v) => { - ConstKind::Value(t.try_fold_with(folder)?, v.try_fold_with(folder)?) - } + ConstKind::Value(v) => ConstKind::Value(v.try_fold_with(folder)?), ConstKind::Error(e) => ConstKind::Error(e.try_fold_with(folder)?), ConstKind::Expr(e) => ConstKind::Expr(e.try_fold_with(folder)?), }; @@ -610,10 +607,7 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> { } ConstKind::Placeholder(p) => p.visit_with(visitor), ConstKind::Unevaluated(uv) => uv.visit_with(visitor), - ConstKind::Value(t, v) => { - try_visit!(t.visit_with(visitor)); - v.visit_with(visitor) - } + ConstKind::Value(v) => v.visit_with(visitor), ConstKind::Error(e) => e.visit_with(visitor), ConstKind::Expr(e) => e.visit_with(visitor), } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 7d5e5c2e823..318bd0c7ec0 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -367,7 +367,7 @@ impl<'tcx> TyCtxt<'tcx> { validate: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>, ) -> Option<ty::Destructor> { let drop_trait = self.lang_items().drop_trait()?; - self.ensure().coherent_trait(drop_trait).ok()?; + self.ensure_ok().coherent_trait(drop_trait).ok()?; let ty = self.type_of(adt_did).instantiate_identity(); let mut dtor_candidate = None; @@ -404,7 +404,7 @@ impl<'tcx> TyCtxt<'tcx> { validate: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>, ) -> Option<ty::AsyncDestructor> { let async_drop_trait = self.lang_items().async_drop_trait()?; - self.ensure().coherent_trait(async_drop_trait).ok()?; + self.ensure_ok().coherent_trait(async_drop_trait).ok()?; let ty = self.type_of(adt_did).instantiate_identity(); let mut dtor_candidate = None; diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index 455bd16ff8c..6c9e0e7c0eb 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -7,7 +7,7 @@ use rustc_type_ir::elaborate; use crate::mir::interpret::{ AllocId, AllocInit, Allocation, CTFE_ALLOC_SALT, Pointer, Scalar, alloc_range, }; -use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt}; +use crate::ty::{self, Instance, TraitRef, Ty, TyCtxt}; #[derive(Clone, Copy, PartialEq, HashStable)] pub enum VtblEntry<'tcx> { @@ -22,7 +22,7 @@ pub enum VtblEntry<'tcx> { /// dispatchable associated function Method(Instance<'tcx>), /// pointer to a separate supertrait vtable, can be used by trait upcasting coercion - TraitVPtr(PolyTraitRef<'tcx>), + TraitVPtr(TraitRef<'tcx>), } impl<'tcx> fmt::Debug for VtblEntry<'tcx> { @@ -59,7 +59,7 @@ pub const COMMON_VTABLE_ENTRIES_ALIGN: usize = 2; // function is an accurate approximation. We verify this when actually computing the vtable below. pub(crate) fn vtable_min_entries<'tcx>( tcx: TyCtxt<'tcx>, - trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, + trait_ref: Option<ty::ExistentialTraitRef<'tcx>>, ) -> usize { let mut count = TyCtxt::COMMON_VTABLE_ENTRIES.len(); let Some(trait_ref) = trait_ref else { @@ -67,7 +67,7 @@ pub(crate) fn vtable_min_entries<'tcx>( }; // This includes self in supertraits. - for def_id in elaborate::supertrait_def_ids(tcx, trait_ref.def_id()) { + for def_id in elaborate::supertrait_def_ids(tcx, trait_ref.def_id) { count += tcx.own_existential_vtable_entries(def_id).len(); } @@ -83,7 +83,7 @@ pub(crate) fn vtable_min_entries<'tcx>( /// initial contents.) pub(super) fn vtable_allocation_provider<'tcx>( tcx: TyCtxt<'tcx>, - key: (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), + key: (Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>), ) -> AllocId { let (ty, poly_trait_ref) = key; @@ -118,7 +118,7 @@ pub(super) fn vtable_allocation_provider<'tcx>( for (idx, entry) in vtable_entries.iter().enumerate() { let idx: u64 = u64::try_from(idx).unwrap(); - let scalar = match entry { + let scalar = match *entry { VtblEntry::MetadataDropInPlace => { if ty.needs_drop(tcx, ty::TypingEnv::fully_monomorphized()) { let instance = ty::Instance::resolve_drop_in_place(tcx, ty); @@ -134,13 +134,12 @@ pub(super) fn vtable_allocation_provider<'tcx>( VtblEntry::Vacant => continue, VtblEntry::Method(instance) => { // Prepare the fn ptr we write into the vtable. - let fn_alloc_id = tcx.reserve_and_set_fn_alloc(*instance, CTFE_ALLOC_SALT); + let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance, CTFE_ALLOC_SALT); let fn_ptr = Pointer::from(fn_alloc_id); Scalar::from_pointer(fn_ptr, &tcx) } VtblEntry::TraitVPtr(trait_ref) => { - let super_trait_ref = trait_ref - .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)); + let super_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref); let supertrait_alloc_id = tcx.vtable_allocation((ty, Some(super_trait_ref))); let vptr = Pointer::from(supertrait_alloc_id); Scalar::from_pointer(vptr, &tcx) diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 2dcba8c2f82..3e8a3d1a289 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -206,7 +206,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) | ty::ConstKind::Bound(..) | ty::ConstKind::Error(_) => {} - ty::ConstKind::Value(ty, _) => stack.push(ty.into()), + ty::ConstKind::Value(cv) => stack.push(cv.ty.into()), ty::ConstKind::Expr(expr) => stack.extend(expr.args().iter().rev()), ty::ConstKind::Unevaluated(ct) => { diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs index b99336c2c85..7dda68b8393 100644 --- a/compiler/rustc_middle/src/util/bug.rs +++ b/compiler/rustc_middle/src/util/bug.rs @@ -1,4 +1,4 @@ -// These functions are used by macro expansion for bug! and span_bug! +// These functions are used by macro expansion for `bug!` and `span_bug!`. use std::fmt; use std::panic::{Location, panic_any}; @@ -8,15 +8,15 @@ use rustc_span::Span; use crate::ty::{TyCtxt, tls}; +// This wrapper makes for more compact code at callsites than calling `opt_span_buf_fmt` directly. #[cold] #[inline(never)] #[track_caller] pub fn bug_fmt(args: fmt::Arguments<'_>) -> ! { - // this wrapper mostly exists so I don't have to write a fully - // qualified path of None::<Span> inside the bug!() macro definition opt_span_bug_fmt(None::<Span>, args, Location::caller()); } +// This wrapper makes for more compact code at callsites than calling `opt_span_buf_fmt` directly. #[cold] #[inline(never)] #[track_caller] diff --git a/compiler/rustc_middle/src/util/common.rs b/compiler/rustc_middle/src/util/common.rs deleted file mode 100644 index 223b2b3bfe4..00000000000 --- a/compiler/rustc_middle/src/util/common.rs +++ /dev/null @@ -1,22 +0,0 @@ -#[cfg(test)] -mod tests; - -pub fn to_readable_str(mut val: usize) -> String { - let mut groups = vec![]; - loop { - let group = val % 1000; - - val /= 1000; - - if val == 0 { - groups.push(group.to_string()); - break; - } else { - groups.push(format!("{group:03}")); - } - } - - groups.reverse(); - - groups.join("_") -} diff --git a/compiler/rustc_middle/src/util/common/tests.rs b/compiler/rustc_middle/src/util/common/tests.rs deleted file mode 100644 index 9a9fb203c62..00000000000 --- a/compiler/rustc_middle/src/util/common/tests.rs +++ /dev/null @@ -1,14 +0,0 @@ -use super::*; - -#[test] -fn test_to_readable_str() { - assert_eq!("0", to_readable_str(0)); - assert_eq!("1", to_readable_str(1)); - assert_eq!("99", to_readable_str(99)); - assert_eq!("999", to_readable_str(999)); - assert_eq!("1_000", to_readable_str(1_000)); - assert_eq!("1_001", to_readable_str(1_001)); - assert_eq!("999_999", to_readable_str(999_999)); - assert_eq!("1_000_000", to_readable_str(1_000_000)); - assert_eq!("1_234_567", to_readable_str(1_234_567)); -} diff --git a/compiler/rustc_middle/src/util/find_self_call.rs b/compiler/rustc_middle/src/util/find_self_call.rs deleted file mode 100644 index 0fdd3520738..00000000000 --- a/compiler/rustc_middle/src/util/find_self_call.rs +++ /dev/null @@ -1,47 +0,0 @@ -use rustc_span::def_id::DefId; -use rustc_span::source_map::Spanned; -use tracing::debug; - -use crate::mir::*; -use crate::ty::{self, GenericArgsRef, TyCtxt}; - -/// Checks if the specified `local` is used as the `self` parameter of a method call -/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is -/// returned. -pub fn find_self_call<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - local: Local, - block: BasicBlock, -) -> Option<(DefId, GenericArgsRef<'tcx>)> { - debug!("find_self_call(local={:?}): terminator={:?}", local, body[block].terminator); - if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) = - &body[block].terminator - && let Operand::Constant(box ConstOperand { const_, .. }) = func - && let ty::FnDef(def_id, fn_args) = *const_.ty().kind() - && let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) = - tcx.opt_associated_item(def_id) - && let [Spanned { node: Operand::Move(self_place) | Operand::Copy(self_place), .. }, ..] = - **args - { - if self_place.as_local() == Some(local) { - return Some((def_id, fn_args)); - } - - // Handle the case where `self_place` gets reborrowed. - // This happens when the receiver is `&T`. - for stmt in &body[block].statements { - if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind - && let Some(reborrow_local) = place.as_local() - && self_place.as_local() == Some(reborrow_local) - && let Rvalue::Ref(_, _, deref_place) = rvalue - && let PlaceRef { local: deref_local, projection: [ProjectionElem::Deref] } = - deref_place.as_ref() - && deref_local == local - { - return Some((def_id, fn_args)); - } - } - } - None -} diff --git a/compiler/rustc_middle/src/util/mod.rs b/compiler/rustc_middle/src/util/mod.rs index 097a868191c..8c875007b7f 100644 --- a/compiler/rustc_middle/src/util/mod.rs +++ b/compiler/rustc_middle/src/util/mod.rs @@ -1,8 +1,4 @@ pub mod bug; -pub mod common; -pub mod find_self_call; - -pub use find_self_call::find_self_call; #[derive(Default, Copy, Clone)] pub struct Providers { diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 053775b4937..3cf3c332893 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -25,8 +25,6 @@ mir_build_borrow_of_moved_value = borrow of moved value .occurs_because_label = move occurs because `{$name}` has type `{$ty}`, which does not implement the `Copy` trait .value_borrowed_label = value borrowed here after move .suggestion = borrow this binding in the pattern to avoid moving the value - .full_type_name = the full type name has been written to '{$path}' - .consider_verbose = consider using `--verbose` to print the full type name to the console mir_build_call_to_deprecated_safe_fn_requires_unsafe = call to deprecated safe function `{$function}` is unsafe and requires unsafe block @@ -361,6 +359,18 @@ mir_build_unreachable_pattern = unreachable pattern .unreachable_pattern_let_binding = there is a binding of the same name; if you meant to pattern match against the value of that binding, that is a feature of constants that is not available for `let` bindings .suggestion = remove the match arm +mir_build_unsafe_binder_cast_requires_unsafe = + unsafe binder cast is unsafe and requires unsafe block + .label = unsafe binder cast + .note = casting to or from an `unsafe<...>` binder type is unsafe since it erases lifetime + information that may be required to uphold safety guarantees of a type + +mir_build_unsafe_binder_cast_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = + unsafe binder cast is unsafe and requires unsafe block or unsafe fn + .label = unsafe binder cast + .note = casting to or from an `unsafe<...>` binder type is unsafe since it erases lifetime + information that may be required to uphold safety guarantees of a type + mir_build_unsafe_field_requires_unsafe = use of unsafe field is unsafe and requires unsafe block .note = unsafe fields may carry library invariants diff --git a/compiler/rustc_mir_build/src/builder/custom/mod.rs b/compiler/rustc_mir_build/src/builder/custom/mod.rs index ca2e1dd7a1a..bfc16816e2e 100644 --- a/compiler/rustc_mir_build/src/builder/custom/mod.rs +++ b/compiler/rustc_mir_build/src/builder/custom/mod.rs @@ -6,7 +6,7 @@ //! present, and if so we branch off into this module, which implements the attribute by //! implementing a custom lowering from THIR to MIR. //! -//! The result of this lowering is returned "normally" from the `build_mir` hook, with the only +//! The result of this lowering is returned "normally" from `build_mir`, with the only //! notable difference being that the `injected` field in the body is set. Various components of the //! MIR pipeline, like borrowck and the pass manager will then consult this field (via //! `body.should_skip()`) to skip the parts of the MIR pipeline that precede the MIR phase the user diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index 0086775e9f4..482f1e3840b 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -105,7 +105,8 @@ fn convert_to_hir_projections_and_truncate_for_capture( ProjectionElem::OpaqueCast(_) | ProjectionElem::Subtype(..) => continue, ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } => { + | ProjectionElem::Subslice { .. } + | ProjectionElem::UnwrapUnsafeBinder(_) => { // We don't capture array-access projections. // We can stop here as arrays are captured completely. break; @@ -523,6 +524,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(PlaceBuilder::from(temp)) } + ExprKind::PlaceUnwrapUnsafeBinder { source } => { + let place_builder = unpack!( + block = this.expr_as_place(block, source, mutability, fake_borrow_temps,) + ); + block.and(place_builder.project(PlaceElem::UnwrapUnsafeBinder(expr.ty))) + } + ExprKind::ValueUnwrapUnsafeBinder { source } => { + let source_expr = &this.thir[source]; + let temp = unpack!( + block = this.as_temp(block, source_expr.temp_lifetime, source, mutability) + ); + block.and(PlaceBuilder::from(temp).project(PlaceElem::UnwrapUnsafeBinder(expr.ty))) + } + ExprKind::Array { .. } | ExprKind::Tuple { .. } | ExprKind::Adt { .. } @@ -560,7 +575,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::OffsetOf { .. } | ExprKind::Yield { .. } | ExprKind::ThreadLocalRef(_) - | ExprKind::Call { .. } => { + | ExprKind::Call { .. } + | ExprKind::WrapUnsafeBinder { .. } => { // these are not places, so we need to make a temporary. debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Place))); let temp = @@ -776,7 +792,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ProjectionElem::OpaqueCast(..) | ProjectionElem::Subtype(..) | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } => (), + | ProjectionElem::Subslice { .. } + | ProjectionElem::UnwrapUnsafeBinder(_) => (), } } } diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs index 9961c2488ef..e7713f0a1d6 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs @@ -508,6 +508,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(Rvalue::Use(Operand::Constant(Box::new(constant)))) } + ExprKind::WrapUnsafeBinder { source } => { + let source = unpack!( + block = this.as_operand( + block, + scope, + source, + LocalInfo::Boring, + NeedsTemporary::Maybe + ) + ); + block.and(Rvalue::WrapUnsafeBinder(source, expr.ty)) + } + ExprKind::Yield { .. } | ExprKind::Block { .. } | ExprKind::Match { .. } @@ -532,7 +545,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::Become { .. } | ExprKind::InlineAsm { .. } | ExprKind::PlaceTypeAscription { .. } - | ExprKind::ValueTypeAscription { .. } => { + | ExprKind::ValueTypeAscription { .. } + | ExprKind::PlaceUnwrapUnsafeBinder { .. } + | ExprKind::ValueUnwrapUnsafeBinder { .. } => { // these do not have corresponding `Rvalue` variants, // so make an operand and then return that debug_assert!(!matches!( diff --git a/compiler/rustc_mir_build/src/builder/expr/category.rs b/compiler/rustc_mir_build/src/builder/expr/category.rs index e0349e3e3f6..ca55d36bfc6 100644 --- a/compiler/rustc_mir_build/src/builder/expr/category.rs +++ b/compiler/rustc_mir_build/src/builder/expr/category.rs @@ -41,7 +41,9 @@ impl Category { | ExprKind::UpvarRef { .. } | ExprKind::VarRef { .. } | ExprKind::PlaceTypeAscription { .. } - | ExprKind::ValueTypeAscription { .. } => Some(Category::Place), + | ExprKind::ValueTypeAscription { .. } + | ExprKind::PlaceUnwrapUnsafeBinder { .. } + | ExprKind::ValueUnwrapUnsafeBinder { .. } => Some(Category::Place), ExprKind::LogicalOp { .. } | ExprKind::Match { .. } @@ -68,7 +70,8 @@ impl Category { | ExprKind::Assign { .. } | ExprKind::AssignOp { .. } | ExprKind::ThreadLocalRef(_) - | ExprKind::OffsetOf { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)), + | ExprKind::OffsetOf { .. } + | ExprKind::WrapUnsafeBinder { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)), ExprKind::ConstBlock { .. } | ExprKind::Literal { .. } diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index 928156572d5..b25cd0f4426 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -554,7 +554,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::VarRef { .. } | ExprKind::UpvarRef { .. } | ExprKind::PlaceTypeAscription { .. } - | ExprKind::ValueTypeAscription { .. } => { + | ExprKind::ValueTypeAscription { .. } + | ExprKind::PlaceUnwrapUnsafeBinder { .. } + | ExprKind::ValueUnwrapUnsafeBinder { .. } => { debug_assert!(Category::of(&expr.kind) == Some(Category::Place)); let place = unpack!(block = this.as_place(block, expr_id)); @@ -613,7 +615,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::ConstParam { .. } | ExprKind::ThreadLocalRef(_) | ExprKind::StaticRef { .. } - | ExprKind::OffsetOf { .. } => { + | ExprKind::OffsetOf { .. } + | ExprKind::WrapUnsafeBinder { .. } => { debug_assert!(match Category::of(&expr.kind).unwrap() { // should be handled above Category::Rvalue(RvalueFunc::Into) => false, diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 9fa431f7d5f..e04c70b5883 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -20,7 +20,6 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_middle::hir::place::PlaceBase as HirPlaceBase; use rustc_middle::middle::region; use rustc_middle::mir::*; -use rustc_middle::query::TyCtxtAt; use rustc_middle::thir::{self, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir}; use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_middle::{bug, span_bug}; @@ -45,10 +44,10 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>( .collect() } -/// Construct the MIR for a given `DefId`. -pub(crate) fn build_mir<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx> { - let tcx = tcx.tcx; - tcx.ensure_with_value().thir_abstract_const(def); +/// Create the MIR for a given `DefId`, including unreachable code. Do not call +/// this directly; instead use the cached version via `mir_built`. +pub fn build_mir<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> { + tcx.ensure_done().thir_abstract_const(def); if let Err(e) = tcx.check_match(def) { return construct_error(tcx, def, e); } @@ -69,7 +68,7 @@ pub(crate) fn build_mir<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx // "not all control paths return a value" is reported here. // // maybe move the check to a MIR pass? - tcx.ensure().check_liveness(def); + tcx.ensure_ok().check_liveness(def); // Don't steal here, instead steal in unsafeck. This is so that // pattern inline constants can be evaluated as part of building the diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs index 0659e3ea314..921205428db 100644 --- a/compiler/rustc_mir_build/src/check_tail_calls.rs +++ b/compiler/rustc_mir_build/src/check_tail_calls.rs @@ -1,4 +1,5 @@ use rustc_abi::ExternAbi; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::Applicability; use rustc_hir::LangItem; use rustc_hir::def::DefKind; @@ -344,12 +345,14 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for TailCallCkVisitor<'a, 'tcx> { } fn visit_expr(&mut self, expr: &'a Expr<'tcx>) { - if let ExprKind::Become { value } = expr.kind { - let call = &self.thir[value]; - self.check_tail_call(call, expr); - } + ensure_sufficient_stack(|| { + if let ExprKind::Become { value } = expr.kind { + let call = &self.thir[value]; + self.check_tail_call(call, expr); + } - visit::walk_expr(self, expr); + visit::walk_expr(self, expr); + }); } } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 995bc311b7c..b6494173b0f 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -2,6 +2,7 @@ use std::borrow::Cow; use std::mem; use std::ops::Bound; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::DiagArgValue; use rustc_hir::def::DefKind; use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability}; @@ -200,7 +201,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { fn visit_inner_body(&mut self, def: LocalDefId) { if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) { // Runs all other queries that depend on THIR. - self.tcx.ensure_with_value().mir_built(def); + self.tcx.ensure_done().mir_built(def); let inner_thir = &inner_thir.steal(); let hir_context = self.tcx.local_def_id_to_hir_id(def); let safety_context = mem::replace(&mut self.safety_context, SafetyContext::Safe); @@ -439,6 +440,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { | ExprKind::NeverToAny { .. } | ExprKind::PlaceTypeAscription { .. } | ExprKind::ValueTypeAscription { .. } + | ExprKind::PlaceUnwrapUnsafeBinder { .. } + | ExprKind::ValueUnwrapUnsafeBinder { .. } + | ExprKind::WrapUnsafeBinder { .. } | ExprKind::PointerCoercion { .. } | ExprKind::Repeat { .. } | ExprKind::StaticRef { .. } @@ -473,7 +477,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { ExprKind::Scope { value, lint_level: LintLevel::Explicit(hir_id), region_scope: _ } => { let prev_id = self.hir_context; self.hir_context = hir_id; - self.visit_expr(&self.thir[value]); + ensure_sufficient_stack(|| { + self.visit_expr(&self.thir[value]); + }); self.hir_context = prev_id; return; // don't visit the whole expression } @@ -680,6 +686,11 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { } } } + ExprKind::PlaceUnwrapUnsafeBinder { .. } + | ExprKind::ValueUnwrapUnsafeBinder { .. } + | ExprKind::WrapUnsafeBinder { .. } => { + self.requires_unsafe(expr.span, UnsafeBinderCast); + } _ => {} } visit::walk_expr(self, expr); @@ -728,6 +739,7 @@ enum UnsafeOpKind { /// (e.g., with `-C target-feature`). build_enabled: Vec<Symbol>, }, + UnsafeBinderCast, } use UnsafeOpKind::*; @@ -891,6 +903,15 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), + UnsafeBinderCast => tcx.emit_node_span_lint( + UNSAFE_OP_IN_UNSAFE_FN, + hir_id, + span, + UnsafeOpInUnsafeFnUnsafeBinderCastRequiresUnsafe { + span, + unsafe_not_inherited_note, + }, + ), } } @@ -1099,6 +1120,15 @@ impl UnsafeOpKind { function: tcx.def_path_str(*function), }); } + UnsafeBinderCast if unsafe_op_in_unsafe_fn_allowed => { + dcx.emit_err(UnsafeBinderCastRequiresUnsafeUnsafeOpInUnsafeFnAllowed { + span, + unsafe_not_inherited_note, + }); + } + UnsafeBinderCast => { + dcx.emit_err(UnsafeBinderCastRequiresUnsafe { span, unsafe_not_inherited_note }); + } } } } @@ -1112,7 +1142,7 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { let Ok((thir, expr)) = tcx.thir_body(def) else { return }; // Runs all other queries that depend on THIR. - tcx.ensure_with_value().mir_built(def); + tcx.ensure_done().mir_built(def); let thir = &thir.steal(); let hir_id = tcx.local_def_id_to_hir_id(def); diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 1f87bf0dbbb..af6f33d9cdd 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -161,6 +161,18 @@ pub(crate) struct UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe } #[derive(LintDiagnostic)] +#[diag( + mir_build_unsafe_binder_cast_requires_unsafe, + code = E0133, +)] +pub(crate) struct UnsafeOpInUnsafeFnUnsafeBinderCastRequiresUnsafe { + #[label] + pub(crate) span: Span, + #[subdiagnostic] + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, +} + +#[derive(LintDiagnostic)] #[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe, code = E0133)] #[help] pub(crate) struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe { @@ -494,6 +506,32 @@ pub(crate) struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } +#[derive(Diagnostic)] +#[diag( + mir_build_unsafe_binder_cast_requires_unsafe, + code = E0133, +)] +pub(crate) struct UnsafeBinderCastRequiresUnsafe { + #[primary_span] + #[label] + pub(crate) span: Span, + #[subdiagnostic] + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, +} + +#[derive(Diagnostic)] +#[diag( + mir_build_unsafe_binder_cast_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, + code = E0133, +)] +pub(crate) struct UnsafeBinderCastRequiresUnsafeUnsafeOpInUnsafeFnAllowed { + #[primary_span] + #[label] + pub(crate) span: Span, + #[subdiagnostic] + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, +} + #[derive(Subdiagnostic)] #[label(mir_build_unsafe_not_inherited)] pub(crate) struct UnsafeNotInheritedNote { @@ -801,10 +839,6 @@ pub(crate) struct BorrowOfMovedValue { pub(crate) ty: String, #[suggestion(code = "ref ", applicability = "machine-applicable")] pub(crate) suggest_borrowing: Option<Span>, - #[note(mir_build_full_type_name)] - #[note(mir_build_consider_verbose)] - pub(crate) has_path: bool, - pub(crate) path: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 8e786733ee0..fa5db32d913 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -14,11 +14,11 @@ // The `builder` module used to be named `build`, but that was causing GitHub's // "Go to file" feature to silently ignore all files in the module, probably // because it assumes that "build" is a build-output directory. See #134365. -mod builder; +pub mod builder; mod check_tail_calls; mod check_unsafety; mod errors; -mod thir; +pub mod thir; use rustc_middle::util::Providers; @@ -27,12 +27,9 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub fn provide(providers: &mut Providers) { providers.check_match = thir::pattern::check_match; providers.lit_to_const = thir::constant::lit_to_const; - providers.hooks.build_mir = builder::build_mir; providers.closure_saved_names_of_captured_variables = builder::closure_saved_names_of_captured_variables; providers.check_unsafety = check_unsafety::check_unsafety; providers.check_tail_calls = check_tail_calls::check_tail_calls; providers.thir_body = thir::cx::thir_body; - providers.hooks.thir_tree = thir::print::thir_tree; - providers.hooks.thir_flat = thir::print::thir_flat; } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 9cdf08d749b..795ac6b4bea 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1,5 +1,6 @@ use itertools::Itertools; use rustc_abi::{FIRST_VARIANT, FieldIdx}; +use rustc_ast::UnsafeBinderCastKind; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; @@ -910,8 +911,19 @@ impl<'tcx> Cx<'tcx> { } } - hir::ExprKind::UnsafeBinderCast(_kind, _source, _ty) => { - unreachable!("unsafe binders are not yet implemented") + hir::ExprKind::UnsafeBinderCast(UnsafeBinderCastKind::Unwrap, source, _ty) => { + // FIXME(unsafe_binders): Take into account the ascribed type, too. + let mirrored = self.mirror_expr(source); + if source.is_syntactic_place_expr() { + ExprKind::PlaceUnwrapUnsafeBinder { source: mirrored } + } else { + ExprKind::ValueUnwrapUnsafeBinder { source: mirrored } + } + } + hir::ExprKind::UnsafeBinderCast(UnsafeBinderCastKind::Wrap, source, _ty) => { + // FIXME(unsafe_binders): Take into account the ascribed type, too. + let mirrored = self.mirror_expr(source); + ExprKind::WrapUnsafeBinder { source: mirrored } } hir::ExprKind::DropTemps(source) => ExprKind::Use { source: self.mirror_expr(source) }, diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs index ca26cc13b5e..c7c88801d4d 100644 --- a/compiler/rustc_mir_build/src/thir/mod.rs +++ b/compiler/rustc_mir_build/src/thir/mod.rs @@ -7,5 +7,5 @@ pub(crate) mod constant; pub(crate) mod cx; pub(crate) mod pattern; -pub(crate) mod print; +pub mod print; mod util; diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index e0a1117f905..8247a6c6a32 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -326,9 +326,10 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { | Use { source } | PointerCoercion { source, .. } | PlaceTypeAscription { source, .. } - | ValueTypeAscription { source, .. } => { - self.is_known_valid_scrutinee(&self.thir()[*source]) - } + | ValueTypeAscription { source, .. } + | PlaceUnwrapUnsafeBinder { source } + | ValueUnwrapUnsafeBinder { source } + | WrapUnsafeBinder { source } => self.is_known_valid_scrutinee(&self.thir()[*source]), // These diverge. Become { .. } | Break { .. } | Continue { .. } | Return { .. } => true, @@ -796,16 +797,16 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat: }); if !conflicts_ref.is_empty() { let mut path = None; - let ty = cx.tcx.short_ty_string(ty, &mut path); - sess.dcx().emit_err(BorrowOfMovedValue { + let ty = cx.tcx.short_string(ty, &mut path); + let mut err = sess.dcx().create_err(BorrowOfMovedValue { binding_span: pat.span, conflicts_ref, name: Ident::new(name, pat.span), ty, suggest_borrowing: Some(pat.span.shrink_to_lo()), - has_path: path.is_some(), - path: path.map(|p| p.display().to_string()).unwrap_or_default(), }); + *err.long_ty_path() = path; + err.emit(); } return; } 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 3853b95f78b..cc6d69710e4 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 @@ -46,7 +46,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { match c.kind() { ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty), - ty::ConstKind::Value(_, val) => convert.valtree_to_pat(val, ty), + ty::ConstKind::Value(cv) => convert.valtree_to_pat(cv.valtree, cv.ty), _ => span_bug!(span, "Invalid `ConstKind` for `const_to_pat`: {:?}", c), } } @@ -214,6 +214,7 @@ impl<'tcx> ConstToPat<'tcx> { } // Recursive helper for `to_pat`; invoke that (instead of calling this directly). + // FIXME(valtrees): Accept `ty::Value` instead of `Ty` and `ty::ValTree` separately. #[instrument(skip(self), level = "debug")] fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> { let span = self.span; diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 2bcdb67c58a..729c8f784ba 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -1,12 +1,13 @@ use std::fmt::{self, Write}; -use rustc_middle::query::TyCtxtAt; use rustc_middle::thir::*; use rustc_middle::ty; +use rustc_middle::ty::TyCtxt; use rustc_span::def_id::LocalDefId; -pub(crate) fn thir_tree(tcx: TyCtxtAt<'_>, owner_def: LocalDefId) -> String { - match super::cx::thir_body(*tcx, owner_def) { +/// Create a THIR tree for debugging. +pub fn thir_tree(tcx: TyCtxt<'_>, owner_def: LocalDefId) -> String { + match super::cx::thir_body(tcx, owner_def) { Ok((thir, _)) => { let thir = thir.steal(); let mut printer = ThirPrinter::new(&thir); @@ -17,8 +18,9 @@ pub(crate) fn thir_tree(tcx: TyCtxtAt<'_>, owner_def: LocalDefId) -> String { } } -pub(crate) fn thir_flat(tcx: TyCtxtAt<'_>, owner_def: LocalDefId) -> String { - match super::cx::thir_body(*tcx, owner_def) { +/// Create a list-like THIR representation for debugging. +pub fn thir_flat(tcx: TyCtxt<'_>, owner_def: LocalDefId) -> String { + match super::cx::thir_body(tcx, owner_def) { Ok((thir, _)) => format!("{:#?}", thir.steal()), Err(_) => "error".into(), } @@ -475,6 +477,24 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_expr(*source, depth_lvl + 2); print_indented!(self, "}", depth_lvl); } + PlaceUnwrapUnsafeBinder { source } => { + print_indented!(self, "PlaceUnwrapUnsafeBinder {", depth_lvl); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + ValueUnwrapUnsafeBinder { source } => { + print_indented!(self, "ValueUnwrapUnsafeBinder {", depth_lvl); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } + WrapUnsafeBinder { source } => { + print_indented!(self, "WrapUnsafeBinder {", depth_lvl); + print_indented!(self, "source:", depth_lvl + 1); + self.print_expr(*source, depth_lvl + 2); + print_indented!(self, "}", depth_lvl); + } Closure(closure_expr) => { print_indented!(self, "Closure {", depth_lvl); print_indented!(self, "closure_expr:", depth_lvl + 1); diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index df4b1a53417..9abb8343432 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -97,7 +97,8 @@ where | Rvalue::UnaryOp(..) | Rvalue::Discriminant(..) | Rvalue::Aggregate(..) - | Rvalue::CopyForDeref(..) => {} + | Rvalue::CopyForDeref(..) + | Rvalue::WrapUnsafeBinder(..) => {} } } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs index d79d2c316ee..d056ad3d4b4 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs @@ -32,6 +32,7 @@ impl<'tcx> Lift for PlaceElem<'tcx> { } ProjectionElem::Downcast(a, u) => ProjectionElem::Downcast(a, u), ProjectionElem::Subtype(_ty) => ProjectionElem::Subtype(()), + ProjectionElem::UnwrapUnsafeBinder(_ty) => ProjectionElem::UnwrapUnsafeBinder(()), } } } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index d1b3a389e9e..6e00e427a46 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -208,7 +208,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { | ty::Infer(_) | ty::Error(_) | ty::Placeholder(_) => bug!( - "When Place contains ProjectionElem::Field it's type shouldn't be {place_ty:#?}" + "When Place contains ProjectionElem::Field its type shouldn't be {place_ty:#?}" ), }, ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { @@ -226,6 +226,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { } _ => bug!("Unexpected type {place_ty:#?}"), }, + ProjectionElem::UnwrapUnsafeBinder(_) => {} // `OpaqueCast`:Only transmutes the type, so no moves there. // `Downcast` :Only changes information about a `Place` without moving. // `Subtype` :Only transmutes the type, so moves. @@ -399,7 +400,8 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { | Rvalue::Repeat(ref operand, _) | Rvalue::Cast(_, ref operand, _) | Rvalue::ShallowInitBox(ref operand, _) - | Rvalue::UnaryOp(_, ref operand) => self.gather_operand(operand), + | Rvalue::UnaryOp(_, ref operand) + | Rvalue::WrapUnsafeBinder(ref operand, _) => self.gather_operand(operand), Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs)) => { self.gather_operand(lhs); self.gather_operand(rhs); diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index d7e22c12394..ca5564e447a 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -1,11 +1,10 @@ -use rustc_hir::lang_items::LangItem; use rustc_index::IndexVec; use rustc_middle::mir::interpret::Scalar; -use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{Ty, TyCtxt}; use rustc_session::Session; -use tracing::{debug, trace}; + +use crate::check_pointers::{BorrowCheckMode, PointerCheck, check_pointers}; pub(super) struct CheckAlignment; @@ -19,46 +18,19 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment { } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // This pass emits new panics. If for whatever reason we do not have a panic - // implementation, running this pass may cause otherwise-valid code to not compile. - if tcx.lang_items().get(LangItem::PanicImpl).is_none() { - return; - } - - let typing_env = body.typing_env(tcx); - let basic_blocks = body.basic_blocks.as_mut(); - let local_decls = &mut body.local_decls; - - // This pass inserts new blocks. Each insertion changes the Location for all - // statements/blocks after. Iterating or visiting the MIR in order would require updating - // our current location after every insertion. By iterating backwards, we dodge this issue: - // The only Locations that an insertion changes have already been handled. - for block in (0..basic_blocks.len()).rev() { - let block = block.into(); - for statement_index in (0..basic_blocks[block].statements.len()).rev() { - let location = Location { block, statement_index }; - let statement = &basic_blocks[block].statements[statement_index]; - let source_info = statement.source_info; - - let mut finder = - PointerFinder { tcx, local_decls, typing_env, pointers: Vec::new() }; - finder.visit_statement(statement, location); - - for (local, ty) in finder.pointers { - debug!("Inserting alignment check for {:?}", ty); - let new_block = split_block(basic_blocks, location); - insert_alignment_check( - tcx, - local_decls, - &mut basic_blocks[block], - local, - ty, - source_info, - new_block, - ); - } - } - } + // Skip trivially aligned place types. + let excluded_pointees = [tcx.types.bool, tcx.types.i8, tcx.types.u8]; + + // We have to exclude borrows here: in `&x.field`, the exact + // requirement is that the final reference must be aligned, but + // `check_pointers` would check that `x` is aligned, which would be wrong. + check_pointers( + tcx, + body, + &excluded_pointees, + insert_alignment_check, + BorrowCheckMode::ExcludeBorrows, + ); } fn is_required(&self) -> bool { @@ -66,119 +38,33 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment { } } -struct PointerFinder<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - local_decls: &'a mut LocalDecls<'tcx>, - typing_env: ty::TypingEnv<'tcx>, - pointers: Vec<(Place<'tcx>, Ty<'tcx>)>, -} - -impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> { - fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { - // We want to only check reads and writes to Places, so we specifically exclude - // Borrow and RawBorrow. - match context { - PlaceContext::MutatingUse( - MutatingUseContext::Store - | MutatingUseContext::AsmOutput - | MutatingUseContext::Call - | MutatingUseContext::Yield - | MutatingUseContext::Drop, - ) => {} - PlaceContext::NonMutatingUse( - NonMutatingUseContext::Copy | NonMutatingUseContext::Move, - ) => {} - _ => { - return; - } - } - - if !place.is_indirect() { - return; - } - - // Since Deref projections must come first and only once, the pointer for an indirect place - // is the Local that the Place is based on. - let pointer = Place::from(place.local); - let pointer_ty = self.local_decls[place.local].ty; - - // We only want to check places based on unsafe pointers - if !pointer_ty.is_unsafe_ptr() { - trace!("Indirect, but not based on an unsafe ptr, not checking {:?}", place); - return; - } - - let pointee_ty = - pointer_ty.builtin_deref(true).expect("no builtin_deref for an unsafe pointer"); - // Ideally we'd support this in the future, but for now we are limited to sized types. - if !pointee_ty.is_sized(self.tcx, self.typing_env) { - debug!("Unsafe pointer, but pointee is not known to be sized: {:?}", pointer_ty); - return; - } - - // Try to detect types we are sure have an alignment of 1 and skip the check - // We don't need to look for str and slices, we already rejected unsized types above - let element_ty = match pointee_ty.kind() { - ty::Array(ty, _) => *ty, - _ => pointee_ty, - }; - if [self.tcx.types.bool, self.tcx.types.i8, self.tcx.types.u8].contains(&element_ty) { - debug!("Trivially aligned place type: {:?}", pointee_ty); - return; - } - - // Ensure that this place is based on an aligned pointer. - self.pointers.push((pointer, pointee_ty)); - - self.super_place(place, context, location); - } -} - -fn split_block( - basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'_>>, - location: Location, -) -> BasicBlock { - let block_data = &mut basic_blocks[location.block]; - - // Drain every statement after this one and move the current terminator to a new basic block - let new_block = BasicBlockData { - statements: block_data.statements.split_off(location.statement_index), - terminator: block_data.terminator.take(), - is_cleanup: block_data.is_cleanup, - }; - - basic_blocks.push(new_block) -} - +/// Inserts the actual alignment check's logic. Returns a +/// [AssertKind::MisalignedPointerDereference] on failure. fn insert_alignment_check<'tcx>( tcx: TyCtxt<'tcx>, - local_decls: &mut IndexVec<Local, LocalDecl<'tcx>>, - block_data: &mut BasicBlockData<'tcx>, pointer: Place<'tcx>, pointee_ty: Ty<'tcx>, + local_decls: &mut IndexVec<Local, LocalDecl<'tcx>>, + stmts: &mut Vec<Statement<'tcx>>, source_info: SourceInfo, - new_block: BasicBlock, -) { - // Cast the pointer to a *const () +) -> PointerCheck<'tcx> { + // Cast the pointer to a *const (). let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit); let rvalue = Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(pointer), const_raw_ptr); let thin_ptr = local_decls.push(LocalDecl::with_source_info(const_raw_ptr, source_info)).into(); - block_data - .statements + stmts .push(Statement { source_info, kind: StatementKind::Assign(Box::new((thin_ptr, rvalue))) }); - // Transmute the pointer to a usize (equivalent to `ptr.addr()`) + // Transmute the pointer to a usize (equivalent to `ptr.addr()`). let rvalue = Rvalue::Cast(CastKind::Transmute, Operand::Copy(thin_ptr), tcx.types.usize); let addr = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); - block_data - .statements - .push(Statement { source_info, kind: StatementKind::Assign(Box::new((addr, rvalue))) }); + stmts.push(Statement { source_info, kind: StatementKind::Assign(Box::new((addr, rvalue))) }); // Get the alignment of the pointee let alignment = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); let rvalue = Rvalue::NullaryOp(NullOp::AlignOf, pointee_ty); - block_data.statements.push(Statement { + stmts.push(Statement { source_info, kind: StatementKind::Assign(Box::new((alignment, rvalue))), }); @@ -191,7 +77,7 @@ fn insert_alignment_check<'tcx>( user_ty: None, const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(1, &tcx)), tcx.types.usize), })); - block_data.statements.push(Statement { + stmts.push(Statement { source_info, kind: StatementKind::Assign(Box::new(( alignment_mask, @@ -202,7 +88,7 @@ fn insert_alignment_check<'tcx>( // BitAnd the alignment mask with the pointer let alignment_bits = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); - block_data.statements.push(Statement { + stmts.push(Statement { source_info, kind: StatementKind::Assign(Box::new(( alignment_bits, @@ -220,7 +106,7 @@ fn insert_alignment_check<'tcx>( user_ty: None, const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)), tcx.types.usize), })); - block_data.statements.push(Statement { + stmts.push(Statement { source_info, kind: StatementKind::Assign(Box::new(( is_ok, @@ -228,21 +114,13 @@ fn insert_alignment_check<'tcx>( ))), }); - // Set this block's terminator to our assert, continuing to new_block if we pass - block_data.terminator = Some(Terminator { - source_info, - kind: TerminatorKind::Assert { - cond: Operand::Copy(is_ok), - expected: true, - target: new_block, - msg: Box::new(AssertKind::MisalignedPointerDereference { - required: Operand::Copy(alignment), - found: Operand::Copy(addr), - }), - // This calls panic_misaligned_pointer_dereference, which is #[rustc_nounwind]. - // We never want to insert an unwind into unsafe code, because unwinding could - // make a failing UB check turn into much worse UB when we start unwinding. - unwind: UnwindAction::Unreachable, - }, - }); + // Emit a check that asserts on the alignment and otherwise triggers a + // AssertKind::MisalignedPointerDereference. + PointerCheck { + cond: Operand::Copy(is_ok), + assert_kind: Box::new(AssertKind::MisalignedPointerDereference { + required: Operand::Copy(alignment), + found: Operand::Copy(addr), + }), + } } diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs index 7968b666dff..3affe4abbfa 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -133,7 +133,7 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> { // the `self` parameter of a method call (as the terminator of our current // BasicBlock). If so, we emit a more specific lint. let method_did = self.target_local.and_then(|target_local| { - rustc_middle::util::find_self_call(self.tcx, self.body, target_local, loc.block) + find_self_call(self.tcx, self.body, target_local, loc.block) }); let lint_loc = if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc }; diff --git a/compiler/rustc_mir_transform/src/check_null.rs b/compiler/rustc_mir_transform/src/check_null.rs new file mode 100644 index 00000000000..0b6c0ceaac1 --- /dev/null +++ b/compiler/rustc_mir_transform/src/check_null.rs @@ -0,0 +1,110 @@ +use rustc_index::IndexVec; +use rustc_middle::mir::interpret::Scalar; +use rustc_middle::mir::*; +use rustc_middle::ty::{Ty, TyCtxt}; +use rustc_session::Session; + +use crate::check_pointers::{BorrowCheckMode, PointerCheck, check_pointers}; + +pub(super) struct CheckNull; + +impl<'tcx> crate::MirPass<'tcx> for CheckNull { + fn is_enabled(&self, sess: &Session) -> bool { + sess.ub_checks() + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + check_pointers(tcx, body, &[], insert_null_check, BorrowCheckMode::IncludeBorrows); + } + + fn is_required(&self) -> bool { + true + } +} + +fn insert_null_check<'tcx>( + tcx: TyCtxt<'tcx>, + pointer: Place<'tcx>, + pointee_ty: Ty<'tcx>, + local_decls: &mut IndexVec<Local, LocalDecl<'tcx>>, + stmts: &mut Vec<Statement<'tcx>>, + source_info: SourceInfo, +) -> PointerCheck<'tcx> { + // Cast the pointer to a *const (). + let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit); + let rvalue = Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(pointer), const_raw_ptr); + let thin_ptr = local_decls.push(LocalDecl::with_source_info(const_raw_ptr, source_info)).into(); + stmts + .push(Statement { source_info, kind: StatementKind::Assign(Box::new((thin_ptr, rvalue))) }); + + // Transmute the pointer to a usize (equivalent to `ptr.addr()`). + let rvalue = Rvalue::Cast(CastKind::Transmute, Operand::Copy(thin_ptr), tcx.types.usize); + let addr = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); + stmts.push(Statement { source_info, kind: StatementKind::Assign(Box::new((addr, rvalue))) }); + + // Get size of the pointee (zero-sized reads and writes are allowed). + let rvalue = Rvalue::NullaryOp(NullOp::SizeOf, pointee_ty); + let sizeof_pointee = + local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into(); + stmts.push(Statement { + source_info, + kind: StatementKind::Assign(Box::new((sizeof_pointee, rvalue))), + }); + + // Check that the pointee is not a ZST. + let zero = Operand::Constant(Box::new(ConstOperand { + span: source_info.span, + user_ty: None, + const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)), tcx.types.usize), + })); + let is_pointee_no_zst = + local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into(); + stmts.push(Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + is_pointee_no_zst, + Rvalue::BinaryOp(BinOp::Ne, Box::new((Operand::Copy(sizeof_pointee), zero.clone()))), + ))), + }); + + // Check whether the pointer is null. + let is_null = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into(); + stmts.push(Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + is_null, + Rvalue::BinaryOp(BinOp::Eq, Box::new((Operand::Copy(addr), zero))), + ))), + }); + + // We want to throw an exception if the pointer is null and doesn't point to a ZST. + let should_throw_exception = + local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into(); + stmts.push(Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + should_throw_exception, + Rvalue::BinaryOp( + BinOp::BitAnd, + Box::new((Operand::Copy(is_null), Operand::Copy(is_pointee_no_zst))), + ), + ))), + }); + + // The final condition whether this pointer usage is ok or not. + let is_ok = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into(); + stmts.push(Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + is_ok, + Rvalue::UnaryOp(UnOp::Not, Operand::Copy(should_throw_exception)), + ))), + }); + + // Emit a PointerCheck that asserts on the condition and otherwise triggers + // a AssertKind::NullPointerDereference. + PointerCheck { + cond: Operand::Copy(is_ok), + assert_kind: Box::new(AssertKind::NullPointerDereference), + } +} diff --git a/compiler/rustc_mir_transform/src/check_pointers.rs b/compiler/rustc_mir_transform/src/check_pointers.rs new file mode 100644 index 00000000000..72460542f87 --- /dev/null +++ b/compiler/rustc_mir_transform/src/check_pointers.rs @@ -0,0 +1,234 @@ +use rustc_hir::lang_items::LangItem; +use rustc_index::IndexVec; +use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; +use rustc_middle::mir::*; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use tracing::{debug, trace}; + +/// Details of a pointer check, the condition on which we decide whether to +/// fail the assert and an [AssertKind] that defines the behavior on failure. +pub(crate) struct PointerCheck<'tcx> { + pub(crate) cond: Operand<'tcx>, + pub(crate) assert_kind: Box<AssertKind<Operand<'tcx>>>, +} + +/// Indicates whether we insert the checks for borrow places of a raw pointer. +/// Concretely places with [MutatingUseContext::Borrow] or +/// [NonMutatingUseContext::SharedBorrow]. +#[derive(Copy, Clone)] +pub(crate) enum BorrowCheckMode { + IncludeBorrows, + ExcludeBorrows, +} + +/// Utility for adding a check for read/write on every sized, raw pointer. +/// +/// Visits every read/write access to a [Sized], raw pointer and inserts a +/// new basic block directly before the pointer access. (Read/write accesses +/// are determined by the `PlaceContext` of the MIR visitor.) Then calls +/// `on_finding` to insert the actual logic for a pointer check (e.g. check for +/// alignment). A check can choose to be inserted for (mutable) borrows of +/// raw pointers via the `borrow_check_mode` parameter. +/// +/// This utility takes care of the right order of blocks, the only thing a +/// caller must do in `on_finding` is: +/// - Append [Statement]s to `stmts`. +/// - Append [LocalDecl]s to `local_decls`. +/// - Return a [PointerCheck] that contains the condition and an [AssertKind]. +/// The AssertKind must be a panic with `#[rustc_nounwind]`. The condition +/// should always return the boolean `is_ok`, so evaluate to true in case of +/// success and fail the check otherwise. +/// This utility will insert a terminator block that asserts on the condition +/// and panics on failure. +pub(crate) fn check_pointers<'a, 'tcx, F>( + tcx: TyCtxt<'tcx>, + body: &mut Body<'tcx>, + excluded_pointees: &'a [Ty<'tcx>], + on_finding: F, + borrow_check_mode: BorrowCheckMode, +) where + F: Fn( + /* tcx: */ TyCtxt<'tcx>, + /* pointer: */ Place<'tcx>, + /* pointee_ty: */ Ty<'tcx>, + /* local_decls: */ &mut IndexVec<Local, LocalDecl<'tcx>>, + /* stmts: */ &mut Vec<Statement<'tcx>>, + /* source_info: */ SourceInfo, + ) -> PointerCheck<'tcx>, +{ + // This pass emits new panics. If for whatever reason we do not have a panic + // implementation, running this pass may cause otherwise-valid code to not compile. + if tcx.lang_items().get(LangItem::PanicImpl).is_none() { + return; + } + + let typing_env = body.typing_env(tcx); + let basic_blocks = body.basic_blocks.as_mut(); + let local_decls = &mut body.local_decls; + + // This operation inserts new blocks. Each insertion changes the Location for all + // statements/blocks after. Iterating or visiting the MIR in order would require updating + // our current location after every insertion. By iterating backwards, we dodge this issue: + // The only Locations that an insertion changes have already been handled. + for block in (0..basic_blocks.len()).rev() { + let block = block.into(); + for statement_index in (0..basic_blocks[block].statements.len()).rev() { + let location = Location { block, statement_index }; + let statement = &basic_blocks[block].statements[statement_index]; + let source_info = statement.source_info; + + let mut finder = PointerFinder::new( + tcx, + local_decls, + typing_env, + excluded_pointees, + borrow_check_mode, + ); + finder.visit_statement(statement, location); + + for (local, ty) in finder.into_found_pointers() { + debug!("Inserting check for {:?}", ty); + let new_block = split_block(basic_blocks, location); + + // Invoke `on_finding` which appends to `local_decls` and the + // blocks statements. It returns information about the assert + // we're performing in the Terminator. + let block_data = &mut basic_blocks[block]; + let pointer_check = on_finding( + tcx, + local, + ty, + local_decls, + &mut block_data.statements, + source_info, + ); + block_data.terminator = Some(Terminator { + source_info, + kind: TerminatorKind::Assert { + cond: pointer_check.cond, + expected: true, + target: new_block, + msg: pointer_check.assert_kind, + // This calls a panic function associated with the pointer check, which + // is #[rustc_nounwind]. We never want to insert an unwind into unsafe + // code, because unwinding could make a failing UB check turn into much + // worse UB when we start unwinding. + unwind: UnwindAction::Unreachable, + }, + }); + } + } + } +} + +struct PointerFinder<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + local_decls: &'a mut LocalDecls<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + pointers: Vec<(Place<'tcx>, Ty<'tcx>)>, + excluded_pointees: &'a [Ty<'tcx>], + borrow_check_mode: BorrowCheckMode, +} + +impl<'a, 'tcx> PointerFinder<'a, 'tcx> { + fn new( + tcx: TyCtxt<'tcx>, + local_decls: &'a mut LocalDecls<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + excluded_pointees: &'a [Ty<'tcx>], + borrow_check_mode: BorrowCheckMode, + ) -> Self { + PointerFinder { + tcx, + local_decls, + typing_env, + excluded_pointees, + pointers: Vec::new(), + borrow_check_mode, + } + } + + fn into_found_pointers(self) -> Vec<(Place<'tcx>, Ty<'tcx>)> { + self.pointers + } + + /// Whether or not we should visit a [Place] with [PlaceContext]. + /// + /// We generally only visit Reads/Writes to a place and only Borrows if + /// requested. + fn should_visit_place(&self, context: PlaceContext) -> bool { + match context { + PlaceContext::MutatingUse( + MutatingUseContext::Store + | MutatingUseContext::Call + | MutatingUseContext::Yield + | MutatingUseContext::Drop, + ) => true, + PlaceContext::NonMutatingUse( + NonMutatingUseContext::Copy | NonMutatingUseContext::Move, + ) => true, + PlaceContext::MutatingUse(MutatingUseContext::Borrow) + | PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) => { + matches!(self.borrow_check_mode, BorrowCheckMode::IncludeBorrows) + } + _ => false, + } + } +} + +impl<'a, 'tcx> Visitor<'tcx> for PointerFinder<'a, 'tcx> { + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { + if !self.should_visit_place(context) || !place.is_indirect() { + return; + } + + // Since Deref projections must come first and only once, the pointer for an indirect place + // is the Local that the Place is based on. + let pointer = Place::from(place.local); + let pointer_ty = self.local_decls[place.local].ty; + + // We only want to check places based on raw pointers + if !pointer_ty.is_unsafe_ptr() { + trace!("Indirect, but not based on an raw ptr, not checking {:?}", place); + return; + } + + let pointee_ty = + pointer_ty.builtin_deref(true).expect("no builtin_deref for an raw pointer"); + // Ideally we'd support this in the future, but for now we are limited to sized types. + if !pointee_ty.is_sized(self.tcx, self.typing_env) { + trace!("Raw pointer, but pointee is not known to be sized: {:?}", pointer_ty); + return; + } + + // We don't need to look for slices, we already rejected unsized types above. + let element_ty = match pointee_ty.kind() { + ty::Array(ty, _) => *ty, + _ => pointee_ty, + }; + if self.excluded_pointees.contains(&element_ty) { + trace!("Skipping pointer for type: {:?}", pointee_ty); + return; + } + + self.pointers.push((pointer, pointee_ty)); + + self.super_place(place, context, location); + } +} + +fn split_block( + basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'_>>, + location: Location, +) -> BasicBlock { + let block_data = &mut basic_blocks[location.block]; + + // Drain every statement after this one and move the current terminator to a new basic block. + let new_block = BasicBlockData { + statements: block_data.statements.split_off(location.statement_index), + terminator: block_data.terminator.take(), + is_cleanup: block_data.is_cleanup, + }; + + basic_blocks.push(new_block) +} diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index 5e7b46182dc..a849ed4c3e2 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -6,7 +6,6 @@ use rustc_middle::mir::coverage::{ FunctionCoverageInfo, MappingKind, Op, }; use rustc_middle::mir::{Body, Statement, StatementKind}; -use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::util::Providers; use rustc_span::def_id::LocalDefId; @@ -15,8 +14,7 @@ use tracing::trace; /// Registers query/hook implementations related to coverage. pub(crate) fn provide(providers: &mut Providers) { - providers.hooks.is_eligible_for_coverage = - |TyCtxtAt { tcx, .. }, def_id| is_eligible_for_coverage(tcx, def_id); + providers.hooks.is_eligible_for_coverage = is_eligible_for_coverage; providers.queries.coverage_attr_on = coverage_attr_on; providers.queries.coverage_ids_info = coverage_ids_info; } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 8879e029346..90173da17f0 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -504,7 +504,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { | Rvalue::Cast(..) | Rvalue::BinaryOp(..) | Rvalue::Aggregate(..) - | Rvalue::ShallowInitBox(..) => { + | Rvalue::ShallowInitBox(..) + | Rvalue::WrapUnsafeBinder(..) => { // No modification is possible through these r-values. return ValueOrPlace::TOP; } diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 41de1b58b91..7395ad496db 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -575,6 +575,9 @@ impl WriteInfo { self.add_operand(op); } } + Rvalue::WrapUnsafeBinder(op, _) => { + self.add_operand(op); + } Rvalue::ThreadLocalRef(_) | Rvalue::NullaryOp(_, _) | Rvalue::Ref(_, _, _) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 16e15fa12e0..c261e25100d 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -476,6 +476,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty), ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty), + ProjectionElem::UnwrapUnsafeBinder(ty) => { + ProjectionElem::UnwrapUnsafeBinder(ty) + } // This should have been replaced by a `ConstantIndex` earlier. ProjectionElem::Index(_) => return None, }; @@ -713,6 +716,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty), ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty), + ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(ty), }; Some(self.insert(Value::Projection(value, proj))) @@ -867,6 +871,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { self.simplify_place_projection(place, location); return self.new_pointer(*place, AddressKind::Address(mutbl)); } + Rvalue::WrapUnsafeBinder(ref mut op, _) => { + return self.simplify_operand(op, location); + } // Operations. Rvalue::Len(ref mut place) => return self.simplify_len(place, location), @@ -931,6 +938,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ProjectionElem::Downcast(symbol, idx) => ProjectionElem::Downcast(symbol, idx), ProjectionElem::OpaqueCast(idx) => ProjectionElem::OpaqueCast(idx), ProjectionElem::Subtype(idx) => ProjectionElem::Subtype(idx), + ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(ty), }) } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 95aeccfdda6..f8b0688dfdc 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -4,7 +4,7 @@ use std::iter; use std::ops::{Range, RangeFrom}; use rustc_abi::{ExternAbi, FieldIdx}; -use rustc_attr_parsing::InlineAttr; +use rustc_attr_parsing::{InlineAttr, OptimizeAttr}; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_index::Idx; @@ -770,6 +770,10 @@ fn check_codegen_attributes<'tcx, I: Inliner<'tcx>>( return Err("never inline attribute"); } + if let OptimizeAttr::DoNotOptimize = callee_attrs.optimize { + return Err("has DoNotOptimize attribute"); + } + // Reachability pass defines which functions are eligible for inlining. Generally inlining // other functions is incorrect because they could reference symbols that aren't exported. let is_generic = callsite.callee.args.non_erasable_generics().next().is_some(); diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index f4ac5c6aa80..2864cc0b9fe 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -444,7 +444,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { | Rvalue::Cast(..) | Rvalue::ShallowInitBox(..) | Rvalue::Discriminant(..) - | Rvalue::NullaryOp(..) => {} + | Rvalue::NullaryOp(..) + | Rvalue::WrapUnsafeBinder(..) => {} } // FIXME we need to revisit this for #67176 @@ -546,7 +547,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let val: Value<'_> = match *rvalue { ThreadLocalRef(_) => return None, - Use(ref operand) => self.eval_operand(operand)?.into(), + Use(ref operand) | WrapUnsafeBinder(ref operand, _) => { + self.eval_operand(operand)?.into() + } CopyForDeref(place) => self.eval_place(place)?.into(), diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 2dc55e3614e..b572f6ca0b3 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -33,6 +33,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_middle::util::Providers; use rustc_middle::{bug, query, span_bug}; +use rustc_mir_build::builder::build_mir; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, sym}; use tracing::debug; @@ -44,6 +45,7 @@ use std::sync::LazyLock; use pass_manager::{self as pm, Lint, MirLint, MirPass, WithMinOptLevel}; +mod check_pointers; mod cost_checker; mod cross_crate_inline; mod deduce_param_attrs; @@ -118,6 +120,7 @@ declare_passes! { mod check_call_recursion : CheckCallRecursion, CheckDropRecursion; mod check_alignment : CheckAlignment; mod check_const_item_mutation : CheckConstItemMutation; + mod check_null : CheckNull; mod check_packed_ref : CheckPackedRef; mod check_undefined_transmutes : CheckUndefinedTransmutes; // This pass is public to allow external drivers to perform MIR cleanup @@ -368,7 +371,7 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs { } fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> { - let mut body = tcx.build_mir(def); + let mut body = build_mir(tcx, def); pass_manager::dump_mir_for_phase_change(tcx, &body); @@ -418,11 +421,11 @@ fn mir_promoted( }; // the `has_ffi_unwind_calls` query uses the raw mir, so make sure it is run. - tcx.ensure_with_value().has_ffi_unwind_calls(def); + tcx.ensure_done().has_ffi_unwind_calls(def); // the `by_move_body` query uses the raw mir, so make sure it is run. if tcx.needs_coroutine_by_move_body_def_id(def.to_def_id()) { - tcx.ensure_with_value().coroutine_by_move_body_def_id(def); + tcx.ensure_done().coroutine_by_move_body_def_id(def); } let mut body = tcx.mir_built(def).steal(); @@ -485,7 +488,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> { /// end up missing the source MIR due to stealing happening. fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> { if tcx.is_coroutine(def.to_def_id()) { - tcx.ensure_with_value().mir_coroutine_witnesses(def); + tcx.ensure_done().mir_coroutine_witnesses(def); } // We only need to borrowck non-synthetic MIR. @@ -498,7 +501,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & if pm::should_run_pass(tcx, &inline::Inline, pm::Optimizations::Allowed) || inline::ForceInline::should_run_pass_for_callee(tcx, def.to_def_id()) { - tcx.ensure_with_value().mir_inliner_callees(ty::InstanceKind::Item(def.to_def_id())); + tcx.ensure_done().mir_inliner_callees(ty::InstanceKind::Item(def.to_def_id())); } } @@ -642,6 +645,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &[ // Add some UB checks before any UB gets optimized away. &check_alignment::CheckAlignment, + &check_null::CheckNull, // Before inlining: trim down MIR with passes to reduce inlining work. // Has to be done before inlining, otherwise actual call will be almost always inlined. @@ -729,7 +733,7 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { // Run the `mir_for_ctfe` query, which depends on `mir_drops_elaborated_and_const_checked` // which we are going to steal below. Thus we need to run `mir_for_ctfe` first, so it // computes and caches its result. - Some(hir::ConstContext::ConstFn) => tcx.ensure_with_value().mir_for_ctfe(did), + Some(hir::ConstContext::ConstFn) => tcx.ensure_done().mir_for_ctfe(did), None => {} Some(other) => panic!("do not use `optimized_mir` for constants: {other:?}"), } @@ -768,7 +772,7 @@ fn promoted_mir(tcx: TyCtxt<'_>, def: LocalDefId) -> &IndexVec<Promoted, Body<'_ } if !tcx.is_synthetic_mir(def) { - tcx.ensure_with_value().mir_borrowck(def); + tcx.ensure_done().mir_borrowck(def); } let mut promoted = tcx.mir_promoted(def).1.steal(); diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 6aa3343bb6e..9101c9bfc9a 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -293,7 +293,8 @@ impl<'tcx> Validator<'_, 'tcx> { // Recurse directly. ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subtype(_) - | ProjectionElem::Subslice { .. } => {} + | ProjectionElem::Subslice { .. } + | ProjectionElem::UnwrapUnsafeBinder(_) => {} // Never recurse. ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => { @@ -426,7 +427,9 @@ impl<'tcx> Validator<'_, 'tcx> { fn validate_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { match rvalue { - Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => { + Rvalue::Use(operand) + | Rvalue::Repeat(operand, _) + | Rvalue::WrapUnsafeBinder(operand, _) => { self.validate_operand(operand)?; } Rvalue::CopyForDeref(place) => { diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 5881264cba5..e282eaf761c 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -807,6 +807,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ) } } + ProjectionElem::UnwrapUnsafeBinder(unwrapped_ty) => { + let binder_ty = place_ref.ty(&self.body.local_decls, self.tcx); + let ty::UnsafeBinder(binder_ty) = *binder_ty.ty.kind() else { + self.fail( + location, + format!("WrapUnsafeBinder does not produce a ty::UnsafeBinder"), + ); + return; + }; + let binder_inner_ty = self.tcx.instantiate_bound_regions_with_erased(*binder_ty); + if !self.mir_assign_valid_types(unwrapped_ty, binder_inner_ty) { + self.fail( + location, + format!( + "Cannot unwrap unsafe binder {binder_ty:?} into type {unwrapped_ty:?}" + ), + ); + } + } _ => {} } self.super_projection_elem(place_ref, elem, context, location); @@ -1362,6 +1381,24 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { | Rvalue::RawPtr(_, _) | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::UbChecks, _) | Rvalue::Discriminant(_) => {} + + Rvalue::WrapUnsafeBinder(op, ty) => { + let unwrapped_ty = op.ty(self.body, self.tcx); + let ty::UnsafeBinder(binder_ty) = *ty.kind() else { + self.fail( + location, + format!("WrapUnsafeBinder does not produce a ty::UnsafeBinder"), + ); + return; + }; + let binder_inner_ty = self.tcx.instantiate_bound_regions_with_erased(*binder_ty); + if !self.mir_assign_valid_types(unwrapped_ty, binder_inner_ty) { + self.fail( + location, + format!("Cannot wrap {unwrapped_ty:?} into unsafe binder {binder_ty:?}"), + ); + } + } } self.super_rvalue(rvalue, location); } diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml index 9bdaeb015cd..5462105e5e8 100644 --- a/compiler/rustc_monomorphize/Cargo.toml +++ b/compiler/rustc_monomorphize/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] # tidy-alphabetical-start rustc_abi = { path = "../rustc_abi" } +rustc_ast = { path = "../rustc_ast" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } @@ -15,6 +16,7 @@ rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } +rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_target = { path = "../rustc_target" } serde = "1" serde_json = "1" diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index d53848f7461..ae31ed59391 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -257,7 +257,7 @@ struct SharedState<'tcx> { pub(crate) struct UsageMap<'tcx> { // Maps every mono item to the mono items used by it. - used_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>, + pub used_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>, // Maps every mono item to the mono items that use it. user_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>, @@ -814,6 +814,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { mir::AssertKind::MisalignedPointerDereference { .. } => { push_mono_lang_item(self, LangItem::PanicMisalignedPointerDereference); } + mir::AssertKind::NullPointerDereference => { + push_mono_lang_item(self, LangItem::PanicNullPointerDereference); + } _ => { push_mono_lang_item(self, msg.panic_function()); } @@ -950,7 +953,7 @@ fn visit_instance_use<'tcx>( /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we /// can just link to the upstream crate and therefore don't need a mono item. -fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) -> bool { +fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> bool { let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() else { return true; }; @@ -973,7 +976,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) - return true; } - if tcx.is_reachable_non_generic(def_id) || instance.upstream_monomorphization(*tcx).is_some() { + if tcx.is_reachable_non_generic(def_id) || instance.upstream_monomorphization(tcx).is_some() { // We can link to the item in question, no instance needed in this crate. return false; } @@ -1138,11 +1141,12 @@ fn create_mono_items_for_vtable_methods<'tcx>( bug!("create_mono_items_for_vtable_methods: {trait_ty:?} not a trait type"); }; if let Some(principal) = trait_ty.principal() { - let poly_trait_ref = principal.with_self_ty(tcx, impl_ty); - assert!(!poly_trait_ref.has_escaping_bound_vars()); + let trait_ref = + tcx.instantiate_bound_regions_with_erased(principal.with_self_ty(tcx, impl_ty)); + assert!(!trait_ref.has_escaping_bound_vars()); // Walk all methods of the trait, including those of its supertraits - let entries = tcx.vtable_entries(poly_trait_ref); + let entries = tcx.vtable_entries(trait_ref); debug!(?entries); let methods = entries .iter() @@ -1197,7 +1201,12 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt } } GlobalAlloc::VTable(ty, dyn_ty) => { - let alloc_id = tcx.vtable_allocation((ty, dyn_ty.principal())); + let alloc_id = tcx.vtable_allocation(( + ty, + dyn_ty + .principal() + .map(|principal| tcx.instantiate_bound_regions_with_erased(principal)), + )); collect_alloc(tcx, alloc_id, output) } } @@ -1213,7 +1222,7 @@ fn collect_items_of_instance<'tcx>( mode: CollectionMode, ) -> (MonoItems<'tcx>, MonoItems<'tcx>) { // This item is getting monomorphized, do mono-time checks. - tcx.ensure().check_mono_item(instance); + tcx.ensure_ok().check_mono_item(instance); let body = tcx.instance_mir(instance.def); // Naively, in "used" collection mode, all functions get added to *both* `used_items` and diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index e08c348a64d..3ef061195da 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -92,6 +92,8 @@ //! source-level module, functions from the same module will be available for //! inlining, even when they are not marked `#[inline]`. +mod autodiff; + use std::cmp; use std::collections::hash_map::Entry; use std::fs::{self, File}; @@ -251,7 +253,17 @@ where can_export_generics, always_export_generics, ); - if visibility == Visibility::Hidden && can_be_internalized { + + // We can't differentiate something that got inlined. + let autodiff_active = cfg!(llvm_enzyme) + && cx + .tcx + .codegen_fn_attrs(mono_item.def_id()) + .autodiff_item + .as_ref() + .is_some_and(|ad| ad.is_active()); + + if !autodiff_active && visibility == Visibility::Hidden && can_be_internalized { internalization_candidates.insert(mono_item); } let size_estimate = mono_item.size_estimate(cx.tcx); @@ -1167,15 +1179,27 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> MonoItemPartitio } } + #[cfg(not(llvm_enzyme))] + let autodiff_mono_items: Vec<_> = vec![]; + #[cfg(llvm_enzyme)] + let mut autodiff_mono_items: Vec<_> = vec![]; let mono_items: DefIdSet = items .iter() .filter_map(|mono_item| match *mono_item { - MonoItem::Fn(ref instance) => Some(instance.def_id()), + MonoItem::Fn(ref instance) => { + #[cfg(llvm_enzyme)] + autodiff_mono_items.push((mono_item, instance)); + Some(instance.def_id()) + } MonoItem::Static(def_id) => Some(def_id), _ => None, }) .collect(); + let autodiff_items = + autodiff::find_autodiff_source_functions(tcx, &usage_map, autodiff_mono_items); + let autodiff_items = tcx.arena.alloc_from_iter(autodiff_items); + // Output monomorphization stats per def_id if let SwitchWithOptPath::Enabled(ref path) = tcx.sess.opts.unstable_opts.dump_mono_stats { if let Err(err) = @@ -1236,7 +1260,11 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> MonoItemPartitio } } - MonoItemPartitions { all_mono_items: tcx.arena.alloc(mono_items), codegen_units } + MonoItemPartitions { + all_mono_items: tcx.arena.alloc(mono_items), + codegen_units, + autodiff_items, + } } /// Outputs stats about instantiation counts and estimated size, per `MonoItem`'s diff --git a/compiler/rustc_monomorphize/src/partitioning/autodiff.rs b/compiler/rustc_monomorphize/src/partitioning/autodiff.rs new file mode 100644 index 00000000000..bce31bf0748 --- /dev/null +++ b/compiler/rustc_monomorphize/src/partitioning/autodiff.rs @@ -0,0 +1,121 @@ +use rustc_ast::expand::autodiff_attrs::{AutoDiffItem, DiffActivity}; +use rustc_hir::def_id::LOCAL_CRATE; +use rustc_middle::bug; +use rustc_middle::mir::mono::MonoItem; +use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_symbol_mangling::symbol_name_for_instance_in_crate; +use tracing::{debug, trace}; + +use crate::partitioning::UsageMap; + +fn adjust_activity_to_abi<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>, da: &mut Vec<DiffActivity>) { + if !matches!(fn_ty.kind(), ty::FnDef(..)) { + bug!("expected fn def for autodiff, got {:?}", fn_ty); + } + let fnc_binder: ty::Binder<'_, ty::FnSig<'_>> = fn_ty.fn_sig(tcx); + + // If rustc compiles the unmodified primal, we know that this copy of the function + // also has correct lifetimes. We know that Enzyme won't free the shadow too early + // (or actually at all), so let's strip lifetimes when computing the layout. + let x = tcx.instantiate_bound_regions_with_erased(fnc_binder); + let mut new_activities = vec![]; + let mut new_positions = vec![]; + for (i, ty) in x.inputs().iter().enumerate() { + if let Some(inner_ty) = ty.builtin_deref(true) { + if ty.is_fn_ptr() { + // FIXME(ZuseZ4): add a nicer error, or just figure out how to support them, + // since Enzyme itself can handle them. + tcx.dcx().err("function pointers are currently not supported in autodiff"); + } + if inner_ty.is_slice() { + // We know that the length will be passed as extra arg. + if !da.is_empty() { + // We are looking at a slice. The length of that slice will become an + // extra integer on llvm level. Integers are always const. + // However, if the slice get's duplicated, we want to know to later check the + // size. So we mark the new size argument as FakeActivitySize. + let activity = match da[i] { + DiffActivity::DualOnly + | DiffActivity::Dual + | DiffActivity::DuplicatedOnly + | DiffActivity::Duplicated => DiffActivity::FakeActivitySize, + DiffActivity::Const => DiffActivity::Const, + _ => bug!("unexpected activity for ptr/ref"), + }; + new_activities.push(activity); + new_positions.push(i + 1); + } + continue; + } + } + } + // now add the extra activities coming from slices + // Reverse order to not invalidate the indices + for _ in 0..new_activities.len() { + let pos = new_positions.pop().unwrap(); + let activity = new_activities.pop().unwrap(); + da.insert(pos, activity); + } +} + +pub(crate) fn find_autodiff_source_functions<'tcx>( + tcx: TyCtxt<'tcx>, + usage_map: &UsageMap<'tcx>, + autodiff_mono_items: Vec<(&MonoItem<'tcx>, &Instance<'tcx>)>, +) -> Vec<AutoDiffItem> { + let mut autodiff_items: Vec<AutoDiffItem> = vec![]; + for (item, instance) in autodiff_mono_items { + let target_id = instance.def_id(); + let cg_fn_attr = tcx.codegen_fn_attrs(target_id).autodiff_item.clone(); + let Some(target_attrs) = cg_fn_attr else { + continue; + }; + let mut input_activities: Vec<DiffActivity> = target_attrs.input_activity.clone(); + if target_attrs.is_source() { + trace!("source found: {:?}", target_id); + } + if !target_attrs.apply_autodiff() { + continue; + } + + let target_symbol = symbol_name_for_instance_in_crate(tcx, instance.clone(), LOCAL_CRATE); + + let source = + usage_map.used_map.get(&item).unwrap().into_iter().find_map(|item| match *item { + MonoItem::Fn(ref instance_s) => { + let source_id = instance_s.def_id(); + if let Some(ad) = &tcx.codegen_fn_attrs(source_id).autodiff_item + && ad.is_active() + { + return Some(instance_s); + } + None + } + _ => None, + }); + let inst = match source { + Some(source) => source, + None => continue, + }; + + debug!("source_id: {:?}", inst.def_id()); + let fn_ty = inst.ty(tcx, ty::TypingEnv::fully_monomorphized()); + assert!(fn_ty.is_fn()); + adjust_activity_to_abi(tcx, fn_ty, &mut input_activities); + let symb = symbol_name_for_instance_in_crate(tcx, inst.clone(), LOCAL_CRATE); + + let mut new_target_attrs = target_attrs.clone(); + new_target_attrs.input_activity = input_activities; + let itm = new_target_attrs.into_item(symb, target_symbol); + autodiff_items.push(itm); + } + + if !autodiff_items.is_empty() { + trace!("AUTODIFF ITEMS EXIST"); + for item in &mut *autodiff_items { + trace!("{}", &item); + } + } + + autodiff_items +} diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 62a7c84bc28..7eeed721d5a 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -522,7 +522,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz // FIXME: See comment above -- we could fold the region separately or something. ty::ConstKind::Bound(_, _) | ty::ConstKind::Unevaluated(_) - | ty::ConstKind::Value(_, _) + | ty::ConstKind::Value(_) | ty::ConstKind::Error(_) | ty::ConstKind::Expr(_) => return c.super_fold_with(self), }; diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 8d1194ee539..1fa35b60304 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -160,9 +160,7 @@ where ty::ConstKind::Infer(_) => { self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } - ty::ConstKind::Placeholder(_) - | ty::ConstKind::Value(_, _) - | ty::ConstKind::Error(_) => { + ty::ConstKind::Placeholder(_) | ty::ConstKind::Value(_) | ty::ConstKind::Error(_) => { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } // We can freely ICE here as: @@ -199,7 +197,7 @@ where unreachable!("`ConstKind::Param` should have been canonicalized to `Placeholder`") } ty::ConstKind::Bound(_, _) => panic!("escaping bound vars in {:?}", ct), - ty::ConstKind::Value(ty, _) => ty, + ty::ConstKind::Value(cv) => cv.ty(), ty::ConstKind::Placeholder(placeholder) => { self.cx().find_const_ty_from_env(goal.param_env, placeholder) } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index a5b73ce4098..ffd46f20767 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3114,9 +3114,8 @@ impl<'a> Parser<'a> { let span_before_body = this.prev_token.span; let arm_body; let is_fat_arrow = this.check(exp!(FatArrow)); - let is_almost_fat_arrow = TokenKind::FatArrow - .similar_tokens() - .is_some_and(|similar_tokens| similar_tokens.contains(&this.token.kind)); + let is_almost_fat_arrow = + TokenKind::FatArrow.similar_tokens().contains(&this.token.kind); // this avoids the compiler saying that a `,` or `}` was expected even though // the pattern isn't a never pattern (and thus an arm body is required) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 714a60cb179..faebb5a40bb 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -924,10 +924,8 @@ impl<'a> Parser<'a> { _ => { // Attempt to keep parsing if it was a similar separator. - if let Some(tokens) = exp.tok.similar_tokens() { - if tokens.contains(&self.token.kind) { - self.bump(); - } + if exp.tok.similar_tokens().contains(&self.token.kind) { + self.bump(); } } } diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 09c88e7f83b..d021ea107ed 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -363,12 +363,7 @@ impl<'a> Parser<'a> { /// Notifies of an error. The message doesn't actually need to be of type /// String, but I think it does when this eventually uses conditions so it /// might as well start using it now. - fn err<S1: Into<String>, S2: Into<String>>( - &mut self, - description: S1, - label: S2, - span: InnerSpan, - ) { + fn err(&mut self, description: impl Into<String>, label: impl Into<String>, span: InnerSpan) { self.errors.push(ParseError { description: description.into(), note: None, @@ -382,11 +377,11 @@ impl<'a> Parser<'a> { /// Notifies of an error. The message doesn't actually need to be of type /// String, but I think it does when this eventually uses conditions so it /// might as well start using it now. - fn err_with_note<S1: Into<String>, S2: Into<String>, S3: Into<String>>( + fn err_with_note( &mut self, - description: S1, - label: S2, - note: S3, + description: impl Into<String>, + label: impl Into<String>, + note: impl Into<String>, span: InnerSpan, ) { self.errors.push(ParseError { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index e19819a22b4..837da6e7724 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -2471,6 +2471,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }))), terr, false, + None, ); diag.emit(); self.abort.set(true); diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index 75b62a40ff9..6d9c70177a4 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -5,10 +5,10 @@ use rustc_ast::visit::BoundKind; use rustc_ast::{self as ast, NodeId, visit as ast_visit}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::thousands::format_with_underscores; use rustc_hir::{self as hir, AmbigArg, HirId, intravisit as hir_visit}; use rustc_middle::hir::map::Map; use rustc_middle::ty::TyCtxt; -use rustc_middle::util::common::to_readable_str; use rustc_span::Span; use rustc_span::def_id::LocalDefId; @@ -144,10 +144,10 @@ impl<'k> StatCollector<'k> { "{} {:<18}{:>10} ({:4.1}%){:>14}{:>14}", prefix, label, - to_readable_str(size), + format_with_underscores(size), percent(size, total_size), - to_readable_str(node.stats.count), - to_readable_str(node.stats.size) + format_with_underscores(node.stats.count), + format_with_underscores(node.stats.size) ); if !node.subnodes.is_empty() { // We will soon sort, so the initial order does not matter. @@ -163,9 +163,9 @@ impl<'k> StatCollector<'k> { "{} - {:<18}{:>10} ({:4.1}%){:>14}", prefix, label, - to_readable_str(size), + format_with_underscores(size), percent(size, total_size), - to_readable_str(subnode.count), + format_with_underscores(subnode.count), ); } } @@ -175,8 +175,8 @@ impl<'k> StatCollector<'k> { "{} {:<18}{:>10} {:>14}", prefix, "Total", - to_readable_str(total_size), - to_readable_str(total_count), + format_with_underscores(total_size), + format_with_underscores(total_count), ); eprintln!("{prefix}"); } diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 73da8855e10..60f7616a5fb 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1522,6 +1522,14 @@ impl<'tcx> Liveness<'_, 'tcx> { } fn warn_about_unused_args(&self, body: &hir::Body<'_>, entry_ln: LiveNode) { + if let Some(intrinsic) = + self.ir.tcx.intrinsic(self.ir.tcx.hir().body_owner_def_id(body.id())) + { + if intrinsic.must_be_overridden { + return; + } + } + for p in body.params { self.check_unused_vars_in_pat( p.pat, diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index a52f080038d..34f1ca55c78 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -5,8 +5,8 @@ use std::mem::replace; use std::num::NonZero; use rustc_attr_parsing::{ - self as attr, AllowedThroughUnstableModules, ConstStability, DeprecatedSince, Stability, - StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER, + self as attr, ConstStability, DeprecatedSince, Stability, StabilityLevel, StableSince, + UnstableReason, VERSION_PLACEHOLDER, }; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; @@ -880,7 +880,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { if item_is_allowed { // The item itself is allowed; check whether the path there is also allowed. - let is_allowed_through_unstable_modules: Option<AllowedThroughUnstableModules> = + let is_allowed_through_unstable_modules: Option<Symbol> = self.tcx.lookup_stability(def_id).and_then(|stab| match stab.level { StabilityLevel::Stable { allowed_through_unstable_modules, .. } => { allowed_through_unstable_modules @@ -888,83 +888,79 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { _ => None, }); - if is_allowed_through_unstable_modules.is_none() { - // Check parent modules stability as well if the item the path refers to is itself - // stable. We only emit warnings for unstable path segments if the item is stable - // or allowed because stability is often inherited, so the most common case is that - // both the segments and the item are unstable behind the same feature flag. - // - // We check here rather than in `visit_path_segment` to prevent visiting the last - // path segment twice - // - // We include special cases via #[rustc_allowed_through_unstable_modules] for items - // that were accidentally stabilized through unstable paths before this check was - // added, such as `core::intrinsics::transmute` - let parents = path.segments.iter().rev().skip(1); - for path_segment in parents { - if let Some(def_id) = path_segment.res.opt_def_id() { - // use `None` for id to prevent deprecation check - self.tcx.check_stability_allow_unstable( - def_id, - None, - path.span, - None, - if is_unstable_reexport(self.tcx, id) { - AllowUnstable::Yes - } else { - AllowUnstable::No - }, - ); - } - } - } else if let Some(AllowedThroughUnstableModules::WithDeprecation(deprecation)) = - is_allowed_through_unstable_modules - { - // Similar to above, but we cannot use `check_stability_allow_unstable` as that would - // immediately show the stability error. We just want to know the result and disaplay - // our own kind of error. - let parents = path.segments.iter().rev().skip(1); - for path_segment in parents { - if let Some(def_id) = path_segment.res.opt_def_id() { - // use `None` for id to prevent deprecation check - let eval_result = self.tcx.eval_stability_allow_unstable( - def_id, - None, - path.span, - None, - if is_unstable_reexport(self.tcx, id) { - AllowUnstable::Yes - } else { - AllowUnstable::No - }, - ); - let is_allowed = matches!(eval_result, EvalResult::Allow); - if !is_allowed { - // Calculating message for lint involves calling `self.def_path_str`, - // which will by default invoke the expensive `visible_parent_map` query. - // Skip all that work if the lint is allowed anyway. - if self.tcx.lint_level_at_node(DEPRECATED, id).0 - == lint::Level::Allow - { - return; - } - // Show a deprecation message. - let def_path = - with_no_trimmed_paths!(self.tcx.def_path_str(def_id)); - let def_kind = self.tcx.def_descr(def_id); - let diag = Deprecated { - sub: None, - kind: def_kind.to_owned(), - path: def_path, - note: Some(deprecation), - since_kind: lint::DeprecatedSinceKind::InEffect, - }; - self.tcx.emit_node_span_lint( - DEPRECATED, - id, - method_span.unwrap_or(path.span), - diag, + // Check parent modules stability as well if the item the path refers to is itself + // stable. We only emit errors for unstable path segments if the item is stable + // or allowed because stability is often inherited, so the most common case is that + // both the segments and the item are unstable behind the same feature flag. + // + // We check here rather than in `visit_path_segment` to prevent visiting the last + // path segment twice + // + // We include special cases via #[rustc_allowed_through_unstable_modules] for items + // that were accidentally stabilized through unstable paths before this check was + // added, such as `core::intrinsics::transmute` + let parents = path.segments.iter().rev().skip(1); + for path_segment in parents { + if let Some(def_id) = path_segment.res.opt_def_id() { + match is_allowed_through_unstable_modules { + None => { + // Emit a hard stability error if this path is not stable. + + // use `None` for id to prevent deprecation check + self.tcx.check_stability_allow_unstable( + def_id, + None, + path.span, + None, + if is_unstable_reexport(self.tcx, id) { + AllowUnstable::Yes + } else { + AllowUnstable::No + }, + ); + } + Some(deprecation) => { + // Call the stability check directly so that we can control which + // diagnostic is emitted. + let eval_result = self.tcx.eval_stability_allow_unstable( + def_id, + None, + path.span, + None, + if is_unstable_reexport(self.tcx, id) { + AllowUnstable::Yes + } else { + AllowUnstable::No + }, ); + let is_allowed = matches!(eval_result, EvalResult::Allow); + if !is_allowed { + // Calculating message for lint involves calling `self.def_path_str`, + // which will by default invoke the expensive `visible_parent_map` query. + // Skip all that work if the lint is allowed anyway. + if self.tcx.lint_level_at_node(DEPRECATED, id).0 + == lint::Level::Allow + { + return; + } + // Show a deprecation message. + let def_path = + with_no_trimmed_paths!(self.tcx.def_path_str(def_id)); + let def_kind = self.tcx.def_descr(def_id); + let diag = Deprecated { + sub: None, + kind: def_kind.to_owned(), + path: def_path, + note: Some(deprecation), + since_kind: lint::DeprecatedSinceKind::InEffect, + }; + self.tcx.emit_node_span_lint( + DEPRECATED, + id, + method_span.unwrap_or(path.span), + diag, + ); + } } } } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index d19df08519d..3842b7035e5 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -24,7 +24,7 @@ use rustc_ast::MacroDef; use rustc_ast::visit::{VisitorResult, try_visit}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; -use rustc_errors::MultiSpan; +use rustc_errors::{MultiSpan, listify}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, InferKind, Visitor}; @@ -958,29 +958,15 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { // | ^^ field `gamma` is private # `fields.2` is `false` // Get the list of all private fields for the main message. - let field_names: Vec<_> = fields.iter().map(|(name, _, _)| name).collect(); - let field_names = match &field_names[..] { - [] => return, - [name] => format!("`{name}`"), - [fields @ .., last] => format!( - "{} and `{last}`", - fields.iter().map(|f| format!("`{f}`")).collect::<Vec<_>>().join(", "), - ), - }; + let Some(field_names) = listify(&fields[..], |(n, _, _)| format!("`{n}`")) else { return }; let span: MultiSpan = fields.iter().map(|(_, span, _)| *span).collect::<Vec<Span>>().into(); // Get the list of all private fields when pointing at the `..rest`. let rest_field_names: Vec<_> = fields.iter().filter(|(_, _, is_present)| !is_present).map(|(n, _, _)| n).collect(); let rest_len = rest_field_names.len(); - let rest_field_names = match &rest_field_names[..] { - [] => String::new(), - [name] => format!("`{name}`"), - [fields @ .., last] => format!( - "{} and `{last}`", - fields.iter().map(|f| format!("`{f}`")).collect::<Vec<_>>().join(", "), - ), - }; + let rest_field_names = + listify(&rest_field_names[..], |n| format!("`{n}`")).unwrap_or_default(); // Get all the labels for each field or `..rest` in the primary MultiSpan. let labels = fields .iter() @@ -1005,7 +991,7 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { } else { None }, - field_names: field_names.clone(), + field_names, variant_descr: def.variant_descr(), def_path_str: self.tcx.def_path_str(def.did()), labels, diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index d2bb0b3f277..bbc83cca99d 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -224,7 +224,6 @@ pub fn query_system<'a>( rustc_middle::rustc_query_append! { define_queries! } pub fn provide(providers: &mut rustc_middle::util::Providers) { - providers.hooks.alloc_self_profile_query_strings = - |tcx| alloc_self_profile_query_strings(tcx.tcx); - providers.hooks.query_key_hash_verify_all = |tcx| query_key_hash_verify_all(tcx.tcx); + providers.hooks.alloc_self_profile_query_strings = alloc_self_profile_query_strings; + providers.hooks.query_key_hash_verify_all = query_key_hash_verify_all; } 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 09648e28df4..5f0c1afdf64 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 @@ -103,7 +103,7 @@ fn encode_args<'tcx>( /// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling.literal>). fn encode_const<'tcx>( tcx: TyCtxt<'tcx>, - c: Const<'tcx>, + ct: Const<'tcx>, ct_ty: Ty<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>, usize>, options: EncodeTyOptions, @@ -111,7 +111,7 @@ fn encode_const<'tcx>( // L<element-type>[n][<element-value>]E as literal argument let mut s = String::from('L'); - match c.kind() { + match ct.kind() { // Const parameters ty::ConstKind::Param(..) => { // L<element-type>E as literal argument @@ -121,18 +121,18 @@ fn encode_const<'tcx>( } // Literal arguments - ty::ConstKind::Value(ct_ty, ..) => { + ty::ConstKind::Value(cv) => { // L<element-type>[n]<element-value>E as literal argument // Element type - s.push_str(&encode_ty(tcx, ct_ty, dict, options)); + s.push_str(&encode_ty(tcx, cv.ty, dict, options)); // The only allowed types of const values are bool, u8, u16, u32, // u64, u128, usize i8, i16, i32, i64, i128, isize, and char. The // bool value false is encoded as 0 and true as 1. - match ct_ty.kind() { + match cv.ty.kind() { ty::Int(ity) => { - let bits = c + let bits = cv .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized()) .expect("expected monomorphic const in cfi"); let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; @@ -142,30 +142,30 @@ fn encode_const<'tcx>( let _ = write!(s, "{val}"); } ty::Uint(_) => { - let val = c + let val = cv .try_to_bits(tcx, ty::TypingEnv::fully_monomorphized()) .expect("expected monomorphic const in cfi"); let _ = write!(s, "{val}"); } ty::Bool => { - let val = c.try_to_bool().expect("expected monomorphic const in cfi"); + let val = cv.try_to_bool().expect("expected monomorphic const in cfi"); let _ = write!(s, "{val}"); } _ => { - bug!("encode_const: unexpected type `{:?}`", ct_ty); + bug!("encode_const: unexpected type `{:?}`", cv.ty); } } } _ => { - bug!("encode_const: unexpected kind `{:?}`", c.kind()); + bug!("encode_const: unexpected kind `{:?}`", ct.kind()); } } // Close the "L..E" pair s.push('E'); - compress(dict, DictKey::Const(c), &mut s); + compress(dict, DictKey::Const(ct), &mut s); s } 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 9c6186d6882..b711c238d59 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 @@ -51,8 +51,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> { // Transforms a ty:Ty for being encoded and used in the substitution dictionary. fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match t.kind() { - ty::Array(..) - | ty::Closure(..) + ty::Closure(..) | ty::Coroutine(..) | ty::CoroutineClosure(..) | ty::CoroutineWitness(..) @@ -67,6 +66,13 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> { | ty::Tuple(..) | ty::UnsafeBinder(_) => t.super_fold_with(self), + // Don't transform the type of the array length and keep it as `usize`. + // This is required for `try_to_target_usize` to work correctly. + &ty::Array(inner, len) => { + let inner = self.fold_ty(inner); + Ty::new_array_with_const_len(self.tcx, inner, len) + } + ty::Bool => { if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { // Note: on all platforms that Rust's currently supports, its size and alignment diff --git a/compiler/rustc_session/src/code_stats.rs b/compiler/rustc_session/src/code_stats.rs index f3c21992784..b4597ae2515 100644 --- a/compiler/rustc_session/src/code_stats.rs +++ b/compiler/rustc_session/src/code_stats.rs @@ -1,10 +1,9 @@ use std::cmp; use rustc_abi::{Align, Size}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lock; use rustc_span::Symbol; -use rustc_span::def_id::DefId; #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct VariantInfo { @@ -71,29 +70,9 @@ pub struct TypeSizeInfo { pub variants: Vec<VariantInfo>, } -pub struct VTableSizeInfo { - pub trait_name: String, - - /// Number of entries in a vtable with the current algorithm - /// (i.e. with upcasting). - pub entries: usize, - - /// Number of entries in a vtable, as-if we did not have trait upcasting. - pub entries_ignoring_upcasting: usize, - - /// Number of entries in a vtable needed solely for upcasting - /// (i.e. `entries - entries_ignoring_upcasting`). - pub entries_for_upcasting: usize, - - /// Cost of having upcasting in % relative to the number of entries without - /// upcasting (i.e. `entries_for_upcasting / entries_ignoring_upcasting * 100%`). - pub upcasting_cost_percent: f64, -} - #[derive(Default)] pub struct CodeStats { type_sizes: Lock<FxHashSet<TypeSizeInfo>>, - vtable_sizes: Lock<FxHashMap<DefId, VTableSizeInfo>>, } impl CodeStats { @@ -127,14 +106,6 @@ impl CodeStats { self.type_sizes.borrow_mut().insert(info); } - pub fn record_vtable_size(&self, trait_did: DefId, trait_name: &str, info: VTableSizeInfo) { - let prev = self.vtable_sizes.lock().insert(trait_did, info); - assert!( - prev.is_none(), - "size of vtable for `{trait_name}` ({trait_did:?}) is already recorded" - ); - } - pub fn print_type_sizes(&self) { let type_sizes = self.type_sizes.borrow(); // We will soon sort, so the initial order does not matter. @@ -238,33 +209,4 @@ impl CodeStats { } } } - - pub fn print_vtable_sizes(&self, crate_name: Symbol) { - // We will soon sort, so the initial order does not matter. - #[allow(rustc::potential_query_instability)] - let mut infos = - std::mem::take(&mut *self.vtable_sizes.lock()).into_values().collect::<Vec<_>>(); - - // Primary sort: cost % in reverse order (from largest to smallest) - // Secondary sort: trait_name - infos.sort_by(|a, b| { - a.upcasting_cost_percent - .total_cmp(&b.upcasting_cost_percent) - .reverse() - .then_with(|| a.trait_name.cmp(&b.trait_name)) - }); - - for VTableSizeInfo { - trait_name, - entries, - entries_ignoring_upcasting, - entries_for_upcasting, - upcasting_cost_percent, - } in infos - { - println!( - r#"print-vtable-sizes {{ "crate_name": "{crate_name}", "trait_name": "{trait_name}", "entries": "{entries}", "entries_ignoring_upcasting": "{entries_ignoring_upcasting}", "entries_for_upcasting": "{entries_for_upcasting}", "upcasting_cost_percent": "{upcasting_cost_percent}" }}"# - ); - } - } } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 97bd2670aa6..2fb4b27b889 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -189,6 +189,39 @@ pub enum CoverageLevel { Mcdc, } +/// The different settings that the `-Z autodiff` flag can have. +#[derive(Clone, Copy, PartialEq, Hash, Debug)] +pub enum AutoDiff { + /// Print TypeAnalysis information + PrintTA, + /// Print ActivityAnalysis Information + PrintAA, + /// Print Performance Warnings from Enzyme + PrintPerf, + /// Combines the three print flags above. + Print, + /// Print the whole module, before running opts. + PrintModBefore, + /// Print the whole module just before we pass it to Enzyme. + /// For Debug purpose, prefer the OPT flag below + PrintModAfterOpts, + /// Print the module after Enzyme differentiated everything. + PrintModAfterEnzyme, + + /// Enzyme's loose type debug helper (can cause incorrect gradients) + LooseTypes, + + /// More flags + NoModOptAfter, + /// Tell Enzyme to run LLVM Opts on each function it generated. By default off, + /// since we already optimize the whole module after Enzyme is done. + EnableFncOpt, + NoVecUnroll, + RuntimeActivity, + /// Runs Enzyme specific Inlining + Inline, +} + /// Settings for `-Z instrument-xray` flag. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] pub struct InstrumentXRay { @@ -1191,6 +1224,7 @@ impl Default for Options { color: ColorConfig::Auto, logical_env: FxIndexMap::default(), verbose: false, + target_modifiers: BTreeMap::default(), } } } @@ -1786,7 +1820,7 @@ pub fn parse_error_format( ErrorOutputType::HumanReadable(HumanReadableErrorType::Unicode, color) } Some(arg) => { - early_dcx.abort_if_error_and_set_error_format(ErrorOutputType::HumanReadable( + early_dcx.set_error_format(ErrorOutputType::HumanReadable( HumanReadableErrorType::Default, color, )); @@ -2327,7 +2361,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let error_format = parse_error_format(early_dcx, matches, color, json_color, json_rendered); - early_dcx.abort_if_error_and_set_error_format(error_format); + early_dcx.set_error_format(error_format); let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| { early_dcx.early_fatal("`--diagnostic-width` must be an positive integer"); @@ -2337,14 +2371,16 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let crate_types = parse_crate_types_from_list(unparsed_crate_types) .unwrap_or_else(|e| early_dcx.early_fatal(e)); - let mut unstable_opts = UnstableOptions::build(early_dcx, matches); + let mut target_modifiers = BTreeMap::<OptionsTargetModifiers, String>::new(); + + let mut unstable_opts = UnstableOptions::build(early_dcx, matches, &mut target_modifiers); let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches); check_error_format_stability(early_dcx, &unstable_opts, error_format); let output_types = parse_output_types(early_dcx, &unstable_opts, matches); - let mut cg = CodegenOptions::build(early_dcx, matches); + let mut cg = CodegenOptions::build(early_dcx, matches, &mut target_modifiers); let (disable_local_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto( early_dcx, &output_types, @@ -2615,6 +2651,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M color, logical_env, verbose, + target_modifiers, } } @@ -2737,6 +2774,7 @@ pub mod nightly_options { "the option `{}` is only accepted on the nightly compiler", opt.name ); + // The non-zero nightly_options_on_stable will force an early_fatal eventually. let _ = early_dcx.early_err(msg); } OptionStability::Stable => {} @@ -2902,7 +2940,7 @@ pub(crate) mod dep_tracking { }; use super::{ - BranchProtection, CFGuard, CFProtection, CollapseMacroDebuginfo, CoverageOptions, + AutoDiff, BranchProtection, CFGuard, CFProtection, CollapseMacroDebuginfo, CoverageOptions, CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FmtDebug, FunctionReturn, InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail, LtoCli, MirStripDebugInfo, NextSolverConfig, OomStrategy, OptLevel, OutFileName, @@ -2950,6 +2988,7 @@ pub(crate) mod dep_tracking { } impl_dep_tracking_hash_via_hash!( + AutoDiff, bool, usize, NonZero<usize>, diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index dcf86d1a408..924350b8cbc 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -4,6 +4,9 @@ #![feature(let_chains)] #![feature(map_many_mut)] #![feature(rustc_attrs)] +// To generate CodegenOptionsTargetModifiers and UnstableOptionsTargetModifiers enums +// with macro_rules, it is necessary to use recursive mechanic ("Incremental TT Munchers"). +#![recursion_limit = "256"] #![warn(unreachable_pub)] // tidy-alphabetical-end diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 4ce63825129..4ed5499d32c 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -10,6 +10,7 @@ use rustc_data_structures::profiling::TimePassesFormat; use rustc_data_structures::stable_hasher::Hash64; use rustc_errors::{ColorConfig, LanguageIdentifier, TerminalUrl}; use rustc_feature::UnstableFeatures; +use rustc_macros::{Decodable, Encodable}; use rustc_span::edition::Edition; use rustc_span::{RealFileName, SourceFileHashAlgorithm}; use rustc_target::spec::{ @@ -59,18 +60,194 @@ macro_rules! hash_substruct { }; } +/// Extended target modifier info. +/// For example, when external target modifier is '-Zregparm=2': +/// Target modifier enum value + user value ('2') from external crate +/// is converted into description: prefix ('Z'), name ('regparm'), tech value ('Some(2)'). +pub struct ExtendedTargetModifierInfo { + /// Flag prefix (usually, 'C' for codegen flags or 'Z' for unstable flags) + pub prefix: String, + /// Flag name + pub name: String, + /// Flag parsed technical value + pub tech_value: String, +} + +/// A recorded -Zopt_name=opt_value (or -Copt_name=opt_value) +/// which alter the ABI or effectiveness of exploit mitigations. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)] +pub struct TargetModifier { + /// Option enum value + pub opt: OptionsTargetModifiers, + /// User-provided option value (before parsing) + pub value_name: String, +} + +impl TargetModifier { + pub fn extend(&self) -> ExtendedTargetModifierInfo { + self.opt.reparse(&self.value_name) + } +} + +fn tmod_push_impl( + opt: OptionsTargetModifiers, + tmod_vals: &BTreeMap<OptionsTargetModifiers, String>, + tmods: &mut Vec<TargetModifier>, +) { + tmods.push(TargetModifier { opt, value_name: tmod_vals.get(&opt).cloned().unwrap_or_default() }) +} + +macro_rules! tmod_push { + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $mods:expr, $tmod_vals:expr) => { + tmod_push_impl( + OptionsTargetModifiers::$struct_name($tmod_enum_name::$opt_name), + $tmod_vals, + $mods, + ); + }; +} + +macro_rules! gather_tmods { + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + [SUBSTRUCT], [TARGET_MODIFIER]) => { + compile_error!("SUBSTRUCT can't be target modifier"); + }; + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + [UNTRACKED], [TARGET_MODIFIER]) => { + tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals) + }; + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + [TRACKED], [TARGET_MODIFIER]) => { + tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals) + }; + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + [TRACKED_NO_CRATE_HASH], [TARGET_MODIFIER]) => { + tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals) + }; + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + [SUBSTRUCT], []) => { + $opt_expr.gather_target_modifiers($mods, $tmod_vals); + }; + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + [UNTRACKED], []) => {{}}; + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + [TRACKED], []) => {{}}; + ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, + [TRACKED_NO_CRATE_HASH], []) => {{}}; +} + +macro_rules! gather_tmods_top_level { + ($_opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, [SUBSTRUCT $substruct_enum:ident]) => { + $opt_expr.gather_target_modifiers($mods, $tmod_vals); + }; + ($opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, [$non_substruct:ident TARGET_MODIFIER]) => { + compile_error!("Top level option can't be target modifier"); + }; + ($opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, [$non_substruct:ident]) => {}; +} + +/// Macro for generating OptionsTargetsModifiers top-level enum with impl. +/// Will generate something like: +/// ```rust,ignore (illustrative) +/// pub enum OptionsTargetModifiers { +/// CodegenOptions(CodegenOptionsTargetModifiers), +/// UnstableOptions(UnstableOptionsTargetModifiers), +/// } +/// impl OptionsTargetModifiers { +/// pub fn reparse(&self, user_value: &str) -> ExtendedTargetModifierInfo { +/// match self { +/// Self::CodegenOptions(v) => v.reparse(user_value), +/// Self::UnstableOptions(v) => v.reparse(user_value), +/// } +/// } +/// pub fn is_target_modifier(flag_name: &str) -> bool { +/// CodegenOptionsTargetModifiers::is_target_modifier(flag_name) || +/// UnstableOptionsTargetModifiers::is_target_modifier(flag_name) +/// } +/// } +/// ``` +macro_rules! top_level_tmod_enum { + ($( {$($optinfo:tt)*} ),* $(,)*) => { + top_level_tmod_enum! { @parse {}, (user_value){}; $($($optinfo)*|)* } + }; + // Termination + ( + @parse + {$($variant:tt($substruct_enum:tt))*}, + ($user_value:ident){$($pout:tt)*}; + ) => { + #[allow(non_camel_case_types)] + #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Copy, Clone, Encodable, Decodable)] + pub enum OptionsTargetModifiers { + $($variant($substruct_enum)),* + } + impl OptionsTargetModifiers { + #[allow(unused_variables)] + pub fn reparse(&self, $user_value: &str) -> ExtendedTargetModifierInfo { + #[allow(unreachable_patterns)] + match self { + $($pout)* + _ => panic!("unknown target modifier option: {:?}", *self) + } + } + pub fn is_target_modifier(flag_name: &str) -> bool { + $($substruct_enum::is_target_modifier(flag_name))||* + } + } + }; + // Adding SUBSTRUCT option group into $eout + ( + @parse {$($eout:tt)*}, ($puser_value:ident){$($pout:tt)*}; + [SUBSTRUCT $substruct_enum:ident $variant:ident] | + $($tail:tt)* + ) => { + top_level_tmod_enum! { + @parse + { + $($eout)* + $variant($substruct_enum) + }, + ($puser_value){ + $($pout)* + Self::$variant(v) => v.reparse($puser_value), + }; + $($tail)* + } + }; + // Skipping non-target-modifier and non-substruct + ( + @parse {$($eout:tt)*}, ($puser_value:ident){$($pout:tt)*}; + [$non_substruct:ident] | + $($tail:tt)* + ) => { + top_level_tmod_enum! { + @parse + { + $($eout)* + }, + ($puser_value){ + $($pout)* + }; + $($tail)* + } + }; +} + macro_rules! top_level_options { ( $( #[$top_level_attr:meta] )* pub struct Options { $( $( #[$attr:meta] )* - $opt:ident : $t:ty [$dep_tracking_marker:ident], + $opt:ident : $t:ty [$dep_tracking_marker:ident $( $tmod:ident $variant:ident )?], )* } ) => ( + top_level_tmod_enum!( {$([$dep_tracking_marker $($tmod $variant),*])|*} ); + #[derive(Clone)] $( #[$top_level_attr] )* pub struct Options { $( $( #[$attr] )* pub $opt: $t - ),* + ),*, + pub target_modifiers: BTreeMap<OptionsTargetModifiers, String>, } impl Options { @@ -98,6 +275,17 @@ macro_rules! top_level_options { })* hasher.finish() } + + pub fn gather_target_modifiers(&self) -> Vec<TargetModifier> { + let mut mods = Vec::<TargetModifier>::new(); + $({ + gather_tmods_top_level!($opt, + &self.$opt, &mut mods, &self.target_modifiers, + [$dep_tracking_marker $($tmod),*]); + })* + mods.sort_by(|a, b| a.opt.cmp(&b.opt)); + mods + } } ); } @@ -165,9 +353,9 @@ top_level_options!( #[rustc_lint_opt_deny_field_access("should only be used via `Config::hash_untracked_state`")] untracked_state_hash: Hash64 [TRACKED_NO_CRATE_HASH], - unstable_opts: UnstableOptions [SUBSTRUCT], + unstable_opts: UnstableOptions [SUBSTRUCT UnstableOptionsTargetModifiers UnstableOptions], prints: Vec<PrintRequest> [UNTRACKED], - cg: CodegenOptions [SUBSTRUCT], + cg: CodegenOptions [SUBSTRUCT CodegenOptionsTargetModifiers CodegenOptions], externs: Externs [UNTRACKED], crate_name: Option<String> [TRACKED], /// Indicates how the compiler should treat unstable features. @@ -226,6 +414,98 @@ top_level_options!( } ); +macro_rules! tmod_enum_opt { + ($struct_name:ident, $tmod_enum_name:ident, $opt:ident, $v:ident) => { + Some(OptionsTargetModifiers::$struct_name($tmod_enum_name::$opt)) + }; + ($struct_name:ident, $tmod_enum_name:ident, $opt:ident, ) => { + None + }; +} + +macro_rules! tmod_enum { + ($tmod_enum_name:ident, $prefix:expr, $( {$($optinfo:tt)*} ),* $(,)*) => { + tmod_enum! { $tmod_enum_name, $prefix, @parse {}, (user_value){}; $($($optinfo)*|)* } + }; + // Termination + ( + $tmod_enum_name:ident, $prefix:expr, + @parse + {$($eout:tt)*}, + ($user_value:ident){$($pout:tt)*}; + ) => { + #[allow(non_camel_case_types)] + #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Copy, Clone, Encodable, Decodable)] + pub enum $tmod_enum_name { + $($eout),* + } + impl $tmod_enum_name { + #[allow(unused_variables)] + pub fn reparse(&self, $user_value: &str) -> ExtendedTargetModifierInfo { + #[allow(unreachable_patterns)] + match self { + $($pout)* + _ => panic!("unknown target modifier option: {:?}", *self) + } + } + pub fn is_target_modifier(flag_name: &str) -> bool { + match flag_name.replace('-', "_").as_str() { + $(stringify!($eout) => true,)* + _ => false, + } + } + } + }; + // Adding target-modifier option into $eout + ( + $tmod_enum_name:ident, $prefix:expr, + @parse {$($eout:tt)*}, ($puser_value:ident){$($pout:tt)*}; + $opt:ident, $parse:ident, $t:ty, [TARGET_MODIFIER] | + $($tail:tt)* + ) => { + tmod_enum! { + $tmod_enum_name, $prefix, + @parse + { + $($eout)* + $opt + }, + ($puser_value){ + $($pout)* + Self::$opt => { + let mut parsed : $t = Default::default(); + parse::$parse(&mut parsed, Some($puser_value)); + ExtendedTargetModifierInfo { + prefix: $prefix.to_string(), + name: stringify!($opt).to_string().replace('_', "-"), + tech_value: format!("{:?}", parsed), + } + }, + }; + $($tail)* + } + }; + // Skipping non-target-modifier + ( + $tmod_enum_name:ident, $prefix:expr, + @parse {$($eout:tt)*}, ($puser_value:ident){$($pout:tt)*}; + $opt:ident, $parse:ident, $t:ty, [] | + $($tail:tt)* + ) => { + tmod_enum! { + $tmod_enum_name, $prefix, + @parse + { + $($eout)* + }, + ($puser_value){ + $($pout)* + }; + $($tail)* + } + }; +} + /// Defines all `CodegenOptions`/`DebuggingOptions` fields and parsers all at once. The goal of this /// macro is to define an interface that can be programmatically used by the option parser /// to initialize the struct without hardcoding field names all over the place. @@ -235,11 +515,11 @@ top_level_options!( /// generated code to parse an option into its respective field in the struct. There are a few /// hand-written parsers for parsing specific types of values in this module. macro_rules! options { - ($struct_name:ident, $stat:ident, $optmod:ident, $prefix:expr, $outputname:expr, + ($struct_name:ident, $tmod_enum_name:ident, $stat:ident, $optmod:ident, $prefix:expr, $outputname:expr, $($( #[$attr:meta] )* $opt:ident : $t:ty = ( $init:expr, $parse:ident, - [$dep_tracking_marker:ident], + [$dep_tracking_marker:ident $( $tmod:ident )?], $desc:expr $(, deprecated_do_nothing: $dnn:literal )?) ),* ,) => @@ -248,6 +528,8 @@ macro_rules! options { #[rustc_lint_opt_ty] pub struct $struct_name { $( $( #[$attr] )* pub $opt: $t),* } + tmod_enum!( $tmod_enum_name, $prefix, {$($opt, $parse, $t, [$($tmod),*])|*} ); + impl Default for $struct_name { fn default() -> $struct_name { $struct_name { $($opt: $init),* } @@ -258,8 +540,9 @@ macro_rules! options { pub fn build( early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches, + target_modifiers: &mut BTreeMap<OptionsTargetModifiers, String>, ) -> $struct_name { - build_options(early_dcx, matches, $stat, $prefix, $outputname) + build_options(early_dcx, matches, target_modifiers, $stat, $prefix, $outputname) } fn dep_tracking_hash(&self, for_crate_hash: bool, error_format: ErrorOutputType) -> u64 { @@ -279,11 +562,23 @@ macro_rules! options { ); hasher.finish() } + + pub fn gather_target_modifiers( + &self, + _mods: &mut Vec<TargetModifier>, + _tmod_vals: &BTreeMap<OptionsTargetModifiers, String>, + ) { + $({ + gather_tmods!($struct_name, $tmod_enum_name, $opt, &self.$opt, _mods, _tmod_vals, + [$dep_tracking_marker], [$($tmod),*]); + })* + } } pub const $stat: OptionDescrs<$struct_name> = &[ $( OptionDesc{ name: stringify!($opt), setter: $optmod::$opt, - type_desc: desc::$parse, desc: $desc, is_deprecated_and_do_nothing: false $( || $dnn )? } ),* ]; + type_desc: desc::$parse, desc: $desc, is_deprecated_and_do_nothing: false $( || $dnn )?, + tmod: tmod_enum_opt!($struct_name, $tmod_enum_name, $opt, $($tmod),*) } ),* ]; mod $optmod { $( @@ -328,6 +623,7 @@ pub struct OptionDesc<O> { // description for option from options table desc: &'static str, is_deprecated_and_do_nothing: bool, + tmod: Option<OptionsTargetModifiers>, } impl<O> OptionDesc<O> { @@ -344,6 +640,7 @@ impl<O> OptionDesc<O> { fn build_options<O: Default>( early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches, + target_modifiers: &mut BTreeMap<OptionsTargetModifiers, String>, descrs: OptionDescrs<O>, prefix: &str, outputname: &str, @@ -357,7 +654,14 @@ fn build_options<O: Default>( let option_to_lookup = key.replace('-', "_"); match descrs.iter().find(|opt_desc| opt_desc.name == option_to_lookup) { - Some(OptionDesc { name: _, setter, type_desc, desc, is_deprecated_and_do_nothing }) => { + Some(OptionDesc { + name: _, + setter, + type_desc, + desc, + is_deprecated_and_do_nothing, + tmod, + }) => { if *is_deprecated_and_do_nothing { // deprecation works for prefixed options only assert!(!prefix.is_empty()); @@ -377,6 +681,11 @@ fn build_options<O: Default>( ), } } + if let Some(tmod) = *tmod + && let Some(value) = value + { + target_modifiers.insert(tmod, value.to_string()); + } } None => early_dcx.early_fatal(format!("unknown {outputname} option: `{key}`")), } @@ -398,6 +707,7 @@ mod desc { pub(crate) const parse_list: &str = "a space-separated list of strings"; pub(crate) const parse_list_with_polarity: &str = "a comma-separated list of strings, with elements beginning with + or -"; + pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Print`, `PrintTA`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfterOpts`, `PrintModAfterEnzyme`, `LooseTypes`, `NoModOptAfter`, `EnableFncOpt`, `NoVecUnroll`, `Inline`"; pub(crate) const parse_comma_list: &str = "a comma-separated list of strings"; pub(crate) const parse_opt_comma_list: &str = parse_comma_list; pub(crate) const parse_number: &str = "a number"; @@ -1029,6 +1339,38 @@ pub mod parse { } } + pub(crate) fn parse_autodiff(slot: &mut Vec<AutoDiff>, v: Option<&str>) -> bool { + let Some(v) = v else { + *slot = vec![]; + return true; + }; + let mut v: Vec<&str> = v.split(",").collect(); + v.sort_unstable(); + for &val in v.iter() { + let variant = match val { + "PrintTA" => AutoDiff::PrintTA, + "PrintAA" => AutoDiff::PrintAA, + "PrintPerf" => AutoDiff::PrintPerf, + "Print" => AutoDiff::Print, + "PrintModBefore" => AutoDiff::PrintModBefore, + "PrintModAfterOpts" => AutoDiff::PrintModAfterOpts, + "PrintModAfterEnzyme" => AutoDiff::PrintModAfterEnzyme, + "LooseTypes" => AutoDiff::LooseTypes, + "NoModOptAfter" => AutoDiff::NoModOptAfter, + "EnableFncOpt" => AutoDiff::EnableFncOpt, + "NoVecUnroll" => AutoDiff::NoVecUnroll, + "Inline" => AutoDiff::Inline, + _ => { + // FIXME(ZuseZ4): print an error saying which value is not recognized + return false; + } + }; + slot.push(variant); + } + + true + } + pub(crate) fn parse_instrument_coverage( slot: &mut InstrumentCoverage, v: Option<&str>, @@ -1581,7 +1923,7 @@ pub mod parse { } options! { - CodegenOptions, CG_OPTIONS, cgopts, "C", "codegen", + CodegenOptions, CodegenOptionsTargetModifiers, CG_OPTIONS, cgopts, "C", "codegen", // If you add a new option, please update: // - compiler/rustc_interface/src/tests.rs @@ -1712,6 +2054,8 @@ options! { target_feature: String = (String::new(), parse_target_feature, [TRACKED], "target specific attributes. (`rustc --print target-features` for details). \ This feature is unsafe."), + unsafe_allow_abi_mismatch: Vec<String> = (Vec::new(), parse_comma_list, [UNTRACKED], + "Allow incompatible target modifiers in dependency crates (comma separated list)"), // tidy-alphabetical-end // If you add a new option, please update: @@ -1720,7 +2064,7 @@ options! { } options! { - UnstableOptions, Z_OPTIONS, dbopts, "Z", "unstable", + UnstableOptions, UnstableOptionsTargetModifiers, Z_OPTIONS, dbopts, "Z", "unstable", // If you add a new option, please update: // - compiler/rustc_interface/src/tests.rs @@ -1736,6 +2080,22 @@ options! { either `loaded` or `not-loaded`."), assume_incomplete_release: bool = (false, parse_bool, [TRACKED], "make cfg(version) treat the current version as incomplete (default: no)"), + autodiff: Vec<crate::config::AutoDiff> = (Vec::new(), parse_autodiff, [TRACKED], + "a list of optional autodiff flags to enable + Optional extra settings: + `=PrintTA` + `=PrintAA` + `=PrintPerf` + `=Print` + `=PrintModBefore` + `=PrintModAfterOpts` + `=PrintModAfterEnzyme` + `=LooseTypes` + `=NoModOptAfter` + `=EnableFncOpt` + `=NoVecUnroll` + `=Inline` + Multiple options can be combined with commas."), #[rustc_lint_opt_deny_field_access("use `Session::binary_dep_depinfo` instead of this field")] binary_dep_depinfo: bool = (false, parse_bool, [TRACKED], "include artifacts (sysroot, crate dependencies) used during compilation in dep-info \ @@ -1803,6 +2163,7 @@ options! { "output statistics about monomorphization collection"), dump_mono_stats_format: DumpMonoStatsFormat = (DumpMonoStatsFormat::Markdown, parse_dump_mono_stats, [UNTRACKED], "the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)"), + #[rustc_lint_opt_deny_field_access("use `Session::dwarf_version` instead of this field")] dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED], "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"), dylib_lto: bool = (false, parse_bool, [UNTRACKED], @@ -2033,8 +2394,6 @@ options! { Note that this overwrites the effect `-Clink-dead-code` has on collection!"), print_type_sizes: bool = (false, parse_bool, [UNTRACKED], "print layout information for each type encountered (default: no)"), - print_vtable_sizes: bool = (false, parse_bool, [UNTRACKED], - "print size comparison between old and new vtable layouts (default: no)"), proc_macro_backtrace: bool = (false, parse_bool, [UNTRACKED], "show backtraces for panics during proc-macro execution (default: no)"), proc_macro_execution_strategy: ProcMacroExecutionStrategy = (ProcMacroExecutionStrategy::SameThread, @@ -2050,10 +2409,10 @@ options! { "enable queries of the dependency graph for regression testing (default: no)"), randomize_layout: bool = (false, parse_bool, [TRACKED], "randomize the layout of types (default: no)"), - reg_struct_return: bool = (false, parse_bool, [TRACKED], + reg_struct_return: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], "On x86-32 targets, it overrides the default ABI to return small structs in registers. It is UNSOUND to link together crates that use different values for this flag!"), - regparm: Option<u32> = (None, parse_opt_number, [TRACKED], + regparm: Option<u32> = (None, parse_opt_number, [TRACKED TARGET_MODIFIER], "On x86-32 targets, setting this to N causes the compiler to pass N arguments \ in registers EAX, EDX, and ECX instead of on the stack for\ \"C\", \"cdecl\", and \"stdcall\" fn.\ diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 90361efed84..81ae06602cd 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -277,14 +277,10 @@ impl ParseSess { ) -> Self { let fallback_bundle = fallback_fluent_bundle(locale_resources, false); let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let emitter = Box::new(HumanEmitter::new( - stderr_destination(ColorConfig::Auto), - Lrc::clone(&fallback_bundle), - )); - let fatal_dcx = DiagCtxt::new(emitter); + let fatal_emitter = + Box::new(HumanEmitter::new(stderr_destination(ColorConfig::Auto), fallback_bundle)); let dcx = DiagCtxt::new(Box::new(SilentEmitter { - fallback_bundle, - fatal_dcx, + fatal_emitter, fatal_note: Some(fatal_note), emit_fatal_diagnostic, })) @@ -341,8 +337,4 @@ impl ParseSess { pub fn dcx(&self) -> DiagCtxtHandle<'_> { self.dcx.handle() } - - pub fn set_dcx(&mut self, dcx: DiagCtxt) { - self.dcx = dcx; - } } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 1f03de3f53d..2b79081a26e 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -732,6 +732,11 @@ impl Session { self.opts.cg.split_debuginfo.unwrap_or(self.target.split_debuginfo) } + /// Returns the DWARF version passed on the CLI or the default for the target. + pub fn dwarf_version(&self) -> u32 { + self.opts.unstable_opts.dwarf_version.unwrap_or(self.target.default_dwarf_version) + } + pub fn stack_protector(&self) -> StackProtector { if self.target.options.supports_stack_protector { self.opts.unstable_opts.stack_protector @@ -1263,8 +1268,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } if sess.opts.unstable_opts.embed_source { - let dwarf_version = - sess.opts.unstable_opts.dwarf_version.unwrap_or(sess.target.default_dwarf_version); + let dwarf_version = sess.dwarf_version(); if dwarf_version < 5 { sess.dcx().emit_warn(errors::EmbedSourceInsufficientDwarfVersion { dwarf_version }); @@ -1358,12 +1362,6 @@ pub struct EarlyDiagCtxt { dcx: DiagCtxt, } -impl Default for EarlyDiagCtxt { - fn default() -> Self { - Self::new(ErrorOutputType::default()) - } -} - impl EarlyDiagCtxt { pub fn new(output: ErrorOutputType) -> Self { let emitter = mk_emitter(output); @@ -1371,10 +1369,9 @@ impl EarlyDiagCtxt { } /// Swap out the underlying dcx once we acquire the user's preference on error emission - /// format. Any errors prior to that will cause an abort and all stashed diagnostics of the - /// previous dcx will be emitted. - pub fn abort_if_error_and_set_error_format(&mut self, output: ErrorOutputType) { - self.dcx.handle().abort_if_errors(); + /// format. If `early_err` was previously called this will panic. + pub fn set_error_format(&mut self, output: ErrorOutputType) { + assert!(self.dcx.handle().has_errors().is_none()); let emitter = mk_emitter(output); self.dcx = DiagCtxt::new(emitter); @@ -1394,7 +1391,7 @@ impl EarlyDiagCtxt { #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] - #[must_use = "ErrorGuaranteed must be returned from `run_compiler` in order to exit with a non-zero status code"] + #[must_use = "raise_fatal must be called on the returned ErrorGuaranteed in order to exit with a non-zero status code"] pub fn early_err(&self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed { self.dcx.handle().err(msg) } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 31c7e6c3eb4..cdc56782a26 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -450,8 +450,9 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let tcx = tables.tcx; let ty = ty::Ty::new_static_str(tcx); let bytes = value.as_bytes(); - let val_tree = ty::ValTree::from_raw_bytes(tcx, bytes); - let val = tcx.valtree_to_const_val((ty, val_tree)); + let valtree = ty::ValTree::from_raw_bytes(tcx, bytes); + let cv = ty::Value { ty, valtree }; + let val = tcx.valtree_to_const_val(cv); mir::Const::from_value(val, ty).stable(&mut tables) } @@ -746,7 +747,9 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let tcx = tables.tcx; let alloc_id = tables.tcx.vtable_allocation(( ty.internal(&mut *tables, tcx), - trait_ref.internal(&mut *tables, tcx), + trait_ref + .internal(&mut *tables, tcx) + .map(|principal| tcx.instantiate_bound_regions_with_erased(principal)), )); Some(alloc_id.stable(&mut *tables)) } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index aee98d7d410..4a0420cc603 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -217,6 +217,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> { stable_mir::mir::Rvalue::ShallowInitBox(op.stable(tables), ty.stable(tables)) } CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.stable(tables)), + WrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"), } } } @@ -395,6 +396,7 @@ impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> { Downcast(_, idx) => stable_mir::mir::ProjectionElem::Downcast(idx.stable(tables)), OpaqueCast(ty) => stable_mir::mir::ProjectionElem::OpaqueCast(ty.stable(tables)), Subtype(ty) => stable_mir::mir::ProjectionElem::Subtype(ty.stable(tables)), + UnwrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"), } } } @@ -496,6 +498,9 @@ impl<'tcx> Stable<'tcx> for mir::AssertMessage<'tcx> { found: found.stable(tables), } } + AssertKind::NullPointerDereference => { + stable_mir::mir::AssertMessage::NullPointerDereference + } } } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index ff452eea23d..a2d95f0f693 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -418,23 +418,16 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { type T = stable_mir::ty::TyConst; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { - let kind = match self.kind() { - ty::ConstKind::Value(ty, val) => { - let val = match val { - ty::ValTree::Leaf(scalar) => ty::ValTree::Leaf(scalar), - ty::ValTree::Branch(branch) => { - ty::ValTree::Branch(tables.tcx.lift(branch).unwrap()) - } - }; - - let ty = tables.tcx.lift(ty).unwrap(); - let const_val = tables.tcx.valtree_to_const_val((ty, val)); + let ct = tables.tcx.lift(*self).unwrap(); + let kind = match ct.kind() { + ty::ConstKind::Value(cv) => { + let const_val = tables.tcx.valtree_to_const_val(cv); if matches!(const_val, mir::ConstValue::ZeroSized) { - stable_mir::ty::TyConstKind::ZSTValue(ty.stable(tables)) + stable_mir::ty::TyConstKind::ZSTValue(cv.ty.stable(tables)) } else { stable_mir::ty::TyConstKind::Value( - ty.stable(tables), - alloc::new_allocation(ty, const_val, tables), + cv.ty.stable(tables), + alloc::new_allocation(cv.ty, const_val, tables), ) } } @@ -449,7 +442,7 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { ty::ConstKind::Placeholder(_) => unimplemented!(), ty::ConstKind::Expr(_) => unimplemented!(), }; - let id = tables.intern_ty_const(tables.tcx.lift(*self).unwrap()); + let id = tables.intern_ty_const(ct); stable_mir::ty::TyConst::new(kind, id) } } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 51d809bd65d..b1f9f4a01c5 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -600,11 +600,43 @@ impl Span { !self.is_dummy() && sm.is_span_accessible(self) } + /// Returns whether `span` originates in a foreign crate's external macro. + /// + /// This is used to test whether a lint should not even begin to figure out whether it should + /// be reported on the current node. + pub fn in_external_macro(self, sm: &SourceMap) -> bool { + let expn_data = self.ctxt().outer_expn_data(); + match expn_data.kind { + ExpnKind::Root + | ExpnKind::Desugaring( + DesugaringKind::ForLoop + | DesugaringKind::WhileLoop + | DesugaringKind::OpaqueTy + | DesugaringKind::Async + | DesugaringKind::Await, + ) => false, + ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external" + ExpnKind::Macro(MacroKind::Bang, _) => { + // Dummy span for the `def_site` means it's an external macro. + expn_data.def_site.is_dummy() || sm.is_imported(expn_data.def_site) + } + ExpnKind::Macro { .. } => true, // definitely a plugin + } + } + /// Returns `true` if `span` originates in a derive-macro's expansion. pub fn in_derive_expansion(self) -> bool { matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _)) } + /// Return whether `span` is generated by `async` or `await`. + pub fn is_from_async_await(self) -> bool { + matches!( + self.ctxt().outer_expn_data().kind, + ExpnKind::Desugaring(DesugaringKind::Async | DesugaringKind::Await), + ) + } + /// Gate suggestions that would not be appropriate in a context the user didn't write. pub fn can_be_used_for_suggestions(self) -> bool { !self.from_expansion() diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6f1d3a74a81..b23cc909911 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -314,8 +314,6 @@ symbols! { Right, Rust, RustaceansAreAwesome, - RustcDecodable, - RustcEncodable, RwLock, RwLockReadGuard, RwLockWriteGuard, @@ -502,7 +500,6 @@ symbols! { augmented_assignments, auto_traits, autodiff, - autodiff_fallback, automatically_derived, avx, avx512_target_feature, @@ -568,7 +565,6 @@ symbols! { cfg_accessible, cfg_attr, cfg_attr_multi, - cfg_autodiff_fallback, cfg_boolean_literals, cfg_doctest, cfg_emscripten_wasm_eh, @@ -1476,6 +1472,7 @@ symbols! { panic_location, panic_misaligned_pointer_dereference, panic_nounwind, + panic_null_pointer_dereference, panic_runtime, panic_str_2015, panic_unwind, @@ -2153,7 +2150,6 @@ symbols! { unwrap, unwrap_binder, unwrap_or, - unwrap_unsafe_binder, use_extern_macros, use_nested_groups, used, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 879f3fac21f..8ae35572d01 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -274,14 +274,15 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> { fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> { // only print integers match ct.kind() { - ty::ConstKind::Value(ty, ty::ValTree::Leaf(scalar)) if ty.is_integral() => { + ty::ConstKind::Value(cv) if cv.ty.is_integral() => { // The `pretty_print_const` formatting depends on -Zverbose-internals // flag, so we cannot reuse it here. - let signed = matches!(ty.kind(), ty::Int(_)); + let scalar = cv.valtree.unwrap_leaf(); + let signed = matches!(cv.ty.kind(), ty::Int(_)); write!( self, "{:#?}", - ty::ConstInt::new(scalar, signed, ty.is_ptr_sized_integral()) + ty::ConstInt::new(scalar, signed, cv.ty.is_ptr_sized_integral()) )?; } _ => self.write_str("_")?, diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 5c5ab435dbd..4312c82815c 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -151,7 +151,7 @@ fn symbol_name_provider<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty pub fn typeid_for_trait_ref<'tcx>( tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyExistentialTraitRef<'tcx>, + trait_ref: ty::ExistentialTraitRef<'tcx>, ) -> String { v0::mangle_typeid_for_trait_ref(tcx, trait_ref) } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 4ddf530a00d..7b040a8b2c4 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -72,7 +72,7 @@ pub(super) fn mangle<'tcx>( pub(super) fn mangle_typeid_for_trait_ref<'tcx>( tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyExistentialTraitRef<'tcx>, + trait_ref: ty::ExistentialTraitRef<'tcx>, ) -> String { // FIXME(flip1995): See comment in `mangle_typeid_for_fnabi`. let mut cx = SymbolMangler { @@ -84,7 +84,7 @@ pub(super) fn mangle_typeid_for_trait_ref<'tcx>( binders: vec![], out: String::new(), }; - cx.print_def_path(trait_ref.def_id(), &[]).unwrap(); + cx.print_def_path(trait_ref.def_id, &[]).unwrap(); std::mem::take(&mut cx.out) } @@ -590,8 +590,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> { // We only mangle a typed value if the const can be evaluated. - let (ct_ty, valtree) = match ct.kind() { - ty::ConstKind::Value(ty, val) => (ty, val), + let cv = match ct.kind() { + ty::ConstKind::Value(cv) => cv, // Should only be encountered within the identity-substituted // impl header of an item nested within an impl item. @@ -619,13 +619,14 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { return Ok(()); } + let ty::Value { ty: ct_ty, valtree } = cv; let start = self.out.len(); match ct_ty.kind() { ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => { ct_ty.print(self)?; - let mut bits = ct + let mut bits = cv .try_to_bits(self.tcx, ty::TypingEnv::fully_monomorphized()) .expect("expected const to be monomorphic"); diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 1292f46f0c9..f17452b3ba0 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -934,6 +934,7 @@ pub enum InlineAsmClobberAbi { LoongArch, PowerPC, S390x, + Bpf, Msp430, } @@ -1003,6 +1004,10 @@ impl InlineAsmClobberAbi { "C" | "system" => Ok(InlineAsmClobberAbi::S390x), _ => Err(&["C", "system"]), }, + InlineAsmArch::Bpf => match name { + "C" | "system" => Ok(InlineAsmClobberAbi::Bpf), + _ => Err(&["C", "system"]), + }, InlineAsmArch::Msp430 => match name { "C" | "system" => Ok(InlineAsmClobberAbi::Msp430), _ => Err(&["C", "system"]), @@ -1278,6 +1283,14 @@ impl InlineAsmClobberAbi { a8, a9, a10, a11, a12, a13, a14, a15, } }, + InlineAsmClobberAbi::Bpf => clobbered_regs! { + Bpf BpfInlineAsmReg { + // Refs: Section 1.1 "Registers and calling convention" in BPF ABI Recommended Conventions and Guidelines v1.0 + // https://www.kernel.org/doc/html/latest/bpf/standardization/abi.html#registers-and-calling-convention + + r0, r1, r2, r3, r4, r5, + } + }, InlineAsmClobberAbi::Msp430 => clobbered_regs! { Msp430 Msp430InlineAsmReg { r11, r12, r13, r14, r15, diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index 9cdc0801b1f..a6b0ec072e8 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -128,6 +128,19 @@ impl Target { Some(Ok(())) })).unwrap_or(Ok(())) } ); + ($key_name:ident, RustcAbi) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { + match s.parse::<super::RustcAbi>() { + Ok(rustc_abi) => base.$key_name = Some(rustc_abi), + _ => return Some(Err(format!( + "'{s}' is not a valid value for rustc-abi. \ + Use 'x86-softfloat' or leave the field unset." + ))), + } + Some(Ok(())) + })).unwrap_or(Ok(())) + } ); ($key_name:ident, RelocModel) => ( { let name = (stringify!($key_name)).replace("_", "-"); obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { @@ -546,6 +559,7 @@ impl Target { key!(link_env_remove, list); key!(asm_args, list); key!(cpu); + key!(need_explicit_cpu, bool); key!(features); key!(dynamic_linking, bool); key!(direct_access_external_data, Option<bool>); @@ -611,6 +625,7 @@ impl Target { key!(llvm_mcount_intrinsic, optional); key!(llvm_abiname); key!(llvm_floatabi, FloatAbi)?; + key!(rustc_abi, RustcAbi)?; key!(relax_elf_relocations, bool); key!(llvm_args, list); key!(use_ctors_section, bool); @@ -720,6 +735,7 @@ impl ToJson for Target { target_option_val!(link_env_remove); target_option_val!(asm_args); target_option_val!(cpu); + target_option_val!(need_explicit_cpu); target_option_val!(features); target_option_val!(dynamic_linking); target_option_val!(direct_access_external_data); @@ -786,6 +802,7 @@ impl ToJson for Target { target_option_val!(llvm_mcount_intrinsic); target_option_val!(llvm_abiname); target_option_val!(llvm_floatabi); + target_option_val!(rustc_abi); target_option_val!(relax_elf_relocations); target_option_val!(llvm_args); target_option_val!(use_ctors_section); diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index bcd2aff54bb..72600225e7a 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1114,6 +1114,33 @@ impl ToJson for FloatAbi { } } +/// The Rustc-specific variant of the ABI used for this target. +#[derive(Clone, Copy, PartialEq, Hash, Debug)] +pub enum RustcAbi { + /// On x86-32/64 only: do not use any FPU or SIMD registers for the ABI. + X86Softfloat, +} + +impl FromStr for RustcAbi { + type Err = (); + + fn from_str(s: &str) -> Result<RustcAbi, ()> { + Ok(match s { + "x86-softfloat" => RustcAbi::X86Softfloat, + _ => return Err(()), + }) + } +} + +impl ToJson for RustcAbi { + fn to_json(&self) -> Json { + match *self { + RustcAbi::X86Softfloat => "x86-softfloat", + } + .to_json() + } +} + #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum TlsModel { GeneralDynamic, @@ -2254,6 +2281,9 @@ pub struct TargetOptions { /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults /// to "generic". pub cpu: StaticCow<str>, + /// Whether a cpu needs to be explicitly set. + /// Set to true if there is no default cpu. Defaults to false. + pub need_explicit_cpu: bool, /// Default target features to pass to LLVM. These features overwrite /// `-Ctarget-cpu` but can be overwritten with `-Ctarget-features`. /// Corresponds to `llc -mattr=$features`. @@ -2502,6 +2532,12 @@ pub struct TargetOptions { /// If not provided, LLVM will infer the float ABI from the target triple (`llvm_target`). pub llvm_floatabi: Option<FloatAbi>, + /// Picks a specific ABI for this target. This is *not* just for "Rust" ABI functions, + /// it can also affect "C" ABI functions; the point is that this flag is interpreted by + /// rustc and not forwarded to LLVM. + /// So far, this is only used on x86. + pub rustc_abi: Option<RustcAbi>, + /// Whether or not RelaxElfRelocation flag will be passed to the linker pub relax_elf_relocations: bool, @@ -2661,10 +2697,6 @@ impl TargetOptions { .collect(); } } - - pub(crate) fn has_feature(&self, search_feature: &str) -> bool { - self.features.split(',').any(|f| f.strip_prefix('+').is_some_and(|f| f == search_feature)) - } } impl Default for TargetOptions { @@ -2686,6 +2718,7 @@ impl Default for TargetOptions { link_script: None, asm_args: cvs![], cpu: "generic".into(), + need_explicit_cpu: false, features: "".into(), direct_access_external_data: None, dynamic_linking: false, @@ -2770,6 +2803,7 @@ impl Default for TargetOptions { llvm_mcount_intrinsic: None, llvm_abiname: "".into(), llvm_floatabi: None, + rustc_abi: None, relax_elf_relocations: false, llvm_args: cvs![], use_ctors_section: false, @@ -3236,6 +3270,17 @@ impl Target { _ => {} } + // Check consistency of Rust ABI declaration. + if let Some(rust_abi) = self.rustc_abi { + match rust_abi { + RustcAbi::X86Softfloat => check_matches!( + &*self.arch, + "x86" | "x86_64", + "`x86-softfloat` ABI is only valid for x86 targets" + ), + } + } + // Check that the given target-features string makes some basic sense. if !self.features.is_empty() { let mut features_enabled = FxHashSet::default(); diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs index 39d3a5a4633..c1ed565f0fe 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_uefi.rs @@ -5,7 +5,7 @@ // The cdecl ABI is used. It differs from the stdcall or fastcall ABI. // "i686-unknown-windows" is used to get the minimal subset of windows-specific features. -use crate::spec::{Target, base}; +use crate::spec::{RustcAbi, Target, base}; pub(crate) fn target() -> Target { let mut base = base::uefi_msvc::opts(); @@ -22,6 +22,7 @@ pub(crate) fn target() -> Target { // If you initialize FP units yourself, you can override these flags with custom linker // arguments, thus giving you access to full MMX/SSE acceleration. base.features = "-mmx,-sse,+soft-float".into(); + base.rustc_abi = Some(RustcAbi::X86Softfloat); // Use -GNU here, because of the reason below: // Background and Problem: diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs index cfefb1de993..e14a3673589 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs @@ -5,8 +5,8 @@ // features. use crate::spec::{ - Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelroLevel, SanitizerSet, StackProbeType, - Target, TargetOptions, + Cc, CodeModel, LinkerFlavor, Lld, PanicStrategy, RelroLevel, RustcAbi, SanitizerSet, + StackProbeType, Target, TargetOptions, }; pub(crate) fn target() -> Target { @@ -20,6 +20,7 @@ pub(crate) fn target() -> Target { relro_level: RelroLevel::Full, linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), + rustc_abi: Some(RustcAbi::X86Softfloat), features: "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,+soft-float".into(), supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, disable_redzone: true, diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs index a11a79ff41a..8fd92e8123b 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_uefi.rs @@ -6,7 +6,7 @@ // LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features. use crate::abi::call::Conv; -use crate::spec::{Target, base}; +use crate::spec::{RustcAbi, Target, base}; pub(crate) fn target() -> Target { let mut base = base::uefi_msvc::opts(); @@ -26,6 +26,7 @@ pub(crate) fn target() -> Target { // If you initialize FP units yourself, you can override these flags with custom linker // arguments, thus giving you access to full MMX/SSE acceleration. base.features = "-mmx,-sse,+soft-float".into(); + base.rustc_abi = Some(RustcAbi::X86Softfloat); Target { llvm_target: "x86_64-unknown-windows".into(), diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 0d8a4988dce..5355a4ad532 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -5,7 +5,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_span::{Symbol, sym}; -use crate::spec::{FloatAbi, Target}; +use crate::spec::{FloatAbi, RustcAbi, Target}; /// Features that control behaviour of rustc, rather than the codegen. /// These exist globally and are not in the target-specific lists below. @@ -422,7 +422,9 @@ const X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("sha512", Unstable(sym::sha512_sm_x86), &["avx2"]), ("sm3", Unstable(sym::sha512_sm_x86), &["avx"]), ("sm4", Unstable(sym::sha512_sm_x86), &["avx2"]), - ("soft-float", Stability::Forbidden { reason: "unsound because it changes float ABI" }, &[]), + // This cannot actually be toggled, the ABI always fixes it, so it'd make little sense to + // stabilize. It must be in this list for the ABI check to be able to use it. + ("soft-float", Stability::Unstable(sym::x87_target_feature), &[]), ("sse", Stable, &[]), ("sse2", Stable, &["sse"]), ("sse3", Stable, &["sse2"]), @@ -773,23 +775,41 @@ impl Target { // questions "which ABI is used". match &*self.arch { "x86" => { - // We support 2 ABIs, hardfloat (default) and softfloat. - // x86 has no sane ABI indicator so we have to use the target feature. - if self.has_feature("soft-float") { - NOTHING - } else { - // Hardfloat ABI. x87 must be enabled. - FeatureConstraints { required: &["x87"], incompatible: &[] } + // We use our own ABI indicator here; LLVM does not have anything native. + // Every case should require or forbid `soft-float`! + match self.rustc_abi { + None => { + // Default hardfloat ABI. + // x87 must be enabled, soft-float must be disabled. + FeatureConstraints { required: &["x87"], incompatible: &["soft-float"] } + } + Some(RustcAbi::X86Softfloat) => { + // Softfloat ABI, requires corresponding target feature. That feature trumps + // `x87` and all other FPU features so those do not matter. + // Note that this one requirement is the entire implementation of the ABI! + // LLVM handles the rest. + FeatureConstraints { required: &["soft-float"], incompatible: &[] } + } } } "x86_64" => { - // We support 2 ABIs, hardfloat (default) and softfloat. - // x86 has no sane ABI indicator so we have to use the target feature. - if self.has_feature("soft-float") { - NOTHING - } else { - // Hardfloat ABI. x87 and SSE2 must be enabled. - FeatureConstraints { required: &["x87", "sse2"], incompatible: &[] } + // We use our own ABI indicator here; LLVM does not have anything native. + // Every case should require or forbid `soft-float`! + match self.rustc_abi { + None => { + // Default hardfloat ABI. On x86-64, this always includes SSE2. + FeatureConstraints { + required: &["x87", "sse2"], + incompatible: &["soft-float"], + } + } + Some(RustcAbi::X86Softfloat) => { + // Softfloat ABI, requires corresponding target feature. That feature trumps + // `x87` and all other FPU features so those do not matter. + // Note that this one requirement is the entire implementation of the ABI! + // LLVM handles the rest. + FeatureConstraints { required: &["soft-float"], incompatible: &[] } + } } } "arm" => { diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 7c72318b4d7..055a3edcc32 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -148,8 +148,6 @@ trait_selection_dtcs_has_req_note = the used `impl` has a `'static` requirement trait_selection_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement trait_selection_dtcs_suggestion = consider relaxing the implicit `'static` requirement -trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries} - trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]` .label = empty on-clause here diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 9eacd377361..091773009e9 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -435,7 +435,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>, terr: TypeError<'tcx>, param_env: Option<ParamEnv<'tcx>>, - path: &mut Option<PathBuf>, ) { match *cause.code() { ObligationCauseCode::Pattern { @@ -458,7 +457,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { format!("this is an iterator with items of type `{}`", args.type_at(0)), ); } else { - let expected_ty = self.tcx.short_ty_string(expected_ty, path); + let expected_ty = self.tcx.short_string(expected_ty, err.long_ty_path()); err.span_label(span, format!("this expression has type `{expected_ty}`")); } } @@ -1392,9 +1391,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { mut values: Option<ty::ParamEnvAnd<'tcx, ValuePairs<'tcx>>>, terr: TypeError<'tcx>, prefer_label: bool, + override_span: Option<Span>, ) { - let span = cause.span; - + // We use `override_span` when we want the error to point at a `Span` other than + // `cause.span`. This is used in E0271, when a closure is passed in where the return type + // isn't what was expected. We want to point at the closure's return type (or expression), + // instead of the expression where the closure is passed as call argument. + let span = override_span.unwrap_or(cause.span); // For some types of errors, expected-found does not make // sense, so just ignore the values we were given. if let TypeError::CyclicTy(_) = terr { @@ -1541,7 +1544,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { (false, Mismatch::Fixed("existential projection")) } }; - let Some(vals) = self.values_str(values, cause) else { + let Some(vals) = self.values_str(values, cause, diag.long_ty_path()) else { // Derived error. Cancel the emitter. // NOTE(eddyb) this was `.cancel()`, but `diag` // is borrowed, so we can't fully defuse it. @@ -1596,9 +1599,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return; } - let mut path = None; - if let Some((expected, found, p)) = expected_found { - path = p; + if let Some((expected, found)) = expected_found { let (expected_label, found_label, exp_found) = match exp_found { Mismatch::Variable(ef) => ( ef.expected.prefix_string(self.tcx), @@ -1721,32 +1722,42 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } TypeError::Sorts(values) => { - let extra = expected == found; + let extra = expected == found + // Ensure that we don't ever say something like + // expected `impl Trait` (opaque type `impl Trait`) + // found `impl Trait` (opaque type `impl Trait`) + && values.expected.sort_string(self.tcx) + != values.found.sort_string(self.tcx); let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) { (true, ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })) => { let sm = self.tcx.sess.source_map(); let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo()); - format!( + DiagStyledString::normal(format!( " (opaque type at <{}:{}:{}>)", sm.filename_for_diagnostics(&pos.file.name), pos.line, pos.col.to_usize() + 1, - ) + )) } (true, ty::Alias(ty::Projection, proj)) if self.tcx.is_impl_trait_in_trait(proj.def_id) => { let sm = self.tcx.sess.source_map(); let pos = sm.lookup_char_pos(self.tcx.def_span(proj.def_id).lo()); - format!( + DiagStyledString::normal(format!( " (trait associated opaque type at <{}:{}:{}>)", sm.filename_for_diagnostics(&pos.file.name), pos.line, pos.col.to_usize() + 1, - ) + )) } - (true, _) => format!(" ({})", ty.sort_string(self.tcx)), - (false, _) => "".to_string(), + (true, _) => { + let mut s = DiagStyledString::normal(" ("); + s.push_highlighted(ty.sort_string(self.tcx)); + s.push_normal(")"); + s + } + (false, _) => DiagStyledString::normal(""), }; if !(values.expected.is_simple_text() && values.found.is_simple_text()) || (exp_found.is_some_and(|ef| { @@ -1763,23 +1774,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } })) { - if let Some(ExpectedFound { found: found_ty, .. }) = exp_found { + if let Some(ExpectedFound { found: found_ty, .. }) = exp_found + && !self.tcx.ty_is_opaque_future(found_ty) + { // `Future` is a special opaque type that the compiler // will try to hide in some case such as `async fn`, so // to make an error more use friendly we will // avoid to suggest a mismatch type with a // type that the user usually are not using // directly such as `impl Future<Output = u8>`. - if !self.tcx.ty_is_opaque_future(found_ty) { - diag.note_expected_found_extra( - &expected_label, - expected, - &found_label, - found, - &sort_string(values.expected), - &sort_string(values.found), - ); - } + diag.note_expected_found_extra( + &expected_label, + expected, + &found_label, + found, + sort_string(values.expected), + sort_string(values.found), + ); } } } @@ -1874,11 +1885,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // It reads better to have the error origin as the final // thing. - self.note_error_origin(diag, cause, exp_found, terr, param_env, &mut path); - if let Some(path) = path { - diag.note(format!("the full type name has been written to '{}'", path.display())); - diag.note("consider using `--verbose` to print the full type name to the console"); - } + self.note_error_origin(diag, cause, exp_found, terr, param_env); debug!(?diag); } @@ -1887,6 +1894,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &self, trace: &TypeTrace<'tcx>, terr: TypeError<'tcx>, + path: &mut Option<PathBuf>, ) -> Vec<TypeErrorAdditionalDiags> { let mut suggestions = Vec::new(); let span = trace.cause.span; @@ -1965,7 +1973,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) | ObligationCauseCode::BlockTailExpression(.., source)) = code && let hir::MatchSource::TryDesugar(_) = source - && let Some((expected_ty, found_ty, _)) = self.values_str(trace.values, &trace.cause) + && let Some((expected_ty, found_ty)) = self.values_str(trace.values, &trace.cause, path) { suggestions.push(TypeErrorAdditionalDiags::TryCannotConvert { found: found_ty.content(), @@ -2023,14 +2031,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => None, }; if let Some(tykind) = tykind - && let hir::TyKind::Array(_, length) = tykind - && let Some((scalar, ty)) = sz.found.try_to_scalar() - && ty == self.tcx.types.usize + && let hir::TyKind::Array(_, length_arg) = tykind + && let Some(length_val) = sz.found.try_to_target_usize(self.tcx) { - let span = length.span(); Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { - span, - length: scalar.to_target_usize(&self.tcx).unwrap(), + span: length_arg.span(), + length: length_val, }) } else { None @@ -2046,12 +2052,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr); let span = trace.cause.span; + let mut path = None; let failure_code = trace.cause.as_failure_code_diag( terr, span, - self.type_error_additional_suggestions(&trace, terr), + self.type_error_additional_suggestions(&trace, terr, &mut path), ); let mut diag = self.dcx().create_err(failure_code); + *diag.long_ty_path() = path; self.note_type_err( &mut diag, &trace.cause, @@ -2059,6 +2067,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Some(param_env.and(trace.values)), terr, false, + None, ); diag } @@ -2095,10 +2104,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &self, values: ValuePairs<'tcx>, cause: &ObligationCause<'tcx>, - ) -> Option<(DiagStyledString, DiagStyledString, Option<PathBuf>)> { + file: &mut Option<PathBuf>, + ) -> Option<(DiagStyledString, DiagStyledString)> { match values { ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found), - ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found), + ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found, file), ValuePairs::Aliases(exp_found) => self.expected_found_str(exp_found), ValuePairs::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found), ValuePairs::ExistentialProjection(exp_found) => self.expected_found_str(exp_found), @@ -2108,7 +2118,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { found: exp_found.found.print_trait_sugared(), }; match self.expected_found_str(pretty_exp_found) { - Some((expected, found, _)) if expected == found => { + Some((expected, found)) if expected == found => { self.expected_found_str(exp_found) } ret => ret, @@ -2130,9 +2140,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { (None, None) }; - let (exp, fnd) = - self.cmp_fn_sig(&exp_found.expected, fn_def1, &exp_found.found, fn_def2); - Some((exp, fnd, None)) + Some(self.cmp_fn_sig(&exp_found.expected, fn_def1, &exp_found.found, fn_def2)) } } } @@ -2140,7 +2148,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn expected_found_str_term( &self, exp_found: ty::error::ExpectedFound<ty::Term<'tcx>>, - ) -> Option<(DiagStyledString, DiagStyledString, Option<PathBuf>)> { + path: &mut Option<PathBuf>, + ) -> Option<(DiagStyledString, DiagStyledString)> { let exp_found = self.resolve_vars_if_possible(exp_found); if exp_found.references_error() { return None; @@ -2155,21 +2164,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let len = self.tcx.sess().diagnostic_width() + 40; let exp_s = exp.content(); let fnd_s = fnd.content(); - let mut path = None; if exp_s.len() > len { - let exp_s = self.tcx.short_ty_string(expected, &mut path); + let exp_s = self.tcx.short_string(expected, path); exp = DiagStyledString::highlighted(exp_s); } if fnd_s.len() > len { - let fnd_s = self.tcx.short_ty_string(found, &mut path); + let fnd_s = self.tcx.short_string(found, path); fnd = DiagStyledString::highlighted(fnd_s); } - (exp, fnd, path) + (exp, fnd) } _ => ( DiagStyledString::highlighted(exp_found.expected.to_string()), DiagStyledString::highlighted(exp_found.found.to_string()), - None, ), }) } @@ -2178,7 +2185,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn expected_found_str<T: fmt::Display + TypeFoldable<TyCtxt<'tcx>>>( &self, exp_found: ty::error::ExpectedFound<T>, - ) -> Option<(DiagStyledString, DiagStyledString, Option<PathBuf>)> { + ) -> Option<(DiagStyledString, DiagStyledString)> { let exp_found = self.resolve_vars_if_possible(exp_found); if exp_found.references_error() { return None; @@ -2187,7 +2194,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Some(( DiagStyledString::highlighted(exp_found.expected.to_string()), DiagStyledString::highlighted(exp_found.found.to_string()), - None, )) } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index 68a53381230..99b70c87ccd 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -713,7 +713,7 @@ impl<'tcx> InferSourceKind<'tcx> { if ty.is_closure() { ("closure", closure_as_fn_str(infcx, ty), path) } else if !ty.is_ty_or_numeric_infer() { - ("normal", infcx.tcx.short_ty_string(ty, &mut path), path) + ("normal", infcx.tcx.short_string(ty, &mut path), path) } else { ("other", String::new(), path) } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs deleted file mode 100644 index beae9962f7f..00000000000 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs +++ /dev/null @@ -1,422 +0,0 @@ -use rustc_errors::{Diag, Subdiagnostic}; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::traits::ObligationCauseCode; -use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::{self, IsSuggestable, Region, Ty}; -use rustc_span::kw; -use tracing::debug; - -use super::ObligationCauseAsDiagArg; -use crate::error_reporting::infer::{TypeErrCtxt, note_and_explain_region}; -use crate::errors::{ - FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent, RefLongerThanData, - RegionOriginNote, WhereClauseSuggestions, note_and_explain, -}; -use crate::fluent_generated as fluent; -use crate::infer::{self, SubregionOrigin}; - -impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { - pub(super) fn note_region_origin(&self, err: &mut Diag<'_>, origin: &SubregionOrigin<'tcx>) { - match *origin { - infer::Subtype(ref trace) => RegionOriginNote::WithRequirement { - span: trace.cause.span, - requirement: ObligationCauseAsDiagArg(trace.cause.clone()), - expected_found: self.values_str(trace.values).map(|(e, f, _)| (e, f)), - } - .add_to_diag(err), - infer::Reborrow(span) => { - RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diag(err) - } - infer::RelateObjectBound(span) => { - RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound } - .add_to_diag(err); - } - infer::ReferenceOutlivesReferent(ty, span) => { - RegionOriginNote::WithName { - span, - msg: fluent::infer_reference_outlives_referent, - name: &self.ty_to_string(ty), - continues: false, - } - .add_to_diag(err); - } - infer::RelateParamBound(span, ty, opt_span) => { - RegionOriginNote::WithName { - span, - msg: fluent::infer_relate_param_bound, - name: &self.ty_to_string(ty), - continues: opt_span.is_some(), - } - .add_to_diag(err); - if let Some(span) = opt_span { - RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 } - .add_to_diag(err); - } - } - infer::RelateRegionParamBound(span, _) => { - RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound } - .add_to_diag(err); - } - infer::CompareImplItemObligation { span, .. } => { - RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation } - .add_to_diag(err); - } - infer::CheckAssociatedTypeBounds { ref parent, .. } => { - self.note_region_origin(err, parent); - } - infer::AscribeUserTypeProvePredicate(span) => { - RegionOriginNote::Plain { - span, - msg: fluent::infer_ascribe_user_type_prove_predicate, - } - .add_to_diag(err); - } - } - } - - pub(super) fn report_concrete_failure( - &self, - generic_param_scope: LocalDefId, - origin: SubregionOrigin<'tcx>, - sub: Region<'tcx>, - sup: Region<'tcx>, - ) -> Diag<'a> { - let mut err = match origin { - infer::Subtype(box trace) => { - let terr = TypeError::RegionsDoesNotOutlive(sup, sub); - let mut err = self.report_and_explain_type_error(trace, terr); - match (*sub, *sup) { - (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {} - (ty::RePlaceholder(_), _) => { - note_and_explain_region( - self.tcx, - &mut err, - generic_param_scope, - "", - sup, - " doesn't meet the lifetime requirements", - None, - ); - } - (_, ty::RePlaceholder(_)) => { - note_and_explain_region( - self.tcx, - &mut err, - generic_param_scope, - "the required lifetime does not necessarily outlive ", - sub, - "", - None, - ); - } - _ => { - note_and_explain_region( - self.tcx, - &mut err, - generic_param_scope, - "", - sup, - "...", - None, - ); - note_and_explain_region( - self.tcx, - &mut err, - generic_param_scope, - "...does not necessarily outlive ", - sub, - "", - None, - ); - } - } - err - } - infer::Reborrow(span) => { - let reference_valid = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sub, - None, - note_and_explain::PrefixKind::RefValidFor, - note_and_explain::SuffixKind::Continues, - ); - let content_valid = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sup, - None, - note_and_explain::PrefixKind::ContentValidFor, - note_and_explain::SuffixKind::Empty, - ); - self.dcx().create_err(OutlivesContent { - span, - notes: reference_valid.into_iter().chain(content_valid).collect(), - }) - } - infer::RelateObjectBound(span) => { - let object_valid = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sub, - None, - note_and_explain::PrefixKind::TypeObjValidFor, - note_and_explain::SuffixKind::Empty, - ); - let pointer_valid = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sup, - None, - note_and_explain::PrefixKind::SourcePointerValidFor, - note_and_explain::SuffixKind::Empty, - ); - self.dcx().create_err(OutlivesBound { - span, - notes: object_valid.into_iter().chain(pointer_valid).collect(), - }) - } - infer::RelateParamBound(span, ty, opt_span) => { - let prefix = match *sub { - ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy, - _ => note_and_explain::PrefixKind::TypeOutlive, - }; - let suffix = if opt_span.is_some() { - note_and_explain::SuffixKind::ReqByBinding - } else { - note_and_explain::SuffixKind::Empty - }; - let note = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sub, - opt_span, - prefix, - suffix, - ); - self.dcx().create_err(FulfillReqLifetime { - span, - ty: self.resolve_vars_if_possible(ty), - note, - }) - } - infer::RelateRegionParamBound(span, _) => { - let param_instantiated = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sup, - None, - note_and_explain::PrefixKind::LfParamInstantiatedWith, - note_and_explain::SuffixKind::Empty, - ); - let param_must_outlive = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sub, - None, - note_and_explain::PrefixKind::LfParamMustOutlive, - note_and_explain::SuffixKind::Empty, - ); - self.dcx().create_err(LfBoundNotSatisfied { - span, - notes: param_instantiated.into_iter().chain(param_must_outlive).collect(), - }) - } - infer::ReferenceOutlivesReferent(ty, span) => { - let pointer_valid = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sub, - None, - note_and_explain::PrefixKind::PointerValidFor, - note_and_explain::SuffixKind::Empty, - ); - let data_valid = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sup, - None, - note_and_explain::PrefixKind::DataValidFor, - note_and_explain::SuffixKind::Empty, - ); - self.dcx().create_err(RefLongerThanData { - span, - ty: self.resolve_vars_if_possible(ty), - notes: pointer_valid.into_iter().chain(data_valid).collect(), - }) - } - infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => { - let mut err = self.infcx.report_extra_impl_obligation( - span, - impl_item_def_id, - trait_item_def_id, - &format!("`{sup}: {sub}`"), - ); - // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause - if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) - && generics.where_clause_span.contains(span) - { - self.suggest_copy_trait_method_bounds( - trait_item_def_id, - impl_item_def_id, - &mut err, - ); - } - err - } - infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => { - let mut err = self.report_concrete_failure(generic_param_scope, *parent, sub, sup); - - // Don't mention the item name if it's an RPITIT, since that'll just confuse - // folks. - if !self.tcx.is_impl_trait_in_trait(impl_item_def_id.to_def_id()) { - let trait_item_span = self.tcx.def_span(trait_item_def_id); - let item_name = self.tcx.item_name(impl_item_def_id.to_def_id()); - err.span_label( - trait_item_span, - format!("definition of `{item_name}` from trait"), - ); - } - - self.suggest_copy_trait_method_bounds( - trait_item_def_id, - impl_item_def_id, - &mut err, - ); - err - } - infer::AscribeUserTypeProvePredicate(span) => { - let instantiated = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sup, - None, - note_and_explain::PrefixKind::LfInstantiatedWith, - note_and_explain::SuffixKind::Empty, - ); - let must_outlive = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sub, - None, - note_and_explain::PrefixKind::LfMustOutlive, - note_and_explain::SuffixKind::Empty, - ); - self.dcx().create_err(LfBoundNotSatisfied { - span, - notes: instantiated.into_iter().chain(must_outlive).collect(), - }) - } - }; - if sub.is_error() || sup.is_error() { - err.downgrade_to_delayed_bug(); - } - err - } - - pub fn suggest_copy_trait_method_bounds( - &self, - trait_item_def_id: DefId, - impl_item_def_id: LocalDefId, - err: &mut Diag<'_>, - ) { - // FIXME(compiler-errors): Right now this is only being used for region - // predicate mismatches. Ideally, we'd use it for *all* predicate mismatches, - // but right now it's not really very smart when it comes to implicit `Sized` - // predicates and bounds on the trait itself. - - let Some(impl_def_id) = self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx) - else { - return; - }; - let Some(trait_ref) = self.tcx.impl_trait_ref(impl_def_id) else { - return; - }; - let trait_args = trait_ref - .instantiate_identity() - // Replace the explicit self type with `Self` for better suggestion rendering - .with_self_ty(self.tcx, Ty::new_param(self.tcx, 0, kw::SelfUpper)) - .args; - let trait_item_args = ty::GenericArgs::identity_for_item(self.tcx, impl_item_def_id) - .rebase_onto(self.tcx, impl_def_id, trait_args); - - let Ok(trait_predicates) = - self.tcx - .explicit_predicates_of(trait_item_def_id) - .instantiate_own(self.tcx, trait_item_args) - .map(|(pred, _)| { - if pred.is_suggestable(self.tcx, false) { - Ok(pred.to_string()) - } else { - Err(()) - } - }) - .collect::<Result<Vec<_>, ()>>() - else { - return; - }; - - let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else { - return; - }; - - let suggestion = if trait_predicates.is_empty() { - WhereClauseSuggestions::Remove { span: generics.where_clause_span } - } else { - let space = if generics.where_clause_span.is_empty() { " " } else { "" }; - WhereClauseSuggestions::CopyPredicates { - span: generics.where_clause_span, - space, - trait_predicates: trait_predicates.join(", "), - } - }; - err.subdiagnostic(suggestion); - } - - pub(super) fn report_placeholder_failure( - &self, - generic_param_scope: LocalDefId, - placeholder_origin: SubregionOrigin<'tcx>, - sub: Region<'tcx>, - sup: Region<'tcx>, - ) -> Diag<'a> { - // I can't think how to do better than this right now. -nikomatsakis - debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure"); - match placeholder_origin { - infer::Subtype(box ref trace) - if matches!( - &trace.cause.code().peel_derives(), - ObligationCauseCode::WhereClause(..) - | ObligationCauseCode::WhereClauseInExpr(..) - ) => - { - // Hack to get around the borrow checker because trace.cause has an `Rc`. - if let ObligationCauseCode::WhereClause(_, span) - | ObligationCauseCode::WhereClauseInExpr(_, span, ..) = - &trace.cause.code().peel_derives() - && !span.is_dummy() - { - let span = *span; - self.report_concrete_failure(generic_param_scope, placeholder_origin, sub, sup) - .with_span_note(span, "the lifetime requirement is introduced here") - } else { - unreachable!( - "control flow ensures we have a `BindingObligation` or `WhereClauseInExpr` here..." - ) - } - } - infer::Subtype(box trace) => { - let terr = TypeError::RegionsPlaceholderMismatch; - return self.report_and_explain_type_error(trace, terr); - } - _ => { - return self.report_concrete_failure( - generic_param_scope, - placeholder_origin, - sub, - sup, - ); - } - } - } -} diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 3acca47025c..f35a5349ecb 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -221,7 +221,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer::Subtype(ref trace) => RegionOriginNote::WithRequirement { span: trace.cause.span, requirement: ObligationCauseAsDiagArg(trace.cause.clone()), - expected_found: self.values_str(trace.values, &trace.cause).map(|(e, f, _)| (e, f)), + expected_found: self.values_str(trace.values, &trace.cause, err.long_ty_path()), } .add_to_diag(err), infer::Reborrow(span) => { @@ -946,10 +946,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let infer::Subtype(ref sup_trace) = sup_origin && let infer::Subtype(ref sub_trace) = sub_origin - && let Some((sup_expected, sup_found, _)) = - self.values_str(sup_trace.values, &sup_trace.cause) - && let Some((sub_expected, sub_found, _)) = - self.values_str(sub_trace.values, &sup_trace.cause) + && let Some((sup_expected, sup_found)) = + self.values_str(sup_trace.values, &sup_trace.cause, err.long_ty_path()) + && let Some((sub_expected, sub_found)) = + self.values_str(sub_trace.values, &sup_trace.cause, err.long_ty_path()) && sub_expected == sup_expected && sub_found == sup_found { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index 231fecf7a4a..562000e28ac 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -418,7 +418,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; let sugg = match (expected.is_ref(), found.is_ref()) { - (true, false) => FunctionPointerSuggestion::UseRef { span, fn_name }, + (true, false) => { + FunctionPointerSuggestion::UseRef { span: span.shrink_to_lo() } + } (false, true) => FunctionPointerSuggestion::RemoveRef { span, fn_name }, (true, true) => { diag.subdiagnostic(FnItemsAreDistinct); @@ -426,7 +428,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } (false, false) => { diag.subdiagnostic(FnItemsAreDistinct); - FunctionPointerSuggestion::Cast { span, fn_name, sig } + FunctionPointerSuggestion::Cast { span: span.shrink_to_hi(), sig } } }; diag.subdiagnostic(sugg); @@ -466,8 +468,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } else { FunctionPointerSuggestion::CastBoth { - span, - fn_name, + span: span.shrink_to_hi(), found_sig: *found_sig, expected_sig: *expected_sig, } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index b4d294a70c0..6beb108bc3a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -163,6 +163,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let predicate = self.resolve_vars_if_possible(obligation.predicate); let span = obligation.cause.span; + let mut file = None; debug!(?predicate, obligation.cause.code = ?obligation.cause.code()); @@ -179,7 +180,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return e; } - if let Err(guar) = self.tcx.ensure().coherent_trait(trait_pred.def_id()) { + if let Err(guar) = self.tcx.ensure_ok().coherent_trait(trait_pred.def_id()) { // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case // other `Foo` impls are incoherent. return guar; @@ -245,7 +246,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span, E0283, "type annotations needed: cannot satisfy `{}`", - predicate, + self.tcx.short_string(predicate, &mut file), ) }; @@ -292,7 +293,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.cancel(); return e; } - err.note(format!("cannot satisfy `{predicate}`")); + let pred = self.tcx.short_string(predicate, &mut file); + err.note(format!("cannot satisfy `{pred}`")); let impl_candidates = self.find_similar_impl_candidates(predicate.as_trait_clause().unwrap()); if impl_candidates.len() < 40 { @@ -511,8 +513,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return e; } - if let Err(guar) = - self.tcx.ensure().coherent_trait(self.tcx.parent(data.projection_term.def_id)) + if let Err(guar) = self + .tcx + .ensure_ok() + .coherent_trait(self.tcx.parent(data.projection_term.def_id)) { // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case // other `Foo` impls are incoherent. @@ -524,6 +528,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .iter() .chain(Some(data.term.into_arg())) .find(|g| g.has_non_region_infer()); + let predicate = self.tcx.short_string(predicate, &mut file); if let Some(arg) = arg { self.emit_inference_failure_err( obligation.cause.body_id, @@ -539,8 +544,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.dcx(), span, E0284, - "type annotations needed: cannot satisfy `{}`", - predicate, + "type annotations needed: cannot satisfy `{predicate}`", ) .with_span_label(span, format!("cannot satisfy `{predicate}`")) } @@ -565,12 +569,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err } else { // If we can't find a generic parameter, just print a generic error + let predicate = self.tcx.short_string(predicate, &mut file); struct_span_code_err!( self.dcx(), span, E0284, - "type annotations needed: cannot satisfy `{}`", - predicate, + "type annotations needed: cannot satisfy `{predicate}`", ) .with_span_label(span, format!("cannot satisfy `{predicate}`")) } @@ -590,6 +594,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let Some(e) = self.tainted_by_errors() { return e; } + let alias = self.tcx.short_string(alias, &mut file); struct_span_code_err!( self.dcx(), span, @@ -603,16 +608,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let Some(e) = self.tainted_by_errors() { return e; } + let predicate = self.tcx.short_string(predicate, &mut file); struct_span_code_err!( self.dcx(), span, E0284, - "type annotations needed: cannot satisfy `{}`", - predicate, + "type annotations needed: cannot satisfy `{predicate}`", ) .with_span_label(span, format!("cannot satisfy `{predicate}`")) } }; + *err.long_ty_path() = file; self.note_obligation_cause(&mut err, obligation); err.emit() } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 6d39cbce3b7..87dcdcfd665 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1,5 +1,6 @@ use core::ops::ControlFlow; use std::borrow::Cow; +use std::path::PathBuf; use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::FxHashMap; @@ -9,7 +10,6 @@ use rustc_errors::{ Applicability, Diag, ErrorGuaranteed, Level, MultiSpan, StashKey, StringPart, Suggestions, pluralize, struct_span_code_err, }; -use rustc_hir::def::Namespace; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, LangItem, Node}; @@ -20,8 +20,8 @@ use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::print::{ - FmtPrinter, Print, PrintPolyTraitPredicateExt, PrintTraitPredicateExt as _, - PrintTraitRefExt as _, with_forced_trimmed_paths, + PrintPolyTraitPredicateExt, PrintTraitPredicateExt as _, PrintTraitRefExt as _, + with_forced_trimmed_paths, }; use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast}; use rustc_middle::{bug, span_bug}; @@ -60,6 +60,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) -> ErrorGuaranteed { let tcx = self.tcx; let mut span = obligation.cause.span; + let mut long_ty_file = None; let mut err = match *error { SelectionError::Unimplemented => { @@ -169,11 +170,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let Err(guar) = self.fn_arg_obligation(&obligation) { return guar; } - let mut file = None; let (post_message, pre_message, type_def) = self .get_parent_trait_ref(obligation.cause.code()) .map(|(t, s)| { - let t = self.tcx.short_ty_string(t, &mut file); + let t = self.tcx.short_string(t, &mut long_ty_file); ( format!(" in `{t}`"), format!("within `{t}`, "), @@ -181,12 +181,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) }) .unwrap_or_default(); - let file_note = file.as_ref().map(|file| format!( - "the full trait has been written to '{}'", - file.display(), - )); - - let mut long_ty_file = None; let OnUnimplementedNote { message, @@ -223,6 +217,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { None, append_const_msg, post_message, + &mut long_ty_file, ); let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::TransmuteTrait) @@ -251,14 +246,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; let mut err = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg); + *err.long_ty_path() = long_ty_file; - if let Some(long_ty_file) = long_ty_file { - err.note(format!( - "the full name for the type has been written to '{}'", - long_ty_file.display(), - )); - err.note("consider using `--verbose` to print the full type name to the console"); - } let mut suggested = false; if is_try_conversion { suggested = self.try_conversion_context(&obligation, main_trait_predicate, &mut err); @@ -309,7 +298,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return err.emit(); } - file_note.map(|note| err.note(note)); if let Some(s) = label { // If it has a custom `#[rustc_on_unimplemented]` // error message, let's display it as the label! @@ -708,6 +696,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { None, TypeError::Sorts(ty::error::ExpectedFound::new(expected_ty, ct_ty)), false, + None, ); diag } @@ -761,14 +750,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_ref: predicate.trait_ref, polarity: ty::PredicatePolarity::Positive, }); + let mut file = None; let err_msg = self.get_standard_error_message( trait_ref, None, Some(predicate.constness()), None, String::new(), + &mut file, ); let mut diag = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg); + *diag.long_ty_path() = file; if !self.predicate_may_hold(&Obligation::new( self.tcx, ObligationCause::dummy(), @@ -931,14 +923,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id); - let body_id = match self.tcx.hir_node(hir_id) { - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn { body: body_id, .. }, .. - }) => body_id, - _ => return false, - }; - let ControlFlow::Break(expr) = (FindMethodSubexprOfTry { search_span: span }) - .visit_body(self.tcx.hir().body(*body_id)) + let Some(body_id) = self.tcx.hir_node(hir_id).body_id() else { return false }; + let ControlFlow::Break(expr) = + (FindMethodSubexprOfTry { search_span: span }).visit_body(self.tcx.hir().body(body_id)) else { return false; }; @@ -1385,22 +1372,53 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => (None, error.err), }; - let msg = values + let mut file = None; + let (msg, span, closure_span) = values .and_then(|(predicate, normalized_term, expected_term)| { - self.maybe_detailed_projection_msg(predicate, normalized_term, expected_term) + self.maybe_detailed_projection_msg( + obligation.cause.span, + predicate, + normalized_term, + expected_term, + &mut file, + ) }) .unwrap_or_else(|| { - let mut cx = FmtPrinter::new_with_limit( - self.tcx, - Namespace::TypeNS, - rustc_session::Limit(10), - ); - with_forced_trimmed_paths!(format!("type mismatch resolving `{}`", { - self.resolve_vars_if_possible(predicate).print(&mut cx).unwrap(); - cx.into_buffer() - })) + ( + with_forced_trimmed_paths!(format!( + "type mismatch resolving `{}`", + self.tcx + .short_string(self.resolve_vars_if_possible(predicate), &mut file), + )), + obligation.cause.span, + None, + ) }); - let mut diag = struct_span_code_err!(self.dcx(), obligation.cause.span, E0271, "{msg}"); + let mut diag = struct_span_code_err!(self.dcx(), span, E0271, "{msg}"); + *diag.long_ty_path() = file; + if let Some(span) = closure_span { + // Mark the closure decl so that it is seen even if we are pointing at the return + // type or expression. + // + // error[E0271]: expected `{closure@foo.rs:41:16}` to be a closure that returns + // `Unit3`, but it returns `Unit4` + // --> $DIR/foo.rs:43:17 + // | + // LL | let v = Unit2.m( + // | - required by a bound introduced by this call + // ... + // LL | f: |x| { + // | --- /* this span */ + // LL | drop(x); + // LL | Unit4 + // | ^^^^^ expected `Unit3`, found `Unit4` + // | + diag.span_label(span, "this closure"); + if !span.overlaps(obligation.cause.span) { + // Point at the binding corresponding to the closure where it is used. + diag.span_label(obligation.cause.span, "closure used here"); + } + } let secondary_span = (|| { let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) = @@ -1443,15 +1461,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ty.span, with_forced_trimmed_paths!(Cow::from(format!( "type mismatch resolving `{}`", - { - let mut cx = FmtPrinter::new_with_limit( - self.tcx, - Namespace::TypeNS, - rustc_session::Limit(5), - ); - self.resolve_vars_if_possible(predicate).print(&mut cx).unwrap(); - cx.into_buffer() - } + self.tcx.short_string( + self.resolve_vars_if_possible(predicate), + diag.long_ty_path() + ), ))), true, )), @@ -1471,6 +1484,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }), err, false, + Some(span), ); self.note_obligation_cause(&mut diag, obligation); diag.emit() @@ -1479,34 +1493,65 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn maybe_detailed_projection_msg( &self, + mut span: Span, projection_term: ty::AliasTerm<'tcx>, normalized_ty: ty::Term<'tcx>, expected_ty: ty::Term<'tcx>, - ) -> Option<String> { + file: &mut Option<PathBuf>, + ) -> Option<(String, Span, Option<Span>)> { let trait_def_id = projection_term.trait_def_id(self.tcx); let self_ty = projection_term.self_ty(); with_forced_trimmed_paths! { if self.tcx.is_lang_item(projection_term.def_id, LangItem::FnOnceOutput) { - let fn_kind = self_ty.prefix_string(self.tcx); + let (span, closure_span) = if let ty::Closure(def_id, _) = self_ty.kind() { + let def_span = self.tcx.def_span(def_id); + if let Some(local_def_id) = def_id.as_local() + && let node = self.tcx.hir_node_by_def_id(local_def_id) + && let Some(fn_decl) = node.fn_decl() + && let Some(id) = node.body_id() + { + span = match fn_decl.output { + hir::FnRetTy::Return(ty) => ty.span, + hir::FnRetTy::DefaultReturn(_) => { + let body = self.tcx.hir().body(id); + match body.value.kind { + hir::ExprKind::Block( + hir::Block { expr: Some(expr), .. }, + _, + ) => expr.span, + hir::ExprKind::Block( + hir::Block { + expr: None, stmts: [.., last], .. + }, + _, + ) => last.span, + _ => body.value.span, + } + } + }; + } + (span, Some(def_span)) + } else { + (span, None) + }; let item = match self_ty.kind() { ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(), - _ => self_ty.to_string(), + _ => self.tcx.short_string(self_ty, file), }; - Some(format!( - "expected `{item}` to be a {fn_kind} that returns `{expected_ty}`, but it \ - returns `{normalized_ty}`", - )) + Some((format!( + "expected `{item}` to return `{expected_ty}`, but it returns `{normalized_ty}`", + ), span, closure_span)) } else if self.tcx.is_lang_item(trait_def_id, LangItem::Future) { - Some(format!( + Some((format!( "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it \ resolves to `{normalized_ty}`" - )) + ), span, None)) } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) { - Some(format!( + Some((format!( "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it \ yields `{normalized_ty}`" - )) + ), span, None)) } else { None } @@ -1923,8 +1968,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { StringPart::normal(" implemented for `"), ]); if types_content.0 == types_content.1 { - let ty = - self.tcx.short_ty_string(obligation_trait_ref.self_ty(), &mut None); + let ty = self + .tcx + .short_string(obligation_trait_ref.self_ty(), err.long_ty_path()); msg.push(StringPart::normal(ty)); } else { msg.extend(types.0.0); @@ -2281,7 +2327,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // First, attempt to add note to this error with an async-await-specific // message, and fall back to regular note otherwise. if !self.maybe_note_obligation_cause_for_async_await(err, obligation) { - let mut long_ty_file = None; self.note_obligation_cause_code( obligation.cause.body_id, err, @@ -2290,15 +2335,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation.cause.code(), &mut vec![], &mut Default::default(), - &mut long_ty_file, ); - if let Some(file) = long_ty_file { - err.note(format!( - "the full name for the type has been written to '{}'", - file.display(), - )); - err.note("consider using `--verbose` to print the full type name to the console"); - } self.suggest_unsized_bound_if_applicable(err, obligation); if let Some(span) = err.span.primary_span() && let Some(mut diag) = @@ -2342,6 +2379,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { predicate_constness: Option<ty::BoundConstness>, append_const_msg: Option<AppendConstMessage>, post_message: String, + long_ty_file: &mut Option<PathBuf>, ) -> String { message .and_then(|cannot_do_this| { @@ -2365,7 +2403,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .unwrap_or_else(|| { format!( "the trait bound `{}` is not satisfied{post_message}", - trait_predicate.print_with_bound_constness(predicate_constness) + self.tcx.short_string( + trait_predicate.print_with_bound_constness(predicate_constness), + long_ty_file, + ), ) }) } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 8111983c539..658fb4009d5 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -306,7 +306,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let ObligationCauseCode::WhereClause(..) | ObligationCauseCode::WhereClauseInExpr(..) = code { - let mut long_ty_file = None; self.note_obligation_cause_code( error.obligation.cause.body_id, &mut diag, @@ -315,17 +314,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { code, &mut vec![], &mut Default::default(), - &mut long_ty_file, ); - if let Some(file) = long_ty_file { - diag.note(format!( - "the full name for the type has been written to '{}'", - file.display(), - )); - diag.note( - "consider using `--verbose` to print the full type name to the console", - ); - } } diag.emit() } @@ -482,11 +471,10 @@ pub fn report_dyn_incompatibility<'tcx>( for (span, msg) in iter::zip(multi_span, messages) { note_span.push_span_label(span, msg); } - // FIXME(dyn_compat_renaming): Update the URL. err.span_note( note_span, "for a trait to be dyn compatible it needs to allow building a vtable\n\ - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>", + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>", ); // Only provide the help if its a local trait, otherwise it's not actionable. diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index 3d79b0acf83..518323f6526 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -932,7 +932,7 @@ impl<'tcx> OnUnimplementedFormatString { let value = match param.kind { GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { if let Some(ty) = trait_ref.args[param.index as usize].as_type() { - tcx.short_ty_string(ty, long_ty_file) + tcx.short_string(ty, long_ty_file) } else { trait_ref.args[param.index as usize].to_string() } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs index d82acc4e054..fad03b5e9bf 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs @@ -141,7 +141,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation.cause.span, suggest_increasing_limit, |err| { - let mut long_ty_file = None; self.note_obligation_cause_code( obligation.cause.body_id, err, @@ -150,17 +149,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation.cause.code(), &mut vec![], &mut Default::default(), - &mut long_ty_file, ); - if let Some(file) = long_ty_file { - err.note(format!( - "the full name for the type has been written to '{}'", - file.display(), - )); - err.note( - "consider using `--verbose` to print the full type name to the console", - ); - } }, ); } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index ab25bef4120..24ca7bb7fc2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3,7 +3,6 @@ use std::assert_matches::debug_assert_matches; use std::borrow::Cow; use std::iter; -use std::path::PathBuf; use itertools::{EitherOrBoth, Itertools}; use rustc_abi::ExternAbi; @@ -1297,30 +1296,24 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Because of this, we modify the error to refer to the original obligation and // return early in the caller. - let msg = format!("the trait bound `{old_pred}` is not satisfied"); + let msg = format!( + "the trait bound `{}` is not satisfied", + self.tcx.short_string(old_pred, err.long_ty_path()), + ); + let self_ty_str = + self.tcx.short_string(old_pred.self_ty().skip_binder(), err.long_ty_path()); if has_custom_message { err.note(msg); } else { err.messages = vec![(rustc_errors::DiagMessage::from(msg), Style::NoStyle)]; } - let mut file = None; err.span_label( span, format!( - "the trait `{}` is not implemented for `{}`", - old_pred.print_modifiers_and_trait_path(), - self.tcx.short_ty_string(old_pred.self_ty().skip_binder(), &mut file), + "the trait `{}` is not implemented for `{self_ty_str}`", + old_pred.print_modifiers_and_trait_path() ), ); - if let Some(file) = file { - err.note(format!( - "the full type name has been written to '{}'", - file.display() - )); - err.note( - "consider using `--verbose` to print full type name to the console", - ); - } if imm_ref_self_ty_satisfies_pred && mut_ref_self_ty_satisfies_pred { err.span_suggestions( @@ -2689,7 +2682,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Add a note for the item obligation that remains - normally a note pointing to the // bound that introduced the obligation (e.g. `T: Send`). debug!(?next_code); - let mut long_ty_file = None; self.note_obligation_cause_code( obligation.cause.body_id, err, @@ -2698,7 +2690,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { next_code.unwrap(), &mut Vec::new(), &mut Default::default(), - &mut long_ty_file, ); } @@ -2711,7 +2702,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { cause_code: &ObligationCauseCode<'tcx>, obligated_types: &mut Vec<Ty<'tcx>>, seen_requirements: &mut FxHashSet<DefId>, - long_ty_file: &mut Option<PathBuf>, ) where T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>, { @@ -2965,9 +2955,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } ObligationCauseCode::Coercion { source, target } => { let source = - tcx.short_ty_string(self.resolve_vars_if_possible(source), long_ty_file); + tcx.short_string(self.resolve_vars_if_possible(source), err.long_ty_path()); let target = - tcx.short_ty_string(self.resolve_vars_if_possible(target), long_ty_file); + tcx.short_string(self.resolve_vars_if_possible(target), err.long_ty_path()); err.note(with_forced_trimmed_paths!(format!( "required for the cast from `{source}` to `{target}`", ))); @@ -3252,7 +3242,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; if !is_upvar_tys_infer_tuple { - let ty_str = tcx.short_ty_string(ty, long_ty_file); + let ty_str = tcx.short_string(ty, err.long_ty_path()); let msg = format!("required because it appears within the type `{ty_str}`"); match ty.kind() { ty::Adt(def, _) => match tcx.opt_item_ident(def.did()) { @@ -3330,7 +3320,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &data.parent_code, obligated_types, seen_requirements, - long_ty_file, ) }); } else { @@ -3343,7 +3332,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { cause_code.peel_derives(), obligated_types, seen_requirements, - long_ty_file, ) }); } @@ -3353,7 +3341,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.resolve_vars_if_possible(data.derived.parent_trait_pred); let parent_def_id = parent_trait_pred.def_id(); let self_ty_str = - tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), long_ty_file); + tcx.short_string(parent_trait_pred.skip_binder().self_ty(), err.long_ty_path()); let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string(); let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`"); let mut is_auto_trait = false; @@ -3449,8 +3437,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { count, pluralize!(count) )); - let self_ty = tcx - .short_ty_string(parent_trait_pred.skip_binder().self_ty(), long_ty_file); + let self_ty = tcx.short_string( + parent_trait_pred.skip_binder().self_ty(), + err.long_ty_path(), + ); err.note(format!( "required for `{self_ty}` to implement `{}`", parent_trait_pred.print_modifiers_and_trait_path() @@ -3466,7 +3456,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &data.parent_code, obligated_types, seen_requirements, - long_ty_file, ) }); } @@ -3505,7 +3494,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &data.derived.parent_code, obligated_types, seen_requirements, - long_ty_file, ) }); } @@ -3519,7 +3507,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &data.parent_code, obligated_types, seen_requirements, - long_ty_file, ) }); } @@ -3536,7 +3523,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &data.parent_code, obligated_types, seen_requirements, - long_ty_file, ) }); } @@ -3551,7 +3537,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { nested, obligated_types, seen_requirements, - long_ty_file, ) }); let mut multispan = MultiSpan::from(span); @@ -3582,7 +3567,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { parent_code, obligated_types, seen_requirements, - long_ty_file, ) }); } @@ -3622,7 +3606,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } ObligationCauseCode::OpaqueReturnType(expr_info) => { let (expr_ty, expr) = if let Some((expr_ty, hir_id)) = expr_info { - let expr_ty = tcx.short_ty_string(expr_ty, long_ty_file); + let expr_ty = tcx.short_string(expr_ty, err.long_ty_path()); let expr = tcx.hir().expect_expr(hir_id); (expr_ty, expr) } else if let Some(body_id) = tcx.hir_node_by_def_id(body_id).body_id() @@ -3637,7 +3621,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder() && self.can_eq(param_env, pred.self_ty(), expr_ty) { - let expr_ty = tcx.short_ty_string(expr_ty, long_ty_file); + let expr_ty = tcx.short_string(expr_ty, err.long_ty_path()); (expr_ty, expr) } else { return; @@ -5231,7 +5215,7 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>( format!( "{pre_message}the trait `{}` is not implemented for{desc} `{}`", trait_predicate.print_modifiers_and_trait_path(), - tcx.short_ty_string(trait_predicate.self_ty().skip_binder(), &mut None), + tcx.short_string(trait_predicate.self_ty().skip_binder(), &mut None), ) } else { // "the trait bound `T: !Send` is not satisfied" reads better than "`!Send` is diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index c8672b9dbd2..62cac5b17bd 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -12,7 +12,7 @@ use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty}; use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, Node}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath}; -use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, PolyTraitRef, Region, Ty, TyCtxt}; +use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, Region, Ty, TyCtxt}; use rustc_span::{BytePos, Ident, Span, Symbol, kw}; use crate::error_reporting::infer::ObligationCauseAsDiagArg; @@ -23,15 +23,6 @@ use crate::fluent_generated as fluent; pub mod note_and_explain; #[derive(Diagnostic)] -#[diag(trait_selection_dump_vtable_entries)] -pub struct DumpVTableEntries<'a> { - #[primary_span] - pub span: Span, - pub trait_ref: PolyTraitRef<'a>, - pub entries: String, -} - -#[derive(Diagnostic)] #[diag(trait_selection_unable_to_construct_constant_value)] pub struct UnableToConstructConstantValue<'a> { #[primary_span] @@ -1400,15 +1391,13 @@ pub struct OpaqueCapturesLifetime<'tcx> { pub enum FunctionPointerSuggestion<'a> { #[suggestion( trait_selection_fps_use_ref, - code = "&{fn_name}", + code = "&", style = "verbose", applicability = "maybe-incorrect" )] UseRef { #[primary_span] span: Span, - #[skip_arg] - fn_name: String, }, #[suggestion( trait_selection_fps_remove_ref, @@ -1438,7 +1427,7 @@ pub enum FunctionPointerSuggestion<'a> { }, #[suggestion( trait_selection_fps_cast, - code = "{fn_name} as {sig}", + code = " as {sig}", style = "verbose", applicability = "maybe-incorrect" )] @@ -1446,13 +1435,11 @@ pub enum FunctionPointerSuggestion<'a> { #[primary_span] span: Span, #[skip_arg] - fn_name: String, - #[skip_arg] sig: Binder<'a, FnSig<'a>>, }, #[suggestion( trait_selection_fps_cast_both, - code = "{fn_name} as {found_sig}", + code = " as {found_sig}", style = "hidden", applicability = "maybe-incorrect" )] @@ -1460,8 +1447,6 @@ pub enum FunctionPointerSuggestion<'a> { #[primary_span] span: Span, #[skip_arg] - fn_name: String, - #[skip_arg] found_sig: Binder<'a, FnSig<'a>>, expected_sig: Binder<'a, FnSig<'a>>, }, diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index acd00d9f74f..abb79493432 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -1,7 +1,7 @@ use std::ops::Deref; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::canonical::{ Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues, @@ -98,9 +98,10 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< param_env: ty::ParamEnv<'tcx>, arg: ty::GenericArg<'tcx>, ) -> Option<Vec<Goal<'tcx, ty::Predicate<'tcx>>>> { - crate::traits::wf::unnormalized_obligations(&self.0, param_env, arg).map(|obligations| { - obligations.into_iter().map(|obligation| obligation.into()).collect() - }) + crate::traits::wf::unnormalized_obligations(&self.0, param_env, arg, DUMMY_SP, CRATE_DEF_ID) + .map(|obligations| { + obligations.into_iter().map(|obligation| obligation.into()).collect() + }) } fn clone_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 2b7da4bc5ff..0db44eda847 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -1,25 +1,21 @@ use std::marker::PhantomData; use std::mem; -use std::ops::ControlFlow; use rustc_data_structures::thinvec::ExtractIf; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; -use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause}; use rustc_infer::traits::{ - self, FromSolverError, MismatchedProjectionTypes, Obligation, ObligationCause, - ObligationCauseCode, PredicateObligation, PredicateObligations, SelectionError, TraitEngine, + FromSolverError, PredicateObligation, PredicateObligations, TraitEngine, }; -use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_middle::{bug, span_bug}; use rustc_next_trait_solver::solve::{GenerateProofTree, HasChanged, SolverDelegateEvalExt as _}; -use tracing::{instrument, trace}; +use tracing::instrument; +use self::derive_errors::*; use super::Certainty; use super::delegate::SolverDelegate; -use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor}; -use crate::traits::{FulfillmentError, FulfillmentErrorCode, ScrubbedTraitError}; +use crate::traits::{FulfillmentError, ScrubbedTraitError}; + +mod derive_errors; /// A trait engine using the new trait solver. /// @@ -244,483 +240,3 @@ impl<'tcx> FromSolverError<'tcx, NextSolverError<'tcx>> for ScrubbedTraitError<' } } } - -fn fulfillment_error_for_no_solution<'tcx>( - infcx: &InferCtxt<'tcx>, - root_obligation: PredicateObligation<'tcx>, -) -> FulfillmentError<'tcx> { - let obligation = find_best_leaf_obligation(infcx, &root_obligation, false); - - let code = match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => { - FulfillmentErrorCode::Project( - // FIXME: This could be a `Sorts` if the term is a type - MismatchedProjectionTypes { err: TypeError::Mismatch }, - ) - } - ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, expected_ty)) => { - let ct_ty = match ct.kind() { - ty::ConstKind::Unevaluated(uv) => { - infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args) - } - ty::ConstKind::Param(param_ct) => param_ct.find_ty_from_env(obligation.param_env), - ty::ConstKind::Value(ty, _) => ty, - kind => span_bug!( - obligation.cause.span, - "ConstArgHasWrongType failed but we don't know how to compute type for {kind:?}" - ), - }; - FulfillmentErrorCode::Select(SelectionError::ConstArgHasWrongType { - ct, - ct_ty, - expected_ty, - }) - } - ty::PredicateKind::NormalizesTo(..) => { - FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch }) - } - ty::PredicateKind::AliasRelate(_, _, _) => { - FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch }) - } - ty::PredicateKind::Subtype(pred) => { - let (a, b) = infcx.enter_forall_and_leak_universe( - obligation.predicate.kind().rebind((pred.a, pred.b)), - ); - let expected_found = ExpectedFound::new(a, b); - FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found)) - } - ty::PredicateKind::Coerce(pred) => { - let (a, b) = infcx.enter_forall_and_leak_universe( - obligation.predicate.kind().rebind((pred.a, pred.b)), - ); - let expected_found = ExpectedFound::new(b, a); - FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found)) - } - ty::PredicateKind::Clause(_) - | ty::PredicateKind::DynCompatible(_) - | ty::PredicateKind::Ambiguous => { - FulfillmentErrorCode::Select(SelectionError::Unimplemented) - } - ty::PredicateKind::ConstEquate(..) => { - bug!("unexpected goal: {obligation:?}") - } - }; - - FulfillmentError { obligation, code, root_obligation } -} - -fn fulfillment_error_for_stalled<'tcx>( - infcx: &InferCtxt<'tcx>, - root_obligation: PredicateObligation<'tcx>, -) -> FulfillmentError<'tcx> { - let (code, refine_obligation) = infcx.probe(|_| { - match <&SolverDelegate<'tcx>>::from(infcx) - .evaluate_root_goal(root_obligation.clone().into(), GenerateProofTree::No) - .0 - { - Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => { - (FulfillmentErrorCode::Ambiguity { overflow: None }, true) - } - Ok((_, Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }))) => ( - FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) }, - // Don't look into overflows because we treat overflows weirdly anyways. - // We discard the inference constraints from overflowing goals, so - // recomputing the goal again during `find_best_leaf_obligation` may apply - // inference guidance that makes other goals go from ambig -> pass, for example. - // - // FIXME: We should probably just look into overflows here. - false, - ), - Ok((_, Certainty::Yes)) => { - bug!("did not expect successful goal when collecting ambiguity errors") - } - Err(_) => { - bug!("did not expect selection error when collecting ambiguity errors") - } - } - }); - - FulfillmentError { - obligation: if refine_obligation { - find_best_leaf_obligation(infcx, &root_obligation, true) - } else { - root_obligation.clone() - }, - code, - root_obligation, - } -} - -fn fulfillment_error_for_overflow<'tcx>( - infcx: &InferCtxt<'tcx>, - root_obligation: PredicateObligation<'tcx>, -) -> FulfillmentError<'tcx> { - FulfillmentError { - obligation: find_best_leaf_obligation(infcx, &root_obligation, true), - code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) }, - root_obligation, - } -} - -fn find_best_leaf_obligation<'tcx>( - infcx: &InferCtxt<'tcx>, - obligation: &PredicateObligation<'tcx>, - consider_ambiguities: bool, -) -> PredicateObligation<'tcx> { - let obligation = infcx.resolve_vars_if_possible(obligation.clone()); - // FIXME: we use a probe here as the `BestObligation` visitor does not - // check whether it uses candidates which get shadowed by where-bounds. - // - // We should probably fix the visitor to not do so instead, as this also - // means the leaf obligation may be incorrect. - infcx - .fudge_inference_if_ok(|| { - infcx - .visit_proof_tree(obligation.clone().into(), &mut BestObligation { - obligation: obligation.clone(), - consider_ambiguities, - }) - .break_value() - .ok_or(()) - }) - .unwrap_or(obligation) -} - -struct BestObligation<'tcx> { - obligation: PredicateObligation<'tcx>, - consider_ambiguities: bool, -} - -impl<'tcx> BestObligation<'tcx> { - fn with_derived_obligation( - &mut self, - derived_obligation: PredicateObligation<'tcx>, - and_then: impl FnOnce(&mut Self) -> <Self as ProofTreeVisitor<'tcx>>::Result, - ) -> <Self as ProofTreeVisitor<'tcx>>::Result { - let old_obligation = std::mem::replace(&mut self.obligation, derived_obligation); - let res = and_then(self); - self.obligation = old_obligation; - res - } - - /// Filter out the candidates that aren't interesting to visit for the - /// purposes of reporting errors. For ambiguities, we only consider - /// candidates that may hold. For errors, we only consider candidates that - /// *don't* hold and which have impl-where clauses that also don't hold. - fn non_trivial_candidates<'a>( - &self, - goal: &'a inspect::InspectGoal<'a, 'tcx>, - ) -> Vec<inspect::InspectCandidate<'a, 'tcx>> { - let mut candidates = goal.candidates(); - match self.consider_ambiguities { - true => { - // If we have an ambiguous obligation, we must consider *all* candidates - // that hold, or else we may guide inference causing other goals to go - // from ambig -> pass/fail. - candidates.retain(|candidate| candidate.result().is_ok()); - } - false => { - // If we have >1 candidate, one may still be due to "boring" reasons, like - // an alias-relate that failed to hold when deeply evaluated. We really - // don't care about reasons like this. - if candidates.len() > 1 { - candidates.retain(|candidate| { - goal.infcx().probe(|_| { - candidate.instantiate_nested_goals(self.span()).iter().any( - |nested_goal| { - matches!( - nested_goal.source(), - GoalSource::ImplWhereBound - | GoalSource::AliasBoundConstCondition - | GoalSource::InstantiateHigherRanked - | GoalSource::AliasWellFormed - ) && match self.consider_ambiguities { - true => { - matches!( - nested_goal.result(), - Ok(Certainty::Maybe(MaybeCause::Ambiguity)) - ) - } - false => matches!(nested_goal.result(), Err(_)), - } - }, - ) - }) - }); - } - - // Prefer a non-rigid candidate if there is one. - if candidates.len() > 1 { - candidates.retain(|candidate| { - !matches!(candidate.kind(), inspect::ProbeKind::RigidAlias { .. }) - }); - } - } - } - - candidates - } -} - -impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { - type Result = ControlFlow<PredicateObligation<'tcx>>; - - fn span(&self) -> rustc_span::Span { - self.obligation.cause.span - } - - #[instrument(level = "trace", skip(self, goal), fields(goal = ?goal.goal()))] - fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result { - let candidates = self.non_trivial_candidates(goal); - trace!(candidates = ?candidates.iter().map(|c| c.kind()).collect::<Vec<_>>()); - - let [candidate] = candidates.as_slice() else { - return ControlFlow::Break(self.obligation.clone()); - }; - - // Don't walk into impls that have `do_not_recommend`. - if let inspect::ProbeKind::TraitCandidate { - source: CandidateSource::Impl(impl_def_id), - result: _, - } = candidate.kind() - && goal.infcx().tcx.do_not_recommend_impl(impl_def_id) - { - return ControlFlow::Break(self.obligation.clone()); - } - - let tcx = goal.infcx().tcx; - // FIXME: Also, what about considering >1 layer up the stack? May be necessary - // for normalizes-to. - let pred_kind = goal.goal().predicate.kind(); - let child_mode = match pred_kind.skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { - ChildMode::Trait(pred_kind.rebind(pred)) - } - ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(pred)) => { - ChildMode::Host(pred_kind.rebind(pred)) - } - ty::PredicateKind::NormalizesTo(normalizes_to) - if matches!( - normalizes_to.alias.kind(tcx), - ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst - ) => - { - ChildMode::Trait(pred_kind.rebind(ty::TraitPredicate { - trait_ref: normalizes_to.alias.trait_ref(tcx), - polarity: ty::PredicatePolarity::Positive, - })) - } - _ => ChildMode::PassThrough, - }; - - let nested_goals = candidate.instantiate_nested_goals(self.span()); - - // If the candidate requires some `T: FnPtr` bound which does not hold should not be treated as - // an actual candidate, instead we should treat them as if the impl was never considered to - // have potentially applied. As if `impl<A, R> Trait for for<..> fn(..A) -> R` was written - // instead of `impl<T: FnPtr> Trait for T`. - // - // We do this as a separate loop so that we do not choose to tell the user about some nested - // goal before we encounter a `T: FnPtr` nested goal. - for nested_goal in &nested_goals { - if let Some(fn_ptr_trait) = tcx.lang_items().fn_ptr_trait() - && let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause() - && poly_trait_pred.def_id() == fn_ptr_trait - && let Err(NoSolution) = nested_goal.result() - { - return ControlFlow::Break(self.obligation.clone()); - } - } - - let mut impl_where_bound_count = 0; - for nested_goal in nested_goals { - trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result())); - - let make_obligation = |cause| Obligation { - cause, - param_env: nested_goal.goal().param_env, - predicate: nested_goal.goal().predicate, - recursion_depth: self.obligation.recursion_depth + 1, - }; - - let obligation; - match (child_mode, nested_goal.source()) { - (ChildMode::Trait(_) | ChildMode::Host(_), GoalSource::Misc) => { - continue; - } - (ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => { - obligation = make_obligation(derive_cause( - tcx, - candidate.kind(), - self.obligation.cause.clone(), - impl_where_bound_count, - parent_trait_pred, - )); - impl_where_bound_count += 1; - } - ( - ChildMode::Host(parent_host_pred), - GoalSource::ImplWhereBound | GoalSource::AliasBoundConstCondition, - ) => { - obligation = make_obligation(derive_host_cause( - tcx, - candidate.kind(), - self.obligation.cause.clone(), - impl_where_bound_count, - parent_host_pred, - )); - impl_where_bound_count += 1; - } - // Skip over a higher-ranked predicate. - (_, GoalSource::InstantiateHigherRanked) => { - obligation = self.obligation.clone(); - } - (ChildMode::PassThrough, _) - | (_, GoalSource::AliasWellFormed | GoalSource::AliasBoundConstCondition) => { - obligation = make_obligation(self.obligation.cause.clone()); - } - } - - // Skip nested goals that aren't the *reason* for our goal's failure. - match self.consider_ambiguities { - true if matches!( - nested_goal.result(), - Ok(Certainty::Maybe(MaybeCause::Ambiguity)) - ) => {} - false if matches!(nested_goal.result(), Err(_)) => {} - _ => continue, - } - - self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?; - } - - // alias-relate may fail because the lhs or rhs can't be normalized, - // and therefore is treated as rigid. - if let Some(ty::PredicateKind::AliasRelate(lhs, rhs, _)) = pred_kind.no_bound_vars() { - if let Some(obligation) = goal - .infcx() - .visit_proof_tree_at_depth( - goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(lhs.into())), - goal.depth() + 1, - self, - ) - .break_value() - { - return ControlFlow::Break(obligation); - } else if let Some(obligation) = goal - .infcx() - .visit_proof_tree_at_depth( - goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(rhs.into())), - goal.depth() + 1, - self, - ) - .break_value() - { - return ControlFlow::Break(obligation); - } - } - - ControlFlow::Break(self.obligation.clone()) - } -} - -#[derive(Debug, Copy, Clone)] -enum ChildMode<'tcx> { - // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`, - // and skip all `GoalSource::Misc`, which represent useless obligations - // such as alias-eq which may not hold. - Trait(ty::PolyTraitPredicate<'tcx>), - // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`, - // and skip all `GoalSource::Misc`, which represent useless obligations - // such as alias-eq which may not hold. - Host(ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>), - // Skip trying to derive an `ObligationCause` from this obligation, and - // report *all* sub-obligations as if they came directly from the parent - // obligation. - PassThrough, -} - -fn derive_cause<'tcx>( - tcx: TyCtxt<'tcx>, - candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>, - mut cause: ObligationCause<'tcx>, - idx: usize, - parent_trait_pred: ty::PolyTraitPredicate<'tcx>, -) -> ObligationCause<'tcx> { - match candidate_kind { - inspect::ProbeKind::TraitCandidate { - source: CandidateSource::Impl(impl_def_id), - result: _, - } => { - if let Some((_, span)) = - tcx.predicates_of(impl_def_id).instantiate_identity(tcx).iter().nth(idx) - { - cause = cause.derived_cause(parent_trait_pred, |derived| { - ObligationCauseCode::ImplDerived(Box::new(traits::ImplDerivedCause { - derived, - impl_or_alias_def_id: impl_def_id, - impl_def_predicate_index: Some(idx), - span, - })) - }) - } - } - inspect::ProbeKind::TraitCandidate { - source: CandidateSource::BuiltinImpl(..), - result: _, - } => { - cause = cause.derived_cause(parent_trait_pred, ObligationCauseCode::BuiltinDerived); - } - _ => {} - }; - cause -} - -fn derive_host_cause<'tcx>( - tcx: TyCtxt<'tcx>, - candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>, - mut cause: ObligationCause<'tcx>, - idx: usize, - parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>, -) -> ObligationCause<'tcx> { - match candidate_kind { - inspect::ProbeKind::TraitCandidate { - source: CandidateSource::Impl(impl_def_id), - result: _, - } => { - if let Some((_, span)) = tcx - .predicates_of(impl_def_id) - .instantiate_identity(tcx) - .into_iter() - .chain(tcx.const_conditions(impl_def_id).instantiate_identity(tcx).into_iter().map( - |(trait_ref, span)| { - ( - trait_ref.to_host_effect_clause( - tcx, - parent_host_pred.skip_binder().constness, - ), - span, - ) - }, - )) - .nth(idx) - { - cause = - cause.derived_host_cause(parent_host_pred, |derived| { - ObligationCauseCode::ImplDerivedHost(Box::new( - traits::ImplDerivedHostCause { derived, impl_def_id, span }, - )) - }) - } - } - inspect::ProbeKind::TraitCandidate { - source: CandidateSource::BuiltinImpl(..), - result: _, - } => { - cause = - cause.derived_host_cause(parent_host_pred, ObligationCauseCode::BuiltinDerivedHost); - } - _ => {} - }; - cause -} diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs new file mode 100644 index 00000000000..c64bc19835b --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -0,0 +1,527 @@ +use std::ops::ControlFlow; + +use rustc_infer::infer::InferCtxt; +use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause}; +use rustc_infer::traits::{ + self, MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode, + PredicateObligation, SelectionError, +}; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::{bug, span_bug}; +use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _}; +use rustc_type_ir::solve::{Goal, NoSolution}; +use tracing::{instrument, trace}; + +use crate::solve::Certainty; +use crate::solve::delegate::SolverDelegate; +use crate::solve::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor}; +use crate::traits::{FulfillmentError, FulfillmentErrorCode, wf}; + +pub(super) fn fulfillment_error_for_no_solution<'tcx>( + infcx: &InferCtxt<'tcx>, + root_obligation: PredicateObligation<'tcx>, +) -> FulfillmentError<'tcx> { + let obligation = find_best_leaf_obligation(infcx, &root_obligation, false); + + let code = match obligation.predicate.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => { + FulfillmentErrorCode::Project( + // FIXME: This could be a `Sorts` if the term is a type + MismatchedProjectionTypes { err: TypeError::Mismatch }, + ) + } + ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, expected_ty)) => { + let ct_ty = match ct.kind() { + ty::ConstKind::Unevaluated(uv) => { + infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args) + } + ty::ConstKind::Param(param_ct) => param_ct.find_ty_from_env(obligation.param_env), + ty::ConstKind::Value(cv) => cv.ty, + kind => span_bug!( + obligation.cause.span, + "ConstArgHasWrongType failed but we don't know how to compute type for {kind:?}" + ), + }; + FulfillmentErrorCode::Select(SelectionError::ConstArgHasWrongType { + ct, + ct_ty, + expected_ty, + }) + } + ty::PredicateKind::NormalizesTo(..) => { + FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch }) + } + ty::PredicateKind::AliasRelate(_, _, _) => { + FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch }) + } + ty::PredicateKind::Subtype(pred) => { + let (a, b) = infcx.enter_forall_and_leak_universe( + obligation.predicate.kind().rebind((pred.a, pred.b)), + ); + let expected_found = ExpectedFound::new(a, b); + FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found)) + } + ty::PredicateKind::Coerce(pred) => { + let (a, b) = infcx.enter_forall_and_leak_universe( + obligation.predicate.kind().rebind((pred.a, pred.b)), + ); + let expected_found = ExpectedFound::new(b, a); + FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found)) + } + ty::PredicateKind::Clause(_) + | ty::PredicateKind::DynCompatible(_) + | ty::PredicateKind::Ambiguous => { + FulfillmentErrorCode::Select(SelectionError::Unimplemented) + } + ty::PredicateKind::ConstEquate(..) => { + bug!("unexpected goal: {obligation:?}") + } + }; + + FulfillmentError { obligation, code, root_obligation } +} + +pub(super) fn fulfillment_error_for_stalled<'tcx>( + infcx: &InferCtxt<'tcx>, + root_obligation: PredicateObligation<'tcx>, +) -> FulfillmentError<'tcx> { + let (code, refine_obligation) = infcx.probe(|_| { + match <&SolverDelegate<'tcx>>::from(infcx) + .evaluate_root_goal(root_obligation.clone().into(), GenerateProofTree::No) + .0 + { + Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => { + (FulfillmentErrorCode::Ambiguity { overflow: None }, true) + } + Ok((_, Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }))) => ( + FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) }, + // Don't look into overflows because we treat overflows weirdly anyways. + // We discard the inference constraints from overflowing goals, so + // recomputing the goal again during `find_best_leaf_obligation` may apply + // inference guidance that makes other goals go from ambig -> pass, for example. + // + // FIXME: We should probably just look into overflows here. + false, + ), + Ok((_, Certainty::Yes)) => { + bug!("did not expect successful goal when collecting ambiguity errors") + } + Err(_) => { + bug!("did not expect selection error when collecting ambiguity errors") + } + } + }); + + FulfillmentError { + obligation: if refine_obligation { + find_best_leaf_obligation(infcx, &root_obligation, true) + } else { + root_obligation.clone() + }, + code, + root_obligation, + } +} + +pub(super) fn fulfillment_error_for_overflow<'tcx>( + infcx: &InferCtxt<'tcx>, + root_obligation: PredicateObligation<'tcx>, +) -> FulfillmentError<'tcx> { + FulfillmentError { + obligation: find_best_leaf_obligation(infcx, &root_obligation, true), + code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) }, + root_obligation, + } +} + +fn find_best_leaf_obligation<'tcx>( + infcx: &InferCtxt<'tcx>, + obligation: &PredicateObligation<'tcx>, + consider_ambiguities: bool, +) -> PredicateObligation<'tcx> { + let obligation = infcx.resolve_vars_if_possible(obligation.clone()); + // FIXME: we use a probe here as the `BestObligation` visitor does not + // check whether it uses candidates which get shadowed by where-bounds. + // + // We should probably fix the visitor to not do so instead, as this also + // means the leaf obligation may be incorrect. + infcx + .fudge_inference_if_ok(|| { + infcx + .visit_proof_tree(obligation.clone().into(), &mut BestObligation { + obligation: obligation.clone(), + consider_ambiguities, + }) + .break_value() + .ok_or(()) + }) + .unwrap_or(obligation) +} + +struct BestObligation<'tcx> { + obligation: PredicateObligation<'tcx>, + consider_ambiguities: bool, +} + +impl<'tcx> BestObligation<'tcx> { + fn with_derived_obligation( + &mut self, + derived_obligation: PredicateObligation<'tcx>, + and_then: impl FnOnce(&mut Self) -> <Self as ProofTreeVisitor<'tcx>>::Result, + ) -> <Self as ProofTreeVisitor<'tcx>>::Result { + let old_obligation = std::mem::replace(&mut self.obligation, derived_obligation); + let res = and_then(self); + self.obligation = old_obligation; + res + } + + /// Filter out the candidates that aren't interesting to visit for the + /// purposes of reporting errors. For ambiguities, we only consider + /// candidates that may hold. For errors, we only consider candidates that + /// *don't* hold and which have impl-where clauses that also don't hold. + fn non_trivial_candidates<'a>( + &self, + goal: &'a inspect::InspectGoal<'a, 'tcx>, + ) -> Vec<inspect::InspectCandidate<'a, 'tcx>> { + let mut candidates = goal.candidates(); + match self.consider_ambiguities { + true => { + // If we have an ambiguous obligation, we must consider *all* candidates + // that hold, or else we may guide inference causing other goals to go + // from ambig -> pass/fail. + candidates.retain(|candidate| candidate.result().is_ok()); + } + false => { + // If we have >1 candidate, one may still be due to "boring" reasons, like + // an alias-relate that failed to hold when deeply evaluated. We really + // don't care about reasons like this. + if candidates.len() > 1 { + candidates.retain(|candidate| { + goal.infcx().probe(|_| { + candidate.instantiate_nested_goals(self.span()).iter().any( + |nested_goal| { + matches!( + nested_goal.source(), + GoalSource::ImplWhereBound + | GoalSource::AliasBoundConstCondition + | GoalSource::InstantiateHigherRanked + | GoalSource::AliasWellFormed + ) && match (self.consider_ambiguities, nested_goal.result()) { + (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) + | (false, Err(_)) => true, + _ => false, + } + }, + ) + }) + }); + } + + // Prefer a non-rigid candidate if there is one. + if candidates.len() > 1 { + candidates.retain(|candidate| { + !matches!(candidate.kind(), inspect::ProbeKind::RigidAlias { .. }) + }); + } + } + } + + candidates + } + + /// HACK: We walk the nested obligations for a well-formed arg manually, + /// since there's nontrivial logic in `wf.rs` to set up an obligation cause. + /// Ideally we'd be able to track this better. + fn visit_well_formed_goal( + &mut self, + candidate: &inspect::InspectCandidate<'_, 'tcx>, + arg: ty::GenericArg<'tcx>, + ) -> ControlFlow<PredicateObligation<'tcx>> { + let infcx = candidate.goal().infcx(); + let param_env = candidate.goal().goal().param_env; + let body_id = self.obligation.cause.body_id; + + for obligation in wf::unnormalized_obligations(infcx, param_env, arg, self.span(), body_id) + .into_iter() + .flatten() + { + let nested_goal = candidate.instantiate_proof_tree_for_nested_goal( + GoalSource::Misc, + Goal::new(infcx.tcx, obligation.param_env, obligation.predicate), + self.span(), + ); + // Skip nested goals that aren't the *reason* for our goal's failure. + match (self.consider_ambiguities, nested_goal.result()) { + (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) | (false, Err(_)) => {} + _ => continue, + } + + self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?; + } + + ControlFlow::Break(self.obligation.clone()) + } +} + +impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { + type Result = ControlFlow<PredicateObligation<'tcx>>; + + fn span(&self) -> rustc_span::Span { + self.obligation.cause.span + } + + #[instrument(level = "trace", skip(self, goal), fields(goal = ?goal.goal()))] + fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result { + let candidates = self.non_trivial_candidates(goal); + trace!(candidates = ?candidates.iter().map(|c| c.kind()).collect::<Vec<_>>()); + + let [candidate] = candidates.as_slice() else { + return ControlFlow::Break(self.obligation.clone()); + }; + + // Don't walk into impls that have `do_not_recommend`. + if let inspect::ProbeKind::TraitCandidate { + source: CandidateSource::Impl(impl_def_id), + result: _, + } = candidate.kind() + && goal.infcx().tcx.do_not_recommend_impl(impl_def_id) + { + return ControlFlow::Break(self.obligation.clone()); + } + + let tcx = goal.infcx().tcx; + // FIXME: Also, what about considering >1 layer up the stack? May be necessary + // for normalizes-to. + let pred_kind = goal.goal().predicate.kind(); + let child_mode = match pred_kind.skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { + ChildMode::Trait(pred_kind.rebind(pred)) + } + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(pred)) => { + ChildMode::Host(pred_kind.rebind(pred)) + } + ty::PredicateKind::NormalizesTo(normalizes_to) + if matches!( + normalizes_to.alias.kind(tcx), + ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst + ) => + { + ChildMode::Trait(pred_kind.rebind(ty::TraitPredicate { + trait_ref: normalizes_to.alias.trait_ref(tcx), + polarity: ty::PredicatePolarity::Positive, + })) + } + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { + return self.visit_well_formed_goal(candidate, arg); + } + _ => ChildMode::PassThrough, + }; + + let nested_goals = candidate.instantiate_nested_goals(self.span()); + + // If the candidate requires some `T: FnPtr` bound which does not hold should not be treated as + // an actual candidate, instead we should treat them as if the impl was never considered to + // have potentially applied. As if `impl<A, R> Trait for for<..> fn(..A) -> R` was written + // instead of `impl<T: FnPtr> Trait for T`. + // + // We do this as a separate loop so that we do not choose to tell the user about some nested + // goal before we encounter a `T: FnPtr` nested goal. + for nested_goal in &nested_goals { + if let Some(fn_ptr_trait) = tcx.lang_items().fn_ptr_trait() + && let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause() + && poly_trait_pred.def_id() == fn_ptr_trait + && let Err(NoSolution) = nested_goal.result() + { + return ControlFlow::Break(self.obligation.clone()); + } + } + + let mut impl_where_bound_count = 0; + for nested_goal in nested_goals { + trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result())); + + let make_obligation = |cause| Obligation { + cause, + param_env: nested_goal.goal().param_env, + predicate: nested_goal.goal().predicate, + recursion_depth: self.obligation.recursion_depth + 1, + }; + + let obligation; + match (child_mode, nested_goal.source()) { + (ChildMode::Trait(_) | ChildMode::Host(_), GoalSource::Misc) => { + continue; + } + (ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => { + obligation = make_obligation(derive_cause( + tcx, + candidate.kind(), + self.obligation.cause.clone(), + impl_where_bound_count, + parent_trait_pred, + )); + impl_where_bound_count += 1; + } + ( + ChildMode::Host(parent_host_pred), + GoalSource::ImplWhereBound | GoalSource::AliasBoundConstCondition, + ) => { + obligation = make_obligation(derive_host_cause( + tcx, + candidate.kind(), + self.obligation.cause.clone(), + impl_where_bound_count, + parent_host_pred, + )); + impl_where_bound_count += 1; + } + // Skip over a higher-ranked predicate. + (_, GoalSource::InstantiateHigherRanked) => { + obligation = self.obligation.clone(); + } + (ChildMode::PassThrough, _) + | (_, GoalSource::AliasWellFormed | GoalSource::AliasBoundConstCondition) => { + obligation = make_obligation(self.obligation.cause.clone()); + } + } + + // Skip nested goals that aren't the *reason* for our goal's failure. + match (self.consider_ambiguities, nested_goal.result()) { + (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) | (false, Err(_)) => {} + _ => continue, + } + + self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?; + } + + // alias-relate may fail because the lhs or rhs can't be normalized, + // and therefore is treated as rigid. + if let Some(ty::PredicateKind::AliasRelate(lhs, rhs, _)) = pred_kind.no_bound_vars() { + if let Some(obligation) = goal + .infcx() + .visit_proof_tree_at_depth( + goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(lhs.into())), + goal.depth() + 1, + self, + ) + .break_value() + { + return ControlFlow::Break(obligation); + } else if let Some(obligation) = goal + .infcx() + .visit_proof_tree_at_depth( + goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(rhs.into())), + goal.depth() + 1, + self, + ) + .break_value() + { + return ControlFlow::Break(obligation); + } + } + + ControlFlow::Break(self.obligation.clone()) + } +} + +#[derive(Debug, Copy, Clone)] +enum ChildMode<'tcx> { + // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`, + // and skip all `GoalSource::Misc`, which represent useless obligations + // such as alias-eq which may not hold. + Trait(ty::PolyTraitPredicate<'tcx>), + // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`, + // and skip all `GoalSource::Misc`, which represent useless obligations + // such as alias-eq which may not hold. + Host(ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>), + // Skip trying to derive an `ObligationCause` from this obligation, and + // report *all* sub-obligations as if they came directly from the parent + // obligation. + PassThrough, +} + +fn derive_cause<'tcx>( + tcx: TyCtxt<'tcx>, + candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>, + mut cause: ObligationCause<'tcx>, + idx: usize, + parent_trait_pred: ty::PolyTraitPredicate<'tcx>, +) -> ObligationCause<'tcx> { + match candidate_kind { + inspect::ProbeKind::TraitCandidate { + source: CandidateSource::Impl(impl_def_id), + result: _, + } => { + if let Some((_, span)) = + tcx.predicates_of(impl_def_id).instantiate_identity(tcx).iter().nth(idx) + { + cause = cause.derived_cause(parent_trait_pred, |derived| { + ObligationCauseCode::ImplDerived(Box::new(traits::ImplDerivedCause { + derived, + impl_or_alias_def_id: impl_def_id, + impl_def_predicate_index: Some(idx), + span, + })) + }) + } + } + inspect::ProbeKind::TraitCandidate { + source: CandidateSource::BuiltinImpl(..), + result: _, + } => { + cause = cause.derived_cause(parent_trait_pred, ObligationCauseCode::BuiltinDerived); + } + _ => {} + }; + cause +} + +fn derive_host_cause<'tcx>( + tcx: TyCtxt<'tcx>, + candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>, + mut cause: ObligationCause<'tcx>, + idx: usize, + parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>, +) -> ObligationCause<'tcx> { + match candidate_kind { + inspect::ProbeKind::TraitCandidate { + source: CandidateSource::Impl(impl_def_id), + result: _, + } => { + if let Some((_, span)) = tcx + .predicates_of(impl_def_id) + .instantiate_identity(tcx) + .into_iter() + .chain(tcx.const_conditions(impl_def_id).instantiate_identity(tcx).into_iter().map( + |(trait_ref, span)| { + ( + trait_ref.to_host_effect_clause( + tcx, + parent_host_pred.skip_binder().constness, + ), + span, + ) + }, + )) + .nth(idx) + { + cause = + cause.derived_host_cause(parent_host_pred, |derived| { + ObligationCauseCode::ImplDerivedHost(Box::new( + traits::ImplDerivedHostCause { derived, impl_def_id, span }, + )) + }) + } + } + inspect::ProbeKind::TraitCandidate { + source: CandidateSource::BuiltinImpl(..), + result: _, + } => { + cause = + cause.derived_host_cause(parent_host_pred, ObligationCauseCode::BuiltinDerivedHost); + } + _ => {} + }; + cause +} diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index e735020a63e..9ba48cd588f 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -194,47 +194,57 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { let goals = instantiated_goals .into_iter() - .map(|(source, goal)| match goal.predicate.kind().no_bound_vars() { - Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => { - let unconstrained_term = match term.unpack() { - ty::TermKind::Ty(_) => infcx.next_ty_var(span).into(), - ty::TermKind::Const(_) => infcx.next_const_var(span).into(), - }; - let goal = - goal.with(infcx.tcx, ty::NormalizesTo { alias, term: unconstrained_term }); - // We have to use a `probe` here as evaluating a `NormalizesTo` can constrain the - // expected term. This means that candidates which only fail due to nested goals - // and which normalize to a different term then the final result could ICE: when - // building their proof tree, the expected term was unconstrained, but when - // instantiating the candidate it is already constrained to the result of another - // candidate. - let proof_tree = infcx - .probe(|_| infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes).1); - InspectGoal::new( - infcx, - self.goal.depth + 1, - proof_tree.unwrap(), - Some(NormalizesToTermHack { term, unconstrained_term }), - source, - ) - } - _ => { - // We're using a probe here as evaluating a goal could constrain - // inference variables by choosing one candidate. If we then recurse - // into another candidate who ends up with different inference - // constraints, we get an ICE if we already applied the constraints - // from the chosen candidate. - let proof_tree = infcx - .probe(|_| infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1) - .unwrap(); - InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source) - } - }) + .map(|(source, goal)| self.instantiate_proof_tree_for_nested_goal(source, goal, span)) .collect(); (goals, opt_impl_args) } + pub fn instantiate_proof_tree_for_nested_goal( + &self, + source: GoalSource, + goal: Goal<'tcx, ty::Predicate<'tcx>>, + span: Span, + ) -> InspectGoal<'a, 'tcx> { + let infcx = self.goal.infcx; + match goal.predicate.kind().no_bound_vars() { + Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => { + let unconstrained_term = match term.unpack() { + ty::TermKind::Ty(_) => infcx.next_ty_var(span).into(), + ty::TermKind::Const(_) => infcx.next_const_var(span).into(), + }; + let goal = + goal.with(infcx.tcx, ty::NormalizesTo { alias, term: unconstrained_term }); + // We have to use a `probe` here as evaluating a `NormalizesTo` can constrain the + // expected term. This means that candidates which only fail due to nested goals + // and which normalize to a different term then the final result could ICE: when + // building their proof tree, the expected term was unconstrained, but when + // instantiating the candidate it is already constrained to the result of another + // candidate. + let proof_tree = + infcx.probe(|_| infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes).1); + InspectGoal::new( + infcx, + self.goal.depth + 1, + proof_tree.unwrap(), + Some(NormalizesToTermHack { term, unconstrained_term }), + source, + ) + } + _ => { + // We're using a probe here as evaluating a goal could constrain + // inference variables by choosing one candidate. If we then recurse + // into another candidate who ends up with different inference + // constraints, we get an ICE if we already applied the constraints + // from the chosen candidate. + let proof_tree = infcx + .probe(|_| infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1) + .unwrap(); + InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source) + } + } + } + /// Visit all nested goals of this candidate, rolling back /// all inference constraints. pub fn visit_nested_in_probe<V: ProofTreeVisitor<'tcx>>(&self, visitor: &mut V) -> V::Result { diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 446f9eaa348..bdee6ca2afe 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -35,7 +35,7 @@ pub fn is_const_evaluatable<'tcx>( ty::ConstKind::Param(_) | ty::ConstKind::Bound(_, _) | ty::ConstKind::Placeholder(_) - | ty::ConstKind::Value(_, _) + | ty::ConstKind::Value(_) | ty::ConstKind::Error(_) => return Ok(()), ty::ConstKind::Infer(_) => return Err(NotConstEvaluatable::MentionsInfer), }; diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 66491d9abe1..baa94ead9d4 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -64,7 +64,7 @@ fn is_dyn_compatible(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { } /// We say a method is *vtable safe* if it can be invoked on a trait -/// object. Note that object-safe traits can have some +/// object. Note that dyn-compatible traits can have some /// non-vtable-safe methods, so long as they require `Self: Sized` or /// otherwise ensure that they cannot be used when `Self = Trait`. pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::AssocItem) -> bool { @@ -421,7 +421,7 @@ fn virtual_call_violations_for_method<'tcx>( let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0)); // Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on. - // However, this is already considered object-safe. We allow it as a special case here. + // However, this is already considered dyn compatible. We allow it as a special case here. // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows // `Receiver: Unsize<Receiver[Self => dyn Trait]>`. if receiver_ty != tcx.types.self_param { @@ -631,7 +631,7 @@ fn object_ty_for_trait<'tcx>( /// - `self: Pin<Box<Self>>` requires `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<dyn Trait>>>`. /// /// The only case where the receiver is not dispatchable, but is still a valid receiver -/// type (just not object-safe), is when there is more than one level of pointer indirection. +/// type (just not dyn compatible), is when there is more than one level of pointer indirection. /// E.g., `self: &&Self`, `self: &Rc<Self>`, `self: Box<Box<Self>>`. In these cases, there /// is no way, or at least no inexpensive way, to coerce the receiver from the version where /// `Self = dyn Trait` to the version where `Self = T`, where `T` is the unknown erased type diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 7529ee128f5..f2d2dd2f3ce 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -479,7 +479,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::ConstKind::Error(_) => { return ProcessResult::Changed(PendingPredicateObligations::new()); } - ty::ConstKind::Value(ty, _) => ty, + ty::ConstKind::Value(cv) => cv.ty, ty::ConstKind::Unevaluated(uv) => { infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args) } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 6b5ebade6ae..d4a9664e282 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -76,6 +76,7 @@ use crate::infer::{InferCtxt, TyCtxtInferExt}; use crate::regions::InferCtxtRegionExt; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; +#[derive(Debug)] pub struct FulfillmentError<'tcx> { pub obligation: PredicateObligation<'tcx>, pub code: FulfillmentErrorCode<'tcx>, @@ -107,12 +108,6 @@ impl<'tcx> FulfillmentError<'tcx> { } } -impl<'tcx> Debug for FulfillmentError<'tcx> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "FulfillmentError({:?},{:?})", self.obligation, self.code) - } -} - #[derive(Clone)] pub enum FulfillmentErrorCode<'tcx> { /// Inherently impossible to fulfill; this trait is implemented if and only diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index 1339739ce7f..ec0b7903396 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -5,8 +5,8 @@ use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds; use rustc_middle::infer::canonical::CanonicalQueryResponse; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt}; -use rustc_span::Span; use rustc_span::def_id::CRATE_DEF_ID; +use rustc_span::{DUMMY_SP, Span}; use rustc_type_ir::outlives::{Component, push_outlives_components}; use smallvec::{SmallVec, smallvec}; use tracing::debug; @@ -92,7 +92,9 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( // From the full set of obligations, just filter down to the region relationships. for obligation in - wf::unnormalized_obligations(ocx.infcx, param_env, arg).into_iter().flatten() + wf::unnormalized_obligations(ocx.infcx, param_env, arg, DUMMY_SP, CRATE_DEF_ID) + .into_iter() + .flatten() { assert!(!obligation.has_escaping_bound_vars()); let Some(pred) = obligation.predicate.kind().no_bound_vars() else { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 6b6e0b32385..99ce1fd9fb4 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -962,7 +962,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Ok(EvaluatedToAmbig); } ty::ConstKind::Error(_) => return Ok(EvaluatedToOk), - ty::ConstKind::Value(ty, _) => ty, + ty::ConstKind::Value(cv) => cv.ty, ty::ConstKind::Unevaluated(uv) => { self.tcx().type_of(uv.def).instantiate(self.tcx(), uv.args) } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 401b41c796d..cb3e81f5477 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -575,7 +575,7 @@ fn report_conflicting_impls<'tcx>( match used_to_be_allowed { None => { let reported = if overlap.with_impl.is_local() - || tcx.ensure().orphan_check_impl(impl_def_id).is_ok() + || tcx.ensure_ok().orphan_check_impl(impl_def_id).is_ok() { let mut err = tcx.dcx().struct_span_err(impl_span, msg()); err.code(E0119); diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index c351cf5aaac..f39c611d19f 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -379,7 +379,7 @@ pub(crate) fn assoc_def( // Ensure that the impl is constrained, otherwise projection may give us // bad unconstrained infer vars. if let Some(impl_def_id) = impl_def_id.as_local() { - tcx.ensure().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?; + tcx.ensure_ok().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?; } let item = tcx.associated_item(impl_item_id); @@ -402,7 +402,7 @@ pub(crate) fn assoc_def( if assoc_item.item.container == ty::AssocItemContainer::Impl && let Some(impl_def_id) = assoc_item.item.container_id(tcx).as_local() { - tcx.ensure().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?; + tcx.ensure_ok().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?; } Ok(assoc_item) diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index c9fb2a757e1..d30363ec158 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -25,7 +25,7 @@ use tracing::debug; /// trait Bar {} /// trait Foo = Bar + Bar; /// -/// let not_object_safe: dyn Foo; // bad, two `Bar` principals. +/// let dyn_incompatible: dyn Foo; // bad, two `Bar` principals. /// ``` pub fn expand_trait_aliases<'tcx>( tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index b5bc8364c7b..000e6a765d3 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -2,26 +2,22 @@ use std::fmt::Debug; use std::ops::ControlFlow; use rustc_hir::def_id::DefId; -use rustc_infer::infer::at::ToTrace; -use rustc_infer::infer::{BoundRegionConversionTime, TyCtxtInferExt}; -use rustc_infer::traits::ObligationCause; use rustc_infer::traits::util::PredicateSet; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::{ self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, Upcast, VtblEntry, }; -use rustc_span::{DUMMY_SP, Span, sym}; +use rustc_span::DUMMY_SP; use smallvec::{SmallVec, smallvec}; use tracing::debug; -use crate::errors::DumpVTableEntries; -use crate::traits::{ObligationCtxt, impossible_predicates, is_vtable_safe_method}; +use crate::traits::{impossible_predicates, is_vtable_safe_method}; #[derive(Clone, Debug)] pub enum VtblSegment<'tcx> { MetadataDSA, - TraitOwnEntries { trait_ref: ty::PolyTraitRef<'tcx>, emit_vptr: bool }, + TraitOwnEntries { trait_ref: ty::TraitRef<'tcx>, emit_vptr: bool }, } /// Prepare the segments for a vtable @@ -29,7 +25,7 @@ pub enum VtblSegment<'tcx> { // about our `Self` type here. pub fn prepare_vtable_segments<'tcx, T>( tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_ref: ty::TraitRef<'tcx>, segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow<T>, ) -> Option<T> { prepare_vtable_segments_inner(tcx, trait_ref, segment_visitor).break_value() @@ -39,7 +35,7 @@ pub fn prepare_vtable_segments<'tcx, T>( /// such that we can use `?` in the body. fn prepare_vtable_segments_inner<'tcx, T>( tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_ref: ty::TraitRef<'tcx>, mut segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow<T>, ) -> ControlFlow<T> { // The following constraints holds for the final arrangement. @@ -92,7 +88,7 @@ fn prepare_vtable_segments_inner<'tcx, T>( let mut emit_vptr_on_new_entry = false; let mut visited = PredicateSet::new(tcx); let predicate = trait_ref.upcast(tcx); - let mut stack: SmallVec<[(ty::PolyTraitRef<'tcx>, _, _); 5]> = + let mut stack: SmallVec<[(ty::TraitRef<'tcx>, _, _); 5]> = smallvec![(trait_ref, emit_vptr_on_new_entry, maybe_iter(None))]; visited.insert(predicate); @@ -125,10 +121,18 @@ fn prepare_vtable_segments_inner<'tcx, T>( let &(inner_most_trait_ref, _, _) = stack.last().unwrap(); let mut direct_super_traits_iter = tcx - .explicit_super_predicates_of(inner_most_trait_ref.def_id()) + .explicit_super_predicates_of(inner_most_trait_ref.def_id) .iter_identity_copied() .filter_map(move |(pred, _)| { - pred.instantiate_supertrait(tcx, inner_most_trait_ref).as_trait_clause() + pred.instantiate_supertrait(tcx, ty::Binder::dummy(inner_most_trait_ref)) + .as_trait_clause() + }) + .map(move |pred| { + tcx.normalize_erasing_late_bound_regions( + ty::TypingEnv::fully_monomorphized(), + pred, + ) + .trait_ref }); // Find an unvisited supertrait @@ -136,16 +140,11 @@ fn prepare_vtable_segments_inner<'tcx, T>( .find(|&super_trait| visited.insert(super_trait.upcast(tcx))) { // Push it to the stack for the next iteration of 'diving_in to pick up - Some(unvisited_super_trait) => { - // We're throwing away potential constness of super traits here. - // FIXME: handle ~const super traits - let next_super_trait = unvisited_super_trait.map_bound(|t| t.trait_ref); - stack.push(( - next_super_trait, - emit_vptr_on_new_entry, - maybe_iter(Some(direct_super_traits_iter)), - )) - } + Some(next_super_trait) => stack.push(( + next_super_trait, + emit_vptr_on_new_entry, + maybe_iter(Some(direct_super_traits_iter)), + )), // There are no more unvisited direct super traits, dive-in finished None => break 'diving_in, @@ -154,8 +153,7 @@ fn prepare_vtable_segments_inner<'tcx, T>( // emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level. while let Some((inner_most_trait_ref, emit_vptr, mut siblings)) = stack.pop() { - let has_entries = - has_own_existential_vtable_entries(tcx, inner_most_trait_ref.def_id()); + let has_entries = has_own_existential_vtable_entries(tcx, inner_most_trait_ref.def_id); segment_visitor(VtblSegment::TraitOwnEntries { trait_ref: inner_most_trait_ref, @@ -169,11 +167,6 @@ fn prepare_vtable_segments_inner<'tcx, T>( if let Some(next_inner_most_trait_ref) = siblings.find(|&sibling| visited.insert(sibling.upcast(tcx))) { - // We're throwing away potential constness of super traits here. - // FIXME: handle ~const super traits - let next_inner_most_trait_ref = - next_inner_most_trait_ref.map_bound(|t| t.trait_ref); - stack.push((next_inner_most_trait_ref, emit_vptr_on_new_entry, siblings)); // just pushed a new trait onto the stack, so we need to go through its super traits @@ -192,15 +185,6 @@ fn maybe_iter<I: Iterator>(i: Option<I>) -> impl Iterator<Item = I::Item> { i.into_iter().flatten() } -fn dump_vtable_entries<'tcx>( - tcx: TyCtxt<'tcx>, - sp: Span, - trait_ref: ty::PolyTraitRef<'tcx>, - entries: &[VtblEntry<'tcx>], -) { - tcx.dcx().emit_err(DumpVTableEntries { span: sp, trait_ref, entries: format!("{entries:#?}") }); -} - fn has_own_existential_vtable_entries(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { own_existential_vtable_entries_iter(tcx, trait_def_id).next().is_some() } @@ -239,8 +223,15 @@ fn own_existential_vtable_entries_iter( /// that come from `trait_ref`, including its supertraits. fn vtable_entries<'tcx>( tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_ref: ty::TraitRef<'tcx>, ) -> &'tcx [VtblEntry<'tcx>] { + debug_assert!(!trait_ref.has_non_region_infer() && !trait_ref.has_non_region_param()); + debug_assert_eq!( + tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref), + trait_ref, + "vtable trait ref should be normalized" + ); + debug!("vtable_entries({:?})", trait_ref); let mut entries = vec![]; @@ -251,33 +242,26 @@ fn vtable_entries<'tcx>( entries.extend(TyCtxt::COMMON_VTABLE_ENTRIES); } VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { - let existential_trait_ref = trait_ref - .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)); + let existential_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref); // Lookup the shape of vtable for the trait. let own_existential_entries = - tcx.own_existential_vtable_entries(existential_trait_ref.def_id()); + tcx.own_existential_vtable_entries(existential_trait_ref.def_id); let own_entries = own_existential_entries.iter().copied().map(|def_id| { debug!("vtable_entries: trait_method={:?}", def_id); // The method may have some early-bound lifetimes; add regions for those. - let args = trait_ref.map_bound(|trait_ref| { + // FIXME: Is this normalize needed? + let args = tcx.normalize_erasing_regions( + ty::TypingEnv::fully_monomorphized(), GenericArgs::for_item(tcx, def_id, |param, _| match param.kind { GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { trait_ref.args[param.index as usize] } - }) - }); - - // The trait type may have higher-ranked lifetimes in it; - // erase them if they appear, so that we get the type - // at some particular call site. - let args = tcx.normalize_erasing_late_bound_regions( - ty::TypingEnv::fully_monomorphized(), - args, + }), ); // It's possible that the method relies on where-clauses that @@ -317,11 +301,6 @@ fn vtable_entries<'tcx>( let _ = prepare_vtable_segments(tcx, trait_ref, vtable_segment_callback); - if tcx.has_attr(trait_ref.def_id(), sym::rustc_dump_vtable) { - let sp = tcx.def_span(trait_ref.def_id()); - dump_vtable_entries(tcx, sp, trait_ref, &entries); - } - tcx.arena.alloc_from_iter(entries) } @@ -329,14 +308,20 @@ fn vtable_entries<'tcx>( // for `Supertrait`'s methods in the vtable of `Subtrait`. pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRef<'tcx>) -> usize { debug_assert!(!key.has_non_region_infer() && !key.has_non_region_param()); + debug_assert_eq!( + tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), key), + key, + "vtable trait ref should be normalized" + ); let ty::Dynamic(source, _, _) = *key.self_ty().kind() else { bug!(); }; - let source_principal = - source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self); + let source_principal = tcx.instantiate_bound_regions_with_erased( + source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self), + ); - let target_principal = ty::Binder::dummy(ty::ExistentialTraitRef::erase_self_ty(tcx, key)); + let target_principal = ty::ExistentialTraitRef::erase_self_ty(tcx, key); let vtable_segment_callback = { let mut vptr_offset = 0; @@ -346,17 +331,14 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len(); } VtblSegment::TraitOwnEntries { trait_ref: vtable_principal, emit_vptr } => { - if trait_refs_are_compatible( - tcx, - vtable_principal - .map_bound(|t| ty::ExistentialTraitRef::erase_self_ty(tcx, t)), - target_principal, - ) { + if ty::ExistentialTraitRef::erase_self_ty(tcx, vtable_principal) + == target_principal + { return ControlFlow::Break(vptr_offset); } vptr_offset += - tcx.own_existential_vtable_entries(vtable_principal.def_id()).len(); + tcx.own_existential_vtable_entries(vtable_principal.def_id).len(); if emit_vptr { vptr_offset += 1; @@ -382,20 +364,27 @@ pub(crate) fn supertrait_vtable_slot<'tcx>( ), ) -> Option<usize> { debug_assert!(!key.has_non_region_infer() && !key.has_non_region_param()); + debug_assert_eq!( + tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), key), + key, + "upcasting trait refs should be normalized" + ); + let (source, target) = key; // If the target principal is `None`, we can just return `None`. let ty::Dynamic(target, _, _) = *target.kind() else { bug!(); }; - let target_principal = target.principal()?; + let target_principal = tcx.instantiate_bound_regions_with_erased(target.principal()?); // Given that we have a target principal, it is a bug for there not to be a source principal. let ty::Dynamic(source, _, _) = *source.kind() else { bug!(); }; - let source_principal = - source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self); + let source_principal = tcx.instantiate_bound_regions_with_erased( + source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self), + ); let vtable_segment_callback = { let mut vptr_offset = 0; @@ -406,13 +395,10 @@ pub(crate) fn supertrait_vtable_slot<'tcx>( } VtblSegment::TraitOwnEntries { trait_ref: vtable_principal, emit_vptr } => { vptr_offset += - tcx.own_existential_vtable_entries(vtable_principal.def_id()).len(); - if trait_refs_are_compatible( - tcx, - vtable_principal - .map_bound(|t| ty::ExistentialTraitRef::erase_self_ty(tcx, t)), - target_principal, - ) { + tcx.own_existential_vtable_entries(vtable_principal.def_id).len(); + if ty::ExistentialTraitRef::erase_self_ty(tcx, vtable_principal) + == target_principal + { if emit_vptr { return ControlFlow::Break(Some(vptr_offset)); } else { @@ -432,41 +418,6 @@ pub(crate) fn supertrait_vtable_slot<'tcx>( prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap() } -fn trait_refs_are_compatible<'tcx>( - tcx: TyCtxt<'tcx>, - hr_vtable_principal: ty::PolyExistentialTraitRef<'tcx>, - hr_target_principal: ty::PolyExistentialTraitRef<'tcx>, -) -> bool { - if hr_vtable_principal.def_id() != hr_target_principal.def_id() { - return false; - } - - let (infcx, param_env) = - tcx.infer_ctxt().build_with_typing_env(ty::TypingEnv::fully_monomorphized()); - let ocx = ObligationCtxt::new(&infcx); - let hr_source_principal = - ocx.normalize(&ObligationCause::dummy(), param_env, hr_vtable_principal); - let hr_target_principal = - ocx.normalize(&ObligationCause::dummy(), param_env, hr_target_principal); - infcx.enter_forall(hr_target_principal, |target_principal| { - let source_principal = infcx.instantiate_binder_with_fresh_vars( - DUMMY_SP, - BoundRegionConversionTime::HigherRankedType, - hr_source_principal, - ); - let Ok(()) = ocx.eq_trace( - &ObligationCause::dummy(), - param_env, - ToTrace::to_trace(&ObligationCause::dummy(), hr_target_principal, hr_source_principal), - target_principal, - source_principal, - ) else { - return false; - }; - ocx.select_all_or_error().is_empty() - }) -} - pub(super) fn provide(providers: &mut Providers) { *providers = Providers { own_existential_vtable_entries, diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 20b675bcb76..96051ad0aa5 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -8,8 +8,8 @@ use rustc_middle::ty::{ self, GenericArg, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; -use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::Span; +use rustc_span::def_id::{DefId, LocalDefId}; use tracing::{debug, instrument, trace}; use crate::infer::InferCtxt; @@ -89,6 +89,8 @@ pub fn unnormalized_obligations<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, arg: GenericArg<'tcx>, + span: Span, + body_id: LocalDefId, ) -> Option<PredicateObligations<'tcx>> { debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg)); @@ -106,8 +108,8 @@ pub fn unnormalized_obligations<'tcx>( let mut wf = WfPredicates { infcx, param_env, - body_id: CRATE_DEF_ID, - span: DUMMY_SP, + body_id, + span, out: PredicateObligations::new(), recursion_depth: 0, item: None, @@ -828,8 +830,25 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> { // Let the visitor iterate into the argument/return // types appearing in the fn signature. } - ty::UnsafeBinder(_) => { - // FIXME(unsafe_binders): We should also recurse into the binder here. + ty::UnsafeBinder(ty) => { + // FIXME(unsafe_binders): For now, we have no way to express + // that a type must be `ManuallyDrop` OR `Copy` (or a pointer). + if !ty.has_escaping_bound_vars() { + self.out.push(traits::Obligation::new( + self.tcx(), + self.cause(ObligationCauseCode::Misc), + self.param_env, + ty.map_bound(|ty| { + ty::TraitRef::new( + self.tcx(), + self.tcx().require_lang_item(LangItem::Copy, Some(self.span)), + [ty], + ) + }), + )); + } + + // We recurse into the binder below. } ty::Dynamic(data, r, _) => { diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index ad86813c87e..a50cc8f5932 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -128,16 +128,16 @@ mod rustc { pub fn from_const<'tcx>( tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, - c: Const<'tcx>, + ct: Const<'tcx>, ) -> Option<Self> { use rustc_middle::ty::ScalarInt; use rustc_span::sym; - let Some((cv, ty)) = c.try_to_valtree() else { + let Some(cv) = ct.try_to_value() else { return None; }; - let adt_def = ty.ty_adt_def()?; + let adt_def = cv.ty.ty_adt_def()?; assert_eq!( tcx.require_lang_item(LangItem::TransmuteOpts, None), @@ -147,7 +147,7 @@ mod rustc { ); let variant = adt_def.non_enum_variant(); - let fields = match cv { + let fields = match cv.valtree { ValTree::Branch(branch) => branch, _ => { return Some(Self { diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 51a7c976f60..4038a1d68fa 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -22,16 +22,16 @@ fn destructure_const<'tcx>( tcx: TyCtxt<'tcx>, const_: ty::Const<'tcx>, ) -> ty::DestructuredConst<'tcx> { - let ty::ConstKind::Value(ct_ty, valtree) = const_.kind() else { + let ty::ConstKind::Value(cv) = const_.kind() else { bug!("cannot destructure constant {:?}", const_) }; - let branches = match valtree { + let branches = match cv.valtree { ty::ValTree::Branch(b) => b, _ => bug!("cannot destructure constant {:?}", const_), }; - let (fields, variant) = match ct_ty.kind() { + let (fields, variant) = match cv.ty.kind() { ty::Array(inner_ty, _) | ty::Slice(inner_ty) => { // construct the consts for the elements of the array/slice let field_consts = branches @@ -116,6 +116,11 @@ fn recurse_build<'tcx>( | &ExprKind::ValueTypeAscription { source, .. } => { recurse_build(tcx, body, source, root_span)? } + &ExprKind::PlaceUnwrapUnsafeBinder { .. } + | &ExprKind::ValueUnwrapUnsafeBinder { .. } + | &ExprKind::WrapUnsafeBinder { .. } => { + todo!("FIXME(unsafe_binders)") + } &ExprKind::Literal { lit, neg } => { let sp = node.span; tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) @@ -347,6 +352,9 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> { | thir::ExprKind::Adt(_) | thir::ExprKind::PlaceTypeAscription { .. } | thir::ExprKind::ValueTypeAscription { .. } + | thir::ExprKind::PlaceUnwrapUnsafeBinder { .. } + | thir::ExprKind::ValueUnwrapUnsafeBinder { .. } + | thir::ExprKind::WrapUnsafeBinder { .. } | thir::ExprKind::Closure(_) | thir::ExprKind::Literal { .. } | thir::ExprKind::NonHirLiteral { .. } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index d5e1937efaa..8c6e3c86bf5 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -225,7 +225,7 @@ fn resolve_associated_item<'tcx>( if trait_item_id != leaf_def.item.def_id && let Some(leaf_def_item) = leaf_def.item.def_id.as_local() { - tcx.ensure().compare_impl_item(leaf_def_item)?; + tcx.ensure_ok().compare_impl_item(leaf_def_item)?; } Some(ty::Instance::new(leaf_def.item.def_id, args)) diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index a04c7536118..2f258b23f2d 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -144,13 +144,13 @@ fn univariant_uninterned<'tcx>( cx.calc.univariant(fields, repr, kind).map_err(|err| map_error(cx, ty, err)) } -fn validate_const_with_value<'tcx>( +fn extract_const_value<'tcx>( const_: ty::Const<'tcx>, ty: Ty<'tcx>, cx: &LayoutCx<'tcx>, -) -> Result<ty::Const<'tcx>, &'tcx LayoutError<'tcx>> { +) -> Result<ty::Value<'tcx>, &'tcx LayoutError<'tcx>> { match const_.kind() { - ty::ConstKind::Value(..) => Ok(const_), + ty::ConstKind::Value(cv) => Ok(cv), ty::ConstKind::Error(guar) => { return Err(error(cx, LayoutError::ReferencesError(guar))); } @@ -209,13 +209,12 @@ fn layout_of_uncached<'tcx>( &mut layout.backend_repr { if let Some(start) = start { - scalar.valid_range_mut().start = - validate_const_with_value(start, ty, cx)? - .try_to_bits(tcx, cx.typing_env) - .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; + scalar.valid_range_mut().start = extract_const_value(start, ty, cx)? + .try_to_bits(tcx, cx.typing_env) + .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; } if let Some(end) = end { - let mut end = validate_const_with_value(end, ty, cx)? + let mut end = extract_const_value(end, ty, cx)? .try_to_bits(tcx, cx.typing_env) .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; if !include_end { @@ -348,9 +347,7 @@ fn layout_of_uncached<'tcx>( // Arrays and slices. ty::Array(element, count) => { - let count = validate_const_with_value(count, ty, cx)? - .to_valtree() - .0 + let count = extract_const_value(count, ty, cx)? .try_to_target_usize(tcx) .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index 03dfe547ced..aafc0907ae1 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -31,7 +31,7 @@ pub enum ConstKind<I: Interner> { Unevaluated(ty::UnevaluatedConst<I>), /// Used to hold computed value. - Value(I::Ty, I::ValueConst), + Value(I::ValueConst), /// A placeholder for a const which could not be computed; this is /// propagated to avoid useless error messages. @@ -52,7 +52,7 @@ impl<I: Interner> fmt::Debug for ConstKind<I> { Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var), Placeholder(placeholder) => write!(f, "{placeholder:?}"), Unevaluated(uv) => write!(f, "{uv:?}"), - Value(ty, valtree) => write!(f, "({valtree:?}: {ty:?})"), + Value(val) => write!(f, "{val:?}"), Error(_) => write!(f, "{{const error}}"), Expr(expr) => write!(f, "{expr:?}"), } diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs index 9b3ff14d507..9955e92b55a 100644 --- a/compiler/rustc_type_ir/src/fast_reject.rs +++ b/compiler/rustc_type_ir/src/fast_reject.rs @@ -483,8 +483,8 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_ }; match lhs.kind() { - ty::ConstKind::Value(_, lhs_val) => match rhs.kind() { - ty::ConstKind::Value(_, rhs_val) => lhs_val == rhs_val, + ty::ConstKind::Value(lhs_val) => match rhs.kind() { + ty::ConstKind::Value(rhs_val) => lhs_val.valtree() == rhs_val.valtree(), _ => false, }, diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index d337a1a8ad9..711e42ff055 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -73,7 +73,7 @@ type Never = std::convert::Infallible; /// which means in practice almost every foldable type needs to also be /// visitable. (However, there are some types that are visitable without being /// foldable.) -pub trait TypeFoldable<I: Interner>: TypeVisitable<I> { +pub trait TypeFoldable<I: Interner>: TypeVisitable<I> + Clone { /// The entry point for folding. To fold a value `t` with a folder `f` /// call: `t.try_fold_with(f)`. /// diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 872cf668018..4e6d645e6fa 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -286,6 +286,11 @@ pub trait Const<I: Interner<Const = Self>>: } } +pub trait ValueConst<I: Interner<ValueConst = Self>>: Copy + Debug + Hash + Eq { + fn ty(self) -> I::Ty; + fn valtree(self) -> I::ValTree; +} + pub trait ExprConst<I: Interner<ExprConst = Self>>: Copy + Debug + Hash + Eq + Relate<I> { fn args(self) -> I::GenericArgs; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 0c3b0758f0f..a6c72da0c56 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -112,8 +112,9 @@ pub trait Interner: type PlaceholderConst: PlaceholderLike; type ParamConst: Copy + Debug + Hash + Eq + ParamLike; type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>; - type ValueConst: Copy + Debug + Hash + Eq; + type ValueConst: ValueConst<Self>; type ExprConst: ExprConst<Self>; + type ValTree: Copy + Debug + Hash + Eq; // Kinds of regions type Region: Region<Self>; diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index e628b66d2f0..5b696ee5ed4 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -606,7 +606,9 @@ pub fn structurally_relate_consts<I: Interner, R: TypeRelation<I>>( true } (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2, - (ty::ConstKind::Value(_, a_val), ty::ConstKind::Value(_, b_val)) => a_val == b_val, + (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => { + a_val.valtree() == b_val.valtree() + } // While this is slightly incorrect, it shouldn't matter for `min_const_generics` // and is the better alternative to waiting until `generic_const_exprs` can diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 3213638afb2..0a074942170 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -59,7 +59,7 @@ use crate::{self as ty, Interner, TypeFlags}; /// /// To implement this conveniently, use the derive macro located in /// `rustc_macros`. -pub trait TypeVisitable<I: Interner>: fmt::Debug + Clone { +pub trait TypeVisitable<I: Interner>: fmt::Debug { /// The entry point for visiting. To visit a value `t` with a visitor `v` /// call: `t.visit_with(v)`. /// diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 8686169c15d..eec6cd8d49b 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -251,6 +251,7 @@ pub enum AssertMessage { ResumedAfterReturn(CoroutineKind), ResumedAfterPanic(CoroutineKind), MisalignedPointerDereference { required: Operand, found: Operand }, + NullPointerDereference, } impl AssertMessage { @@ -306,6 +307,7 @@ impl AssertMessage { AssertMessage::MisalignedPointerDereference { .. } => { Ok("misaligned pointer dereference") } + AssertMessage::NullPointerDereference => Ok("null pointer dereference occured"), } } } diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs index 81981bce202..6638f93e555 100644 --- a/compiler/stable_mir/src/mir/pretty.rs +++ b/compiler/stable_mir/src/mir/pretty.rs @@ -298,6 +298,9 @@ fn pretty_assert_message<W: Write>(writer: &mut W, msg: &AssertMessage) -> io::R "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\",{pretty_required}, {pretty_found}" ) } + AssertMessage::NullPointerDereference => { + write!(writer, "\"null pointer dereference occured.\"") + } AssertMessage::ResumedAfterReturn(_) | AssertMessage::ResumedAfterPanic(_) => { write!(writer, "{}", msg.description().unwrap()) } diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index 79efb83cebd..d985a98fcbf 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -426,7 +426,10 @@ pub trait MirVisitor { | AssertMessage::RemainderByZero(op) => { self.visit_operand(op, location); } - AssertMessage::ResumedAfterReturn(_) | AssertMessage::ResumedAfterPanic(_) => { //nothing to visit + AssertMessage::ResumedAfterReturn(_) + | AssertMessage::ResumedAfterPanic(_) + | AssertMessage::NullPointerDereference => { + //nothing to visit } AssertMessage::MisalignedPointerDereference { required, found } => { self.visit_operand(required, location); diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 0c9535dfaa6..b29f740ef0f 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -712,8 +712,8 @@ impl String { } } - /// Decode a UTF-16–encoded vector `v` into a `String`, returning [`Err`] - /// if `v` contains any invalid data. + /// Decode a native endian UTF-16–encoded vector `v` into a `String`, + /// returning [`Err`] if `v` contains any invalid data. /// /// # Examples /// @@ -745,8 +745,8 @@ impl String { Ok(ret) } - /// Decode a UTF-16–encoded slice `v` into a `String`, replacing - /// invalid data with [the replacement character (`U+FFFD`)][U+FFFD]. + /// Decode a native endian UTF-16–encoded slice `v` into a `String`, + /// replacing invalid data with [the replacement character (`U+FFFD`)][U+FFFD]. /// /// Unlike [`from_utf8_lossy`] which returns a [`Cow<'a, str>`], /// `from_utf16_lossy` returns a `String` since the UTF-16 to UTF-8 @@ -777,8 +777,8 @@ impl String { .collect() } - /// Decode a UTF-16LE–encoded vector `v` into a `String`, returning [`Err`] - /// if `v` contains any invalid data. + /// Decode a UTF-16LE–encoded vector `v` into a `String`, + /// returning [`Err`] if `v` contains any invalid data. /// /// # Examples /// @@ -852,8 +852,8 @@ impl String { } } - /// Decode a UTF-16BE–encoded vector `v` into a `String`, returning [`Err`] - /// if `v` contains any invalid data. + /// Decode a UTF-16BE–encoded vector `v` into a `String`, + /// returning [`Err`] if `v` contains any invalid data. /// /// # Examples /// diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index fb8a740aced..ccfdbf0eb70 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -92,7 +92,7 @@ impl char { #[stable(feature = "assoc_char_consts", since = "1.52.0")] pub const UNICODE_VERSION: (u8, u8, u8) = crate::unicode::UNICODE_VERSION; - /// Creates an iterator over the UTF-16 encoded code points in `iter`, + /// Creates an iterator over the native endian UTF-16 encoded code points in `iter`, /// returning unpaired surrogates as `Err`s. /// /// # Examples @@ -704,7 +704,7 @@ impl char { unsafe { from_utf8_unchecked_mut(encode_utf8_raw(self as u32, dst)) } } - /// Encodes this character as UTF-16 into the provided `u16` buffer, + /// Encodes this character as native endian UTF-16 into the provided `u16` buffer, /// and then returns the subslice of the buffer that contains the encoded character. /// /// # Panics @@ -1828,7 +1828,7 @@ pub const fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] { unsafe { slice::from_raw_parts_mut(dst.as_mut_ptr(), len) } } -/// Encodes a raw `u32` value as UTF-16 into the provided `u16` buffer, +/// Encodes a raw `u32` value as native endian UTF-16 into the provided `u16` buffer, /// and then returns the subslice of the buffer that contains the encoded character. /// /// Unlike `char::encode_utf16`, this method also handles codepoints in the surrogate range. diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 97974d195fe..594236cf1d9 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -973,6 +973,24 @@ pub trait Ord: Eq + PartialOrd<Self> { /// assert_eq!(1.max(2), 2); /// assert_eq!(2.max(2), 2); /// ``` + /// ``` + /// use std::cmp::Ordering; + /// + /// #[derive(Eq)] + /// struct Equal(&'static str); + /// + /// impl PartialEq for Equal { + /// fn eq(&self, other: &Self) -> bool { true } + /// } + /// impl PartialOrd for Equal { + /// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(Ordering::Equal) } + /// } + /// impl Ord for Equal { + /// fn cmp(&self, other: &Self) -> Ordering { Ordering::Equal } + /// } + /// + /// assert_eq!(Equal("self").max(Equal("other")).0, "other"); + /// ``` #[stable(feature = "ord_max_min", since = "1.21.0")] #[inline] #[must_use] @@ -981,7 +999,7 @@ pub trait Ord: Eq + PartialOrd<Self> { where Self: Sized, { - max_by(self, other, Ord::cmp) + if other < self { self } else { other } } /// Compares and returns the minimum of two values. @@ -994,6 +1012,24 @@ pub trait Ord: Eq + PartialOrd<Self> { /// assert_eq!(1.min(2), 1); /// assert_eq!(2.min(2), 2); /// ``` + /// ``` + /// use std::cmp::Ordering; + /// + /// #[derive(Eq)] + /// struct Equal(&'static str); + /// + /// impl PartialEq for Equal { + /// fn eq(&self, other: &Self) -> bool { true } + /// } + /// impl PartialOrd for Equal { + /// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(Ordering::Equal) } + /// } + /// impl Ord for Equal { + /// fn cmp(&self, other: &Self) -> Ordering { Ordering::Equal } + /// } + /// + /// assert_eq!(Equal("self").min(Equal("other")).0, "self"); + /// ``` #[stable(feature = "ord_max_min", since = "1.21.0")] #[inline] #[must_use] @@ -1002,7 +1038,7 @@ pub trait Ord: Eq + PartialOrd<Self> { where Self: Sized, { - min_by(self, other, Ord::cmp) + if other < self { other } else { self } } /// Restrict a value to a certain interval. @@ -1414,6 +1450,24 @@ pub macro PartialOrd($item:item) { /// assert_eq!(cmp::min(1, 2), 1); /// assert_eq!(cmp::min(2, 2), 2); /// ``` +/// ``` +/// use std::cmp::{self, Ordering}; +/// +/// #[derive(Eq)] +/// struct Equal(&'static str); +/// +/// impl PartialEq for Equal { +/// fn eq(&self, other: &Self) -> bool { true } +/// } +/// impl PartialOrd for Equal { +/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(Ordering::Equal) } +/// } +/// impl Ord for Equal { +/// fn cmp(&self, other: &Self) -> Ordering { Ordering::Equal } +/// } +/// +/// assert_eq!(cmp::min(Equal("v1"), Equal("v2")).0, "v1"); +/// ``` #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] @@ -1431,20 +1485,22 @@ pub fn min<T: Ord>(v1: T, v2: T) -> T { /// ``` /// use std::cmp; /// -/// let result = cmp::min_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())); -/// assert_eq!(result, 1); +/// let abs_cmp = |x: &i32, y: &i32| x.abs().cmp(&y.abs()); /// -/// let result = cmp::min_by(-2, 3, |x: &i32, y: &i32| x.abs().cmp(&y.abs())); -/// assert_eq!(result, -2); +/// let result = cmp::min_by(2, -1, abs_cmp); +/// assert_eq!(result, -1); +/// +/// let result = cmp::min_by(2, -3, abs_cmp); +/// assert_eq!(result, 2); +/// +/// let result = cmp::min_by(1, -1, abs_cmp); +/// assert_eq!(result, 1); /// ``` #[inline] #[must_use] #[stable(feature = "cmp_min_max_by", since = "1.53.0")] pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T { - match compare(&v1, &v2) { - Ordering::Less | Ordering::Equal => v1, - Ordering::Greater => v2, - } + if compare(&v2, &v1).is_lt() { v2 } else { v1 } } /// Returns the element that gives the minimum value from the specified function. @@ -1456,17 +1512,20 @@ pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T { /// ``` /// use std::cmp; /// -/// let result = cmp::min_by_key(-2, 1, |x: &i32| x.abs()); -/// assert_eq!(result, 1); +/// let result = cmp::min_by_key(2, -1, |x: &i32| x.abs()); +/// assert_eq!(result, -1); /// -/// let result = cmp::min_by_key(-2, 2, |x: &i32| x.abs()); -/// assert_eq!(result, -2); +/// let result = cmp::min_by_key(2, -3, |x: &i32| x.abs()); +/// assert_eq!(result, 2); +/// +/// let result = cmp::min_by_key(1, -1, |x: &i32| x.abs()); +/// assert_eq!(result, 1); /// ``` #[inline] #[must_use] #[stable(feature = "cmp_min_max_by", since = "1.53.0")] pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T { - min_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2))) + if f(&v2) < f(&v1) { v2 } else { v1 } } /// Compares and returns the maximum of two values. @@ -1483,6 +1542,24 @@ pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T { /// assert_eq!(cmp::max(1, 2), 2); /// assert_eq!(cmp::max(2, 2), 2); /// ``` +/// ``` +/// use std::cmp::{self, Ordering}; +/// +/// #[derive(Eq)] +/// struct Equal(&'static str); +/// +/// impl PartialEq for Equal { +/// fn eq(&self, other: &Self) -> bool { true } +/// } +/// impl PartialOrd for Equal { +/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(Ordering::Equal) } +/// } +/// impl Ord for Equal { +/// fn cmp(&self, other: &Self) -> Ordering { Ordering::Equal } +/// } +/// +/// assert_eq!(cmp::max(Equal("v1"), Equal("v2")).0, "v2"); +/// ``` #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] @@ -1500,20 +1577,22 @@ pub fn max<T: Ord>(v1: T, v2: T) -> T { /// ``` /// use std::cmp; /// -/// let result = cmp::max_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())); +/// let abs_cmp = |x: &i32, y: &i32| x.abs().cmp(&y.abs()); +/// +/// let result = cmp::max_by(3, -2, abs_cmp) ; +/// assert_eq!(result, 3); +/// +/// let result = cmp::max_by(1, -2, abs_cmp); /// assert_eq!(result, -2); /// -/// let result = cmp::max_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())) ; -/// assert_eq!(result, 2); +/// let result = cmp::max_by(1, -1, abs_cmp); +/// assert_eq!(result, -1); /// ``` #[inline] #[must_use] #[stable(feature = "cmp_min_max_by", since = "1.53.0")] pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T { - match compare(&v1, &v2) { - Ordering::Less | Ordering::Equal => v2, - Ordering::Greater => v1, - } + if compare(&v2, &v1).is_lt() { v1 } else { v2 } } /// Returns the element that gives the maximum value from the specified function. @@ -1525,17 +1604,20 @@ pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T { /// ``` /// use std::cmp; /// -/// let result = cmp::max_by_key(-2, 1, |x: &i32| x.abs()); +/// let result = cmp::max_by_key(3, -2, |x: &i32| x.abs()); +/// assert_eq!(result, 3); +/// +/// let result = cmp::max_by_key(1, -2, |x: &i32| x.abs()); /// assert_eq!(result, -2); /// -/// let result = cmp::max_by_key(-2, 2, |x: &i32| x.abs()); -/// assert_eq!(result, 2); +/// let result = cmp::max_by_key(1, -1, |x: &i32| x.abs()); +/// assert_eq!(result, -1); /// ``` #[inline] #[must_use] #[stable(feature = "cmp_min_max_by", since = "1.53.0")] pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T { - max_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2))) + if f(&v2) < f(&v1) { v1 } else { v2 } } /// Compares and sorts two values, returning minimum and maximum. @@ -1549,13 +1631,32 @@ pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T { /// use std::cmp; /// /// assert_eq!(cmp::minmax(1, 2), [1, 2]); -/// assert_eq!(cmp::minmax(2, 2), [2, 2]); +/// assert_eq!(cmp::minmax(2, 1), [1, 2]); /// /// // You can destructure the result using array patterns /// let [min, max] = cmp::minmax(42, 17); /// assert_eq!(min, 17); /// assert_eq!(max, 42); /// ``` +/// ``` +/// #![feature(cmp_minmax)] +/// use std::cmp::{self, Ordering}; +/// +/// #[derive(Eq)] +/// struct Equal(&'static str); +/// +/// impl PartialEq for Equal { +/// fn eq(&self, other: &Self) -> bool { true } +/// } +/// impl PartialOrd for Equal { +/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(Ordering::Equal) } +/// } +/// impl Ord for Equal { +/// fn cmp(&self, other: &Self) -> Ordering { Ordering::Equal } +/// } +/// +/// assert_eq!(cmp::minmax(Equal("v1"), Equal("v2")).map(|v| v.0), ["v1", "v2"]); +/// ``` #[inline] #[must_use] #[unstable(feature = "cmp_minmax", issue = "115939")] @@ -1563,7 +1664,7 @@ pub fn minmax<T>(v1: T, v2: T) -> [T; 2] where T: Ord, { - if v1 <= v2 { [v1, v2] } else { [v2, v1] } + if v2 < v1 { [v2, v1] } else { [v1, v2] } } /// Returns minimum and maximum values with respect to the specified comparison function. @@ -1576,11 +1677,14 @@ where /// #![feature(cmp_minmax)] /// use std::cmp; /// -/// assert_eq!(cmp::minmax_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), [1, -2]); -/// assert_eq!(cmp::minmax_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), [-2, 2]); +/// let abs_cmp = |x: &i32, y: &i32| x.abs().cmp(&y.abs()); +/// +/// assert_eq!(cmp::minmax_by(-2, 1, abs_cmp), [1, -2]); +/// assert_eq!(cmp::minmax_by(-1, 2, abs_cmp), [-1, 2]); +/// assert_eq!(cmp::minmax_by(-2, 2, abs_cmp), [-2, 2]); /// /// // You can destructure the result using array patterns -/// let [min, max] = cmp::minmax_by(-42, 17, |x: &i32, y: &i32| x.abs().cmp(&y.abs())); +/// let [min, max] = cmp::minmax_by(-42, 17, abs_cmp); /// assert_eq!(min, 17); /// assert_eq!(max, -42); /// ``` @@ -1591,7 +1695,7 @@ pub fn minmax_by<T, F>(v1: T, v2: T, compare: F) -> [T; 2] where F: FnOnce(&T, &T) -> Ordering, { - if compare(&v1, &v2).is_le() { [v1, v2] } else { [v2, v1] } + if compare(&v2, &v1).is_lt() { [v2, v1] } else { [v1, v2] } } /// Returns minimum and maximum values with respect to the specified key function. @@ -1620,7 +1724,7 @@ where F: FnMut(&T) -> K, K: Ord, { - minmax_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2))) + if f(&v2) < f(&v1) { [v2, v1] } else { [v1, v2] } } // Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 80f6e32b6b2..e5c1a64c12e 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -468,9 +468,11 @@ pub fn spin_loop() { /// // No assumptions can be made about either operand, so the multiplication is not optimized out. /// let y = black_box(5) * black_box(10); /// ``` +/// +/// During constant evaluation, `black_box` is treated as a no-op. #[inline] #[stable(feature = "bench_black_box", since = "1.66.0")] -#[rustc_const_unstable(feature = "const_black_box", issue = "none")] +#[rustc_const_stable(feature = "const_black_box", since = "CURRENT_RUSTC_VERSION")] pub const fn black_box<T>(dummy: T) -> T { crate::intrinsics::black_box(dummy) } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 41b2ffad668..bf07632d992 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -78,7 +78,11 @@ pub mod simd; use crate::sync::atomic::{self, AtomicBool, AtomicI32, AtomicIsize, AtomicU32, Ordering}; #[stable(feature = "drop_in_place", since = "1.8.0")] -#[rustc_allowed_through_unstable_modules] +#[cfg_attr(bootstrap, rustc_allowed_through_unstable_modules)] +#[cfg_attr( + not(bootstrap), + rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead" +)] #[deprecated(note = "no longer an intrinsic - use `ptr::drop_in_place` directly", since = "1.52.0")] #[inline] pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) { @@ -3725,6 +3729,7 @@ pub const unsafe fn compare_bytes(_left: *const u8, _right: *const u8, _bytes: u #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] +#[rustc_intrinsic_const_stable_indirect] pub const fn black_box<T>(_dummy: T) -> T { unimplemented!() } diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 01a3c9d2ada..3669051ce82 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1831,32 +1831,4 @@ pub(crate) mod builtin { pub macro deref($pat:pat) { builtin # deref($pat) } - - /// Derive macro for `rustc-serialize`. Should not be used in new code. - #[rustc_builtin_macro] - #[unstable( - feature = "rustc_encodable_decodable", - issue = "none", - soft, - reason = "derive macro for `rustc-serialize`; should not be used in new code" - )] - #[deprecated(since = "1.52.0", note = "rustc-serialize is deprecated and no longer supported")] - #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it. - pub macro RustcDecodable($item:item) { - /* compiler built-in */ - } - - /// Derive macro for `rustc-serialize`. Should not be used in new code. - #[rustc_builtin_macro] - #[unstable( - feature = "rustc_encodable_decodable", - issue = "none", - soft, - reason = "derive macro for `rustc-serialize`; should not be used in new code" - )] - #[deprecated(since = "1.52.0", note = "rustc-serialize is deprecated and no longer supported")] - #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it. - pub macro RustcEncodable($item:item) { - /* compiler built-in */ - } } diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index a793fc2aa2e..18ada14d101 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1091,7 +1091,195 @@ pub trait FnPtr: Copy + Clone { fn addr(self) -> *const (); } -/// Derive macro generating impls of traits related to smart pointers. +/// Derive macro that makes a smart pointer usable with trait objects. +/// +/// # What this macro does +/// +/// This macro is intended to be used with user-defined pointer types, and makes it possible to +/// perform coercions on the pointee of the user-defined pointer. There are two aspects to this: +/// +/// ## Unsizing coercions of the pointee +/// +/// By using the macro, the following example will compile: +/// ``` +/// #![feature(derive_coerce_pointee)] +/// use std::marker::CoercePointee; +/// use std::ops::Deref; +/// +/// #[derive(CoercePointee)] +/// #[repr(transparent)] +/// struct MySmartPointer<T: ?Sized>(Box<T>); +/// +/// impl<T: ?Sized> Deref for MySmartPointer<T> { +/// type Target = T; +/// fn deref(&self) -> &T { +/// &self.0 +/// } +/// } +/// +/// trait MyTrait {} +/// +/// impl MyTrait for i32 {} +/// +/// fn main() { +/// let ptr: MySmartPointer<i32> = MySmartPointer(Box::new(4)); +/// +/// // This coercion would be an error without the derive. +/// let ptr: MySmartPointer<dyn MyTrait> = ptr; +/// } +/// ``` +/// Without the `#[derive(CoercePointee)]` macro, this example would fail with the following error: +/// ```text +/// error[E0308]: mismatched types +/// --> src/main.rs:11:44 +/// | +/// 11 | let ptr: MySmartPointer<dyn MyTrait> = ptr; +/// | --------------------------- ^^^ expected `MySmartPointer<dyn MyTrait>`, found `MySmartPointer<i32>` +/// | | +/// | expected due to this +/// | +/// = note: expected struct `MySmartPointer<dyn MyTrait>` +/// found struct `MySmartPointer<i32>` +/// = help: `i32` implements `MyTrait` so you could box the found value and coerce it to the trait object `Box<dyn MyTrait>`, you will have to change the expected type as well +/// ``` +/// +/// ## Dyn compatibility +/// +/// This macro allows you to dispatch on the user-defined pointer type. That is, traits using the +/// type as a receiver are dyn-compatible. For example, this compiles: +/// +/// ``` +/// #![feature(arbitrary_self_types, derive_coerce_pointee)] +/// use std::marker::CoercePointee; +/// use std::ops::Deref; +/// +/// #[derive(CoercePointee)] +/// #[repr(transparent)] +/// struct MySmartPointer<T: ?Sized>(Box<T>); +/// +/// impl<T: ?Sized> Deref for MySmartPointer<T> { +/// type Target = T; +/// fn deref(&self) -> &T { +/// &self.0 +/// } +/// } +/// +/// // You can always define this trait. (as long as you have #![feature(arbitrary_self_types)]) +/// trait MyTrait { +/// fn func(self: MySmartPointer<Self>); +/// } +/// +/// // But using `dyn MyTrait` requires #[derive(CoercePointee)]. +/// fn call_func(value: MySmartPointer<dyn MyTrait>) { +/// value.func(); +/// } +/// ``` +/// If you remove the `#[derive(CoercePointee)]` annotation from the struct, then the above example +/// will fail with this error message: +/// ```text +/// error[E0038]: the trait `MyTrait` is not dyn compatible +/// --> src/lib.rs:21:36 +/// | +/// 17 | fn func(self: MySmartPointer<Self>); +/// | -------------------- help: consider changing method `func`'s `self` parameter to be `&self`: `&Self` +/// ... +/// 21 | fn call_func(value: MySmartPointer<dyn MyTrait>) { +/// | ^^^^^^^^^^^ `MyTrait` is not dyn compatible +/// | +/// note: for a trait to be dyn compatible it needs to allow building a vtable +/// for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> +/// --> src/lib.rs:17:19 +/// | +/// 16 | trait MyTrait { +/// | ------- this trait is not dyn compatible... +/// 17 | fn func(self: MySmartPointer<Self>); +/// | ^^^^^^^^^^^^^^^^^^^^ ...because method `func`'s `self` parameter cannot be dispatched on +/// ``` +/// +/// # Requirements for using the macro +/// +/// This macro can only be used if: +/// * The type is a `#[repr(transparent)]` struct. +/// * The type of its non-zero-sized field must either be a standard library pointer type +/// (reference, raw pointer, `NonNull`, `Box`, `Rc`, `Arc`, etc.) or another user-defined type +/// also using the `#[derive(CoercePointee)]` macro. +/// * Zero-sized fields must not mention any generic parameters unless the zero-sized field has +/// type [`PhantomData`]. +/// +/// ## Multiple type parameters +/// +/// If the type has multiple type parameters, then you must explicitly specify which one should be +/// used for dynamic dispatch. For example: +/// ``` +/// # #![feature(derive_coerce_pointee)] +/// # use std::marker::{CoercePointee, PhantomData}; +/// #[derive(CoercePointee)] +/// #[repr(transparent)] +/// struct MySmartPointer<#[pointee] T: ?Sized, U> { +/// ptr: Box<T>, +/// _phantom: PhantomData<U>, +/// } +/// ``` +/// Specifying `#[pointee]` when the struct has only one type parameter is allowed, but not required. +/// +/// # Examples +/// +/// A custom implementation of the `Rc` type: +/// ``` +/// #![feature(derive_coerce_pointee)] +/// use std::marker::CoercePointee; +/// use std::ops::Deref; +/// use std::ptr::NonNull; +/// +/// #[derive(CoercePointee)] +/// #[repr(transparent)] +/// pub struct Rc<T: ?Sized> { +/// inner: NonNull<RcInner<T>>, +/// } +/// +/// struct RcInner<T: ?Sized> { +/// refcount: usize, +/// value: T, +/// } +/// +/// impl<T: ?Sized> Deref for Rc<T> { +/// type Target = T; +/// fn deref(&self) -> &T { +/// let ptr = self.inner.as_ptr(); +/// unsafe { &(*ptr).value } +/// } +/// } +/// +/// impl<T> Rc<T> { +/// pub fn new(value: T) -> Self { +/// let inner = Box::new(RcInner { +/// refcount: 1, +/// value, +/// }); +/// Self { +/// inner: NonNull::from(Box::leak(inner)), +/// } +/// } +/// } +/// +/// impl<T: ?Sized> Clone for Rc<T> { +/// fn clone(&self) -> Self { +/// // A real implementation would handle overflow here. +/// unsafe { (*self.inner.as_ptr()).refcount += 1 }; +/// Self { inner: self.inner } +/// } +/// } +/// +/// impl<T: ?Sized> Drop for Rc<T> { +/// fn drop(&mut self) { +/// let ptr = self.inner.as_ptr(); +/// unsafe { (*ptr).refcount -= 1 }; +/// if unsafe { (*ptr).refcount } == 0 { +/// drop(unsafe { Box::from_raw(ptr) }); +/// } +/// } +/// } +/// ``` #[rustc_builtin_macro(CoercePointee, attributes(pointee))] #[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize)] #[unstable(feature = "derive_coerce_pointee", issue = "123430")] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index ac5307a671d..0d8c3ef906b 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -276,10 +276,9 @@ impl<T: Copy> Clone for MaybeUninit<T> { impl<T> fmt::Debug for MaybeUninit<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // NB: there is no `.pad_fmt` so we can't use a simpler `format_args!("MaybeUninit<{..}>"). - // This needs to be adjusted if `MaybeUninit` moves modules. let full_name = type_name::<Self>(); - let short_name = full_name.split_once("mem::maybe_uninit::").unwrap().1; - f.pad(short_name) + let prefix_len = full_name.find("MaybeUninit").unwrap(); + f.pad(&full_name[prefix_len..]) } } diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 8fb1588e60b..5e45974b3d4 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -670,7 +670,8 @@ impl f128 { /// If one of the arguments is NaN, then the other argument is returned. /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids maxNum's problems with associativity. - /// This also matches the behavior of libm’s fmax. + /// This also matches the behavior of libm’s fmax. In particular, if the inputs compare equal + /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. /// /// ``` /// #![feature(f128)] @@ -696,7 +697,8 @@ impl f128 { /// If one of the arguments is NaN, then the other argument is returned. /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids minNum's problems with associativity. - /// This also matches the behavior of libm’s fmin. + /// This also matches the behavior of libm’s fmin. In particular, if the inputs compare equal + /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. /// /// ``` /// #![feature(f128)] diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 8c2af74b8f8..e3176cd1688 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -662,7 +662,8 @@ impl f16 { /// If one of the arguments is NaN, then the other argument is returned. /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids maxNum's problems with associativity. - /// This also matches the behavior of libm’s fmax. + /// This also matches the behavior of libm’s fmax. In particular, if the inputs compare equal + /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. /// /// ``` /// #![feature(f16)] @@ -687,7 +688,8 @@ impl f16 { /// If one of the arguments is NaN, then the other argument is returned. /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids minNum's problems with associativity. - /// This also matches the behavior of libm’s fmin. + /// This also matches the behavior of libm’s fmin. In particular, if the inputs compare equal + /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. /// /// ``` /// #![feature(f16)] diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 817bedbd44f..4d42997369f 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -874,7 +874,8 @@ impl f32 { /// If one of the arguments is NaN, then the other argument is returned. /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids maxNum's problems with associativity. - /// This also matches the behavior of libm’s fmax. + /// This also matches the behavior of libm’s fmax. In particular, if the inputs compare equal + /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. /// /// ``` /// let x = 1.0f32; @@ -895,7 +896,8 @@ impl f32 { /// If one of the arguments is NaN, then the other argument is returned. /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids minNum's problems with associativity. - /// This also matches the behavior of libm’s fmin. + /// This also matches the behavior of libm’s fmin. In particular, if the inputs compare equal + /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. /// /// ``` /// let x = 1.0f32; diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 1b0651a0def..907971d303f 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -892,7 +892,8 @@ impl f64 { /// If one of the arguments is NaN, then the other argument is returned. /// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids maxNum's problems with associativity. - /// This also matches the behavior of libm’s fmax. + /// This also matches the behavior of libm’s fmax. In particular, if the inputs compare equal + /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. /// /// ``` /// let x = 1.0_f64; @@ -913,7 +914,8 @@ impl f64 { /// If one of the arguments is NaN, then the other argument is returned. /// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs; /// this function handles all NaNs the same way and avoids minNum's problems with associativity. - /// This also matches the behavior of libm’s fmin. + /// This also matches the behavior of libm’s fmin. In particular, if the inputs compare equal + /// (such as for the case of `+0.0` and `-0.0`), either input may be returned non-deterministically. /// /// ``` /// let x = 1.0_f64; diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 53e2b238bae..a89de12c02b 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -291,6 +291,22 @@ fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! { ) } +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] +#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[track_caller] +#[cfg_attr(not(bootstrap), lang = "panic_null_pointer_dereference")] // needed by codegen for panic on null pointer deref +#[rustc_nounwind] // `CheckNull` MIR pass requires this function to never unwind +fn panic_null_pointer_dereference() -> ! { + if cfg!(feature = "panic_immediate_abort") { + super::intrinsics::abort() + } + + panic_nounwind_fmt( + format_args!("null pointer dereference occured"), + /* force_no_backtrace */ false, + ) +} + /// Panics because we cannot unwind out of a function. /// /// This is a separate function to avoid the codesize impact of each crate containing the string to diff --git a/library/core/src/prelude/common.rs b/library/core/src/prelude/common.rs index e38ef1e147c..8b116cecb52 100644 --- a/library/core/src/prelude/common.rs +++ b/library/core/src/prelude/common.rs @@ -12,6 +12,9 @@ pub use crate::marker::{Copy, Send, Sized, Sync, Unpin}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use crate::ops::{Drop, Fn, FnMut, FnOnce}; +#[stable(feature = "async_closure", since = "1.85.0")] +#[doc(no_inline)] +pub use crate::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce}; // Re-exported functions #[stable(feature = "core_prelude", since = "1.4.0")] diff --git a/library/core/src/prelude/mod.rs b/library/core/src/prelude/mod.rs index d3fda1cd273..0ab97f5bbd5 100644 --- a/library/core/src/prelude/mod.rs +++ b/library/core/src/prelude/mod.rs @@ -18,16 +18,6 @@ mod common; pub mod v1 { #[stable(feature = "rust1", since = "1.0.0")] pub use super::common::*; - - // Do not `doc(inline)` these `doc(hidden)` items. - #[unstable( - feature = "rustc_encodable_decodable", - issue = "none", - soft, - reason = "derive macro for `rustc-serialize`; should not be used in new code" - )] - #[allow(deprecated)] - pub use crate::macros::builtin::{RustcDecodable, RustcEncodable}; } /// The 2015 version of the core prelude. diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index c5f029363e5..bbf5939fe1b 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1160,9 +1160,9 @@ impl<T> (T,) {} /// /// Note that most common platforms will not support `f16` in hardware without enabling extra target /// features, with the notable exception of Apple Silicon (also known as M1, M2, etc.) processors. -/// Hardware support on x86-64 requires the avx512fp16 feature, while RISC-V requires Zhf. -/// Usually the fallback implementation will be to use `f32` hardware if it exists, and convert -/// between `f16` and `f32` when performing math. +/// Hardware support on x86/x86-64 requires the avx512fp16 or avx10.1 features, while RISC-V requires +/// Zfh, and Arm/AArch64 requires FEAT_FP16. Usually the fallback implementation will be to use `f32` +/// hardware if it exists, and convert between `f16` and `f32` when performing math. /// /// *[See also the `std::f16::consts` module](crate::f16::consts).* /// @@ -1344,10 +1344,10 @@ mod prim_f64 {} /// quad-precision values][wikipedia] for more information. /// /// Note that no platforms have hardware support for `f128` without enabling target specific features, -/// as for all instruction set architectures `f128` is considered an optional feature. -/// Only Power ISA ("PowerPC") and RISC-V specify it, and only certain microarchitectures -/// actually implement it. For x86-64 and AArch64, ISA support is not even specified, -/// so it will always be a software implementation significantly slower than `f64`. +/// as for all instruction set architectures `f128` is considered an optional feature. Only Power ISA +/// ("PowerPC") and RISC-V (via the Q extension) specify it, and only certain microarchitectures +/// actually implement it. For x86-64 and AArch64, ISA support is not even specified, so it will always +/// be a software implementation significantly slower than `f64`. /// /// _Note: `f128` support is incomplete. Many platforms will not be able to link math functions. On /// x86 in particular, these functions do link but their results are always incorrect._ diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index ec569291853..0c6eaf60d04 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1681,7 +1681,7 @@ impl<T, const N: usize> *const [T; N] { } } -// Equality for pointers +/// Pointer equality is by address, as produced by the [`<*const T>::addr`](pointer::addr) method. #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized> PartialEq for *const T { #[inline] @@ -1691,10 +1691,11 @@ impl<T: ?Sized> PartialEq for *const T { } } +/// Pointer equality is an equivalence relation. #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized> Eq for *const T {} -// Comparison for pointers +/// Pointer comparison is by address, as produced by the `[`<*const T>::addr`](pointer::addr)` method. #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized> Ord for *const T { #[inline] @@ -1710,6 +1711,7 @@ impl<T: ?Sized> Ord for *const T { } } +/// Pointer comparison is by address, as produced by the `[`<*const T>::addr`](pointer::addr)` method. #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized> PartialOrd for *const T { #[inline] diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 5d9d337f101..d1b0104c0fa 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -2097,7 +2097,7 @@ impl<T, const N: usize> *mut [T; N] { } } -// Equality for pointers +/// Pointer equality is by address, as produced by the [`<*mut T>::addr`](pointer::addr) method. #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized> PartialEq for *mut T { #[inline(always)] @@ -2107,9 +2107,11 @@ impl<T: ?Sized> PartialEq for *mut T { } } +/// Pointer equality is an equivalence relation. #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized> Eq for *mut T {} +/// Pointer comparison is by address, as produced by the [`<*mut T>::addr`](pointer::addr) method. #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized> Ord for *mut T { #[inline] @@ -2125,6 +2127,7 @@ impl<T: ?Sized> Ord for *mut T { } } +/// Pointer comparison is by address, as produced by the [`<*mut T>::addr`](pointer::addr) method. #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized> PartialOrd for *mut T { #[inline(always)] diff --git a/library/core/src/slice/sort/stable/drift.rs b/library/core/src/slice/sort/stable/drift.rs index 644e75a4581..cf1df1e91a5 100644 --- a/library/core/src/slice/sort/stable/drift.rs +++ b/library/core/src/slice/sort/stable/drift.rs @@ -10,8 +10,8 @@ use crate::{cmp, intrinsics}; /// 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. +/// worst-case complexity. `scratch.len()` must be at least +/// `max(v.len() - v.len() / 2, SMALL_SORT_GENERAL_SCRATCH_LEN)` otherwise the implementation may abort. /// Fully ascending and descending inputs will be sorted with exactly N - 1 /// comparisons. /// diff --git a/library/core/src/slice/sort/stable/mod.rs b/library/core/src/slice/sort/stable/mod.rs index 7adcc83b818..3ff2e71fd05 100644 --- a/library/core/src/slice/sort/stable/mod.rs +++ b/library/core/src/slice/sort/stable/mod.rs @@ -41,6 +41,8 @@ pub fn sort<T, F: FnMut(&T, &T) -> bool, BufT: BufGuard<T>>(v: &mut [T], is_less cfg_if! { if #[cfg(any(feature = "optimize_for_size", target_pointer_width = "16"))] { + // Unlike driftsort, mergesort only requires len / 2, + // not len - len / 2. let alloc_len = len / 2; cfg_if! { @@ -91,16 +93,26 @@ fn driftsort_main<T, F: FnMut(&T, &T) -> bool, BufT: BufGuard<T>>(v: &mut [T], i // 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 + // reduce our memory usage to n - n / 2 for large inputs. We do this by scaling + // our allocation as max(n - n / 2, min(n, 8MB)), ensuring we scale like n for + // small inputs and n - n / 2 for large inputs, without a sudden drop off. We + // also need to ensure our alloc >= SMALL_SORT_GENERAL_SCRATCH_LEN, as the // small-sort always needs this much memory. + // + // driftsort will produce unsorted runs of up to min_good_run_len, which + // is at most len - len / 2. + // Unsorted runs need to be processed by quicksort, which requires as much + // scratch space as the run length, therefore the scratch space must be at + // least len - len / 2. + // If min_good_run_len is ever modified, this code must be updated to allocate + // the correct scratch size for it. 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); + let alloc_len = cmp::max( + cmp::max(len - 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. diff --git a/library/core/src/slice/sort/stable/quicksort.rs b/library/core/src/slice/sort/stable/quicksort.rs index 0c8308bfce0..630c6ff9077 100644 --- a/library/core/src/slice/sort/stable/quicksort.rs +++ b/library/core/src/slice/sort/stable/quicksort.rs @@ -7,6 +7,8 @@ use crate::slice::sort::shared::smallsort::StableSmallSortTypeImpl; use crate::{intrinsics, ptr}; /// Sorts `v` recursively using quicksort. +/// `scratch.len()` must be at least `max(v.len() - v.len() / 2, SMALL_SORT_GENERAL_SCRATCH_LEN)` +/// otherwise the implementation may abort. /// /// `limit` when initialized with `c*log(v.len())` for some c ensures we do not /// overflow the stack or go quadratic. diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 8a473b398bb..39fa6c1a25f 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -1108,7 +1108,8 @@ impl str { LinesAny(self.lines()) } - /// Returns an iterator of `u16` over the string encoded as UTF-16. + /// Returns an iterator of `u16` over the string encoded + /// as native endian UTF-16 (without byte-order mark). /// /// # Examples /// diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 0061e33f986..73180bde54a 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -716,6 +716,12 @@ impl AtomicBool { /// AcqRel | AcqRel | Acquire /// SeqCst | SeqCst | SeqCst /// + /// `compare_and_swap` and `compare_exchange` also differ in their return type. You can use + /// `compare_exchange(...).unwrap_or_else(|x| x)` to recover the behavior of `compare_and_swap`, + /// but in most cases it is more idiomatic to check whether the return value is `Ok` or `Err` + /// rather than to infer success vs failure based on the value that was read. + /// + /// During migration, consider whether it makes sense to use `compare_exchange_weak` instead. /// `compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds, /// which allows the compiler to generate better assembly code when the compare and swap /// is used in a loop. @@ -1651,6 +1657,12 @@ impl<T> AtomicPtr<T> { /// AcqRel | AcqRel | Acquire /// SeqCst | SeqCst | SeqCst /// + /// `compare_and_swap` and `compare_exchange` also differ in their return type. You can use + /// `compare_exchange(...).unwrap_or_else(|x| x)` to recover the behavior of `compare_and_swap`, + /// but in most cases it is more idiomatic to check whether the return value is `Ok` or `Err` + /// rather than to infer success vs failure based on the value that was read. + /// + /// During migration, consider whether it makes sense to use `compare_exchange_weak` instead. /// `compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds, /// which allows the compiler to generate better assembly code when the compare and swap /// is used in a loop. @@ -2771,6 +2783,12 @@ macro_rules! atomic_int { /// AcqRel | AcqRel | Acquire /// SeqCst | SeqCst | SeqCst /// + /// `compare_and_swap` and `compare_exchange` also differ in their return type. You can use + /// `compare_exchange(...).unwrap_or_else(|x| x)` to recover the behavior of `compare_and_swap`, + /// but in most cases it is more idiomatic to check whether the return value is `Ok` or `Err` + /// rather than to infer success vs failure based on the value that was read. + /// + /// During migration, consider whether it makes sense to use `compare_exchange_weak` instead. /// `compare_exchange_weak` is allowed to fail spuriously even when the comparison succeeds, /// which allows the compiler to generate better assembly code when the compare and swap /// is used in a loop. diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 0607d508a48..7fe72862608 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -14,7 +14,6 @@ #![feature(bstr)] #![feature(cell_update)] #![feature(clone_to_uninit)] -#![feature(const_black_box)] #![feature(const_eval_select)] #![feature(const_swap_nonoverlapping)] #![feature(const_trait_impl)] diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 1f8aac48a9a..a5b0111adfb 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -629,9 +629,9 @@ impl File { /// This acquires an exclusive advisory lock; no other file handle to this file may acquire /// another lock. /// - /// If this file handle, or a clone of it, already holds an advisory lock the exact behavior is - /// unspecified and platform dependent, including the possibility that it will deadlock. - /// However, if this method returns, then an exclusive lock is held. + /// If this file handle/descriptor, or a clone of it, already holds an advisory lock the exact + /// behavior is unspecified and platform dependent, including the possibility that it will + /// deadlock. However, if this method returns, then an exclusive lock is held. /// /// If the file not open for writing, it is unspecified whether this function returns an error. /// @@ -639,6 +639,9 @@ impl File { /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`] /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. /// + /// The lock will be released when this file (along with any other file descriptors/handles + /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called. + /// /// # Platform-specific behavior /// /// This function currently corresponds to the `flock` function on Unix with the `LOCK_EX` flag, @@ -671,19 +674,22 @@ impl File { self.inner.lock() } - /// Acquire a shared advisory lock on the file. Blocks until the lock can be acquired. + /// Acquire a shared (non-exclusive) advisory lock on the file. Blocks until the lock can be acquired. /// /// This acquires a shared advisory lock; more than one file handle may hold a shared lock, but - /// none may hold an exclusive lock. + /// none may hold an exclusive lock at the same time. /// - /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is - /// unspecified and platform dependent, including the possibility that it will deadlock. - /// However, if this method returns, then a shared lock is held. + /// If this file handle/descriptor, or a clone of it, already holds an advisory lock, the exact + /// behavior is unspecified and platform dependent, including the possibility that it will + /// deadlock. However, if this method returns, then a shared lock is held. /// /// Note, this is an advisory lock meant to interact with [`lock`], [`try_lock`], /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`] /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. /// + /// The lock will be released when this file (along with any other file descriptors/handles + /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called. + /// /// # Platform-specific behavior /// /// This function currently corresponds to the `flock` function on Unix with the `LOCK_SH` flag, @@ -716,14 +722,18 @@ impl File { self.inner.lock_shared() } - /// Acquire an exclusive advisory lock on the file. Returns `Ok(false)` if the file is locked. + /// Try to acquire an exclusive advisory lock on the file. + /// + /// Returns `Ok(false)` if a different lock is already held on this file (via another + /// handle/descriptor). /// /// This acquires an exclusive advisory lock; no other file handle to this file may acquire /// another lock. /// - /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is - /// unspecified and platform dependent, including the possibility that it will deadlock. - /// However, if this method returns, then an exclusive lock is held. + /// If this file handle/descriptor, or a clone of it, already holds an advisory lock, the exact + /// behavior is unspecified and platform dependent, including the possibility that it will + /// deadlock. However, if this method returns `Ok(true)`, then it has acquired an exclusive + /// lock. /// /// If the file not open for writing, it is unspecified whether this function returns an error. /// @@ -731,6 +741,9 @@ impl File { /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`] /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. /// + /// The lock will be released when this file (along with any other file descriptors/handles + /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called. + /// /// # Platform-specific behavior /// /// This function currently corresponds to the `flock` function on Unix with the `LOCK_EX` and @@ -764,20 +777,25 @@ impl File { self.inner.try_lock() } - /// Acquire a shared advisory lock on the file. - /// Returns `Ok(false)` if the file is exclusively locked. + /// Try to acquire a shared (non-exclusive) advisory lock on the file. + /// + /// Returns `Ok(false)` if an exclusive lock is already held on this file (via another + /// handle/descriptor). /// /// This acquires a shared advisory lock; more than one file handle may hold a shared lock, but - /// none may hold an exclusive lock. + /// none may hold an exclusive lock at the same time. /// /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is /// unspecified and platform dependent, including the possibility that it will deadlock. - /// However, if this method returns, then a shared lock is held. + /// However, if this method returns `Ok(true)`, then it has acquired a shared lock. /// /// Note, this is an advisory lock meant to interact with [`lock`], [`try_lock`], /// [`try_lock`], and [`unlock`]. Its interactions with other methods, such as [`read`] /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block. /// + /// The lock will be released when this file (along with any other file descriptors/handles + /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called. + /// /// # Platform-specific behavior /// /// This function currently corresponds to the `flock` function on Unix with the `LOCK_SH` and @@ -813,7 +831,12 @@ impl File { /// Release all locks on the file. /// - /// All remaining locks are released when the file handle, and all clones of it, are dropped. + /// All locks are released when the file (along with any other file descriptors/handles + /// duplicated or inherited from it) is closed. This method allows releasing locks without + /// closing the file. + /// + /// If no lock is currently held via this file descriptor/handle, this method may return an + /// error, or may return successfully without taking any action. /// /// # Platform-specific behavior /// diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs index 4ec328208f0..14e6c2715df 100644 --- a/library/std/src/prelude/mod.rs +++ b/library/std/src/prelude/mod.rs @@ -120,16 +120,6 @@ mod common; pub mod v1 { #[stable(feature = "rust1", since = "1.0.0")] pub use super::common::*; - - // Do not `doc(inline)` these `doc(hidden)` items. - #[unstable( - feature = "rustc_encodable_decodable", - issue = "none", - soft, - reason = "derive macro for `rustc-serialize`; should not be used in new code" - )] - #[allow(deprecated)] - pub use core::prelude::v1::{RustcDecodable, RustcEncodable}; } /// The 2015 version of the prelude of The Rust Standard Library. diff --git a/library/std/src/process.rs b/library/std/src/process.rs index e0dd2e14817..fd0fd1cb755 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -2318,14 +2318,10 @@ pub fn exit(code: i32) -> ! { /// Terminates the process in an abnormal fashion. /// /// The function will never return and will immediately terminate the current -/// process in a platform specific "abnormal" manner. -/// -/// Note that because this function never returns, and that it terminates the -/// process, no destructors on the current stack or any other thread's stack -/// will be run. -/// -/// Rust IO buffers (eg, from `BufWriter`) will not be flushed. -/// Likewise, C stdio buffers will (on most platforms) not be flushed. +/// process in a platform specific "abnormal" manner. As a consequence, +/// no destructors on the current stack or any other thread's stack +/// will be run, Rust IO buffers (eg, from `BufWriter`) will not be flushed, +/// and C stdio buffers will (on most platforms) not be flushed. /// /// This is in contrast to the default behavior of [`panic!`] which unwinds /// the current thread's stack and calls all destructors. diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index 49f2dafd8fd..6fc0abbed9e 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -174,8 +174,6 @@ impl<T> OnceLock<T> { /// /// Waiting for a computation on another thread to finish: /// ```rust - /// #![feature(once_wait)] - /// /// use std::thread; /// use std::sync::OnceLock; /// @@ -189,7 +187,7 @@ impl<T> OnceLock<T> { /// }) /// ``` #[inline] - #[unstable(feature = "once_wait", issue = "127527")] + #[stable(feature = "once_wait", since = "CURRENT_RUSTC_VERSION")] pub fn wait(&self) -> &T { self.once.wait_force(); diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index 01ef71a187f..fb43ada6375 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -181,10 +181,29 @@ pub struct Mutex<T: ?Sized> { data: UnsafeCell<T>, } -// these are the only places where `T: Send` matters; all other -// functionality works fine on a single thread. +/// `T` must be `Send` for a [`Mutex`] to be `Send` because it is possible to acquire +/// the owned `T` from the `Mutex` via [`into_inner`]. +/// +/// [`into_inner`]: Mutex::into_inner #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<T: ?Sized + Send> Send for Mutex<T> {} + +/// `T` must be `Send` for [`Mutex`] to be `Sync`. +/// This ensures that the protected data can be accessed safely from multiple threads +/// without causing data races or other unsafe behavior. +/// +/// [`Mutex<T>`] provides mutable access to `T` to one thread at a time. However, it's essential +/// for `T` to be `Send` because it's not safe for non-`Send` structures to be accessed in +/// this manner. For instance, consider [`Rc`], a non-atomic reference counted smart pointer, +/// which is not `Send`. With `Rc`, we can have multiple copies pointing to the same heap +/// allocation with a non-atomic reference count. If we were to use `Mutex<Rc<_>>`, it would +/// only protect one instance of `Rc` from shared access, leaving other copies vulnerable +/// to potential data races. +/// +/// Also note that it is not necessary for `T` to be `Sync` as `&T` is only made available +/// to one thread at a time if `T` is not `Sync`. +/// +/// [`Rc`]: crate::rc::Rc #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {} @@ -211,8 +230,17 @@ pub struct MutexGuard<'a, T: ?Sized + 'a> { poison: poison::Guard, } +/// A [`MutexGuard`] is not `Send` to maximize platform portablity. +/// +/// On platforms that use POSIX threads (commonly referred to as pthreads) there is a requirement to +/// release mutex locks on the same thread they were acquired. +/// For this reason, [`MutexGuard`] must not implement `Send` to prevent it being dropped from +/// another thread. #[stable(feature = "rust1", since = "1.0.0")] impl<T: ?Sized> !Send for MutexGuard<'_, T> {} + +/// `T` must be `Sync` for a [`MutexGuard<T>`] to be `Sync` +/// because it is possible to get a `&T` from `&MutexGuard` (via `Deref`). #[stable(feature = "mutexguard", since = "1.19.0")] unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {} diff --git a/library/std/src/sync/poison/once.rs b/library/std/src/sync/poison/once.rs index 27db4b634fb..528b11ca0c1 100644 --- a/library/std/src/sync/poison/once.rs +++ b/library/std/src/sync/poison/once.rs @@ -269,8 +269,6 @@ impl Once { /// # Example /// /// ```rust - /// #![feature(once_wait)] - /// /// use std::sync::Once; /// use std::thread; /// @@ -289,7 +287,7 @@ impl Once { /// If this [`Once`] has been poisoned because an initialization closure has /// panicked, this method will also panic. Use [`wait_force`](Self::wait_force) /// if this behavior is not desired. - #[unstable(feature = "once_wait", issue = "127527")] + #[stable(feature = "once_wait", since = "CURRENT_RUSTC_VERSION")] pub fn wait(&self) { if !self.inner.is_completed() { self.inner.wait(false); @@ -298,7 +296,7 @@ impl Once { /// Blocks the current thread until initialization has completed, ignoring /// poisoning. - #[unstable(feature = "once_wait", issue = "127527")] + #[stable(feature = "once_wait", since = "CURRENT_RUSTC_VERSION")] pub fn wait_force(&self) { if !self.inner.is_completed() { self.inner.wait(true); diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index 7504a0f7ad7..dccc137d6f5 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -14,10 +14,12 @@ use r_efi::protocols::{device_path, device_path_to_text, shell}; use crate::ffi::{OsStr, OsString}; use crate::io::{self, const_error}; +use crate::marker::PhantomData; use crate::mem::{MaybeUninit, size_of}; use crate::os::uefi::env::boot_services; use crate::os::uefi::ffi::{OsStrExt, OsStringExt}; use crate::os::uefi::{self}; +use crate::path::Path; use crate::ptr::NonNull; use crate::slice; use crate::sync::atomic::{AtomicPtr, Ordering}; @@ -278,6 +280,10 @@ impl OwnedDevicePath { pub(crate) const fn as_ptr(&self) -> *mut r_efi::protocols::device_path::Protocol { self.0.as_ptr() } + + pub(crate) const fn borrow<'a>(&'a self) -> BorrowedDevicePath<'a> { + BorrowedDevicePath::new(self.0) + } } impl Drop for OwnedDevicePath { @@ -293,13 +299,37 @@ impl Drop for OwnedDevicePath { impl crate::fmt::Debug for OwnedDevicePath { fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { - match device_path_to_text(self.0) { + match self.borrow().to_text() { Ok(p) => p.fmt(f), Err(_) => f.debug_struct("OwnedDevicePath").finish_non_exhaustive(), } } } +pub(crate) struct BorrowedDevicePath<'a> { + protocol: NonNull<r_efi::protocols::device_path::Protocol>, + phantom: PhantomData<&'a r_efi::protocols::device_path::Protocol>, +} + +impl<'a> BorrowedDevicePath<'a> { + pub(crate) const fn new(protocol: NonNull<r_efi::protocols::device_path::Protocol>) -> Self { + Self { protocol, phantom: PhantomData } + } + + pub(crate) fn to_text(&self) -> io::Result<OsString> { + device_path_to_text(self.protocol) + } +} + +impl<'a> crate::fmt::Debug for BorrowedDevicePath<'a> { + fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { + match self.to_text() { + Ok(p) => p.fmt(f), + Err(_) => f.debug_struct("BorrowedDevicePath").finish_non_exhaustive(), + } + } +} + pub(crate) struct OwnedProtocol<T> { guid: r_efi::efi::Guid, handle: NonNull<crate::ffi::c_void>, @@ -452,3 +482,21 @@ pub(crate) fn open_shell() -> Option<NonNull<shell::Protocol>> { None } + +/// Get device path protocol associated with shell mapping. +/// +/// returns None in case no such mapping is exists +pub(crate) fn get_device_path_from_map(map: &Path) -> io::Result<BorrowedDevicePath<'static>> { + let shell = + open_shell().ok_or(io::const_error!(io::ErrorKind::NotFound, "UEFI Shell not found"))?; + let mut path = os_string_to_raw(map.as_os_str()) + .ok_or(io::const_error!(io::ErrorKind::InvalidFilename, "Invalid UEFI shell mapping"))?; + + // The Device Path Protocol pointer returned by UEFI shell is owned by the shell and is not + // freed throughout it's lifetime. So it has a 'static lifetime. + let protocol = unsafe { ((*shell.as_ptr()).get_device_path_from_map)(path.as_mut_ptr()) }; + let protocol = NonNull::new(protocol) + .ok_or(io::const_error!(io::ErrorKind::NotFound, "UEFI Shell mapping not found"))?; + + Ok(BorrowedDevicePath::new(protocol)) +} diff --git a/library/std/src/sys/path/mod.rs b/library/std/src/sys/path/mod.rs index 24a94ec7828..1fa4e80d678 100644 --- a/library/std/src/sys/path/mod.rs +++ b/library/std/src/sys/path/mod.rs @@ -5,12 +5,12 @@ cfg_if::cfg_if! { } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { mod sgx; pub use sgx::*; - } else if #[cfg(any( - target_os = "uefi", - target_os = "solid_asp3", - ))] { + } else if #[cfg(target_os = "solid_asp3")] { mod unsupported_backslash; pub use unsupported_backslash::*; + } else if #[cfg(target_os = "uefi")] { + mod uefi; + pub use uefi::*; } else { mod unix; pub use unix::*; diff --git a/library/std/src/sys/path/uefi.rs b/library/std/src/sys/path/uefi.rs new file mode 100644 index 00000000000..a3f4a3bfe1b --- /dev/null +++ b/library/std/src/sys/path/uefi.rs @@ -0,0 +1,105 @@ +#![forbid(unsafe_op_in_unsafe_fn)] +use crate::ffi::OsStr; +use crate::io; +use crate::path::{Path, PathBuf, Prefix}; +use crate::sys::{helpers, unsupported_err}; + +const FORWARD_SLASH: u8 = b'/'; +const COLON: u8 = b':'; + +#[inline] +pub fn is_sep_byte(b: u8) -> bool { + b == b'\\' +} + +#[inline] +pub fn is_verbatim_sep(b: u8) -> bool { + b == b'\\' +} + +pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> { + None +} + +pub const MAIN_SEP_STR: &str = "\\"; +pub const MAIN_SEP: char = '\\'; + +/// UEFI paths can be of 4 types: +/// +/// 1. Absolute Shell Path: Uses shell mappings (eg: `FS0:`). Does not exist if UEFI shell not present. +/// It can be identified with `:`. +/// Eg: FS0:\abc\run.efi +/// +/// 2. Absolute Device Path: this is what we want +/// It can be identified with `/`. +/// Eg: PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Slave,0x0)/\abc\run.efi +/// +/// 3: Relative root: path relative to the current volume. +/// It will start with `\`. +/// Eg: \abc\run.efi +/// +/// 4: Relative +/// Eg: run.efi +/// +/// The algorithm is mostly taken from edk2 UEFI shell implementation and is +/// somewhat simple. Check for the path type in order. +/// +/// The volume mapping in Absolute Shell Path (not the rest of the path) can be converted to Device +/// Path Protocol using `EFI_SHELL->GetDevicePathFromMap`. The rest of the path (Relative root +/// path), can just be appended to the remaining path. +/// +/// For Relative root, we get the current volume (either in Shell Mapping, or Device Path Protocol +/// form) and join it with the relative root path. We then recurse the function to resolve the Shell +/// Mapping if present. +/// +/// For Relative paths, we use the current working directory to construct +/// the new path and recurse the function to resolve the Shell mapping if present. +/// +/// Finally, at the end, we get the 2nd form, i.e. Absolute Device Path, which can be used in the +/// normal UEFI APIs such as file, process, etc. +/// Eg: PciRoot(0x0)/Pci(0x1,0x1)/Ata(Secondary,Slave,0x0)/\abc\run.efi +pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> { + // Absolute Shell Path + if path.as_os_str().as_encoded_bytes().contains(&COLON) { + let mut path_components = path.components(); + // Since path is not empty, it has at least one Component + let prefix = path_components.next().unwrap(); + + let dev_path = helpers::get_device_path_from_map(prefix.as_ref())?; + let mut dev_path_text = dev_path.to_text().map_err(|_| unsupported_err())?; + + // UEFI Shell does not seem to end device path with `/` + if *dev_path_text.as_encoded_bytes().last().unwrap() != FORWARD_SLASH { + dev_path_text.push("/"); + } + + let mut ans = PathBuf::from(dev_path_text); + ans.push(path_components); + + return Ok(ans); + } + + // Absolute Device Path + if path.as_os_str().as_encoded_bytes().contains(&FORWARD_SLASH) { + return Ok(path.to_path_buf()); + } + + // cur_dir() always returns something + let cur_dir = crate::env::current_dir().unwrap(); + let mut path_components = path.components(); + + // Relative Root + if path_components.next().unwrap() == crate::path::Component::RootDir { + let mut ans = PathBuf::new(); + ans.push(cur_dir.components().next().unwrap()); + ans.push(path_components); + return absolute(&ans); + } + + absolute(&cur_dir.join(path)) +} + +pub(crate) fn is_absolute(path: &Path) -> bool { + let temp = path.as_os_str().as_encoded_bytes(); + temp.contains(&COLON) || temp.contains(&FORWARD_SLASH) +} diff --git a/license-metadata.json b/license-metadata.json index 09cc3693565..4cf9bea2861 100644 --- a/license-metadata.json +++ b/license-metadata.json @@ -113,8 +113,12 @@ { "directories": [], "files": [ + "FiraMono-Medium.woff2", + "FiraMono-Regular.woff2", + "FiraSans-Italic.woff2", "FiraSans-LICENSE.txt", "FiraSans-Medium.woff2", + "FiraSans-MediumItalic.woff2", "FiraSans-Regular.woff2" ], "license": { @@ -266,4 +270,4 @@ ], "type": "root" } -} \ No newline at end of file +} diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index fd9bf47234c..f447d186a52 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1049,9 +1049,12 @@ pub fn rustc_cargo( // <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Internal.20lint.20for.20raw.20.60print!.60.20and.20.60println!.60.3F>. cargo.rustflag("-Zon-broken-pipe=kill"); - if builder.config.llvm_enzyme { - cargo.rustflag("-l").rustflag("Enzyme-19"); - } + // We temporarily disable linking here as part of some refactoring. + // This way, people can manually use -Z llvm-plugins and -C passes=enzyme for now. + // In a follow-up PR, we will re-enable linking here and load the pass for them. + //if builder.config.llvm_enzyme { + // cargo.rustflag("-l").rustflag("Enzyme-19"); + //} // Building with protected visibility reduces the number of dynamic relocations needed, giving // us a faster startup time. However GNU ld < 2.40 will error if we try to link a shared object diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 5e250d18ce6..825e5452f0e 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -86,6 +86,7 @@ impl Step for CrateBootstrap { SourceType::InTree, &[], ); + let crate_name = path.rsplit_once('/').unwrap().1; run_cargo_test(cargo, &[], &[], crate_name, crate_name, bootstrap_host, builder); } @@ -3106,6 +3107,8 @@ impl Step for Bootstrap { &[], ); + cargo.release_build(false); + cargo .rustflag("-Cdebuginfo=2") .env("CARGO_TARGET_DIR", builder.out.join("bootstrap")) diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 1b413dcb07e..f6a03a386d1 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -88,12 +88,14 @@ impl HostFlags { #[derive(Debug)] pub struct Cargo { command: BootstrapCommand, + args: Vec<OsString>, compiler: Compiler, target: TargetSelection, rustflags: Rustflags, rustdocflags: Rustflags, hostflags: HostFlags, allow_features: String, + release_build: bool, } impl Cargo { @@ -121,6 +123,10 @@ impl Cargo { cargo } + pub fn release_build(&mut self, release_build: bool) { + self.release_build = release_build; + } + pub fn compiler(&self) -> Compiler { self.compiler } @@ -153,7 +159,7 @@ impl Cargo { } pub fn arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Cargo { - self.command.arg(arg.as_ref()); + self.args.push(arg.as_ref().into()); self } @@ -342,6 +348,12 @@ impl Cargo { impl From<Cargo> for BootstrapCommand { fn from(mut cargo: Cargo) -> BootstrapCommand { + if cargo.release_build { + cargo.args.insert(0, "--release".into()); + } + + cargo.command.args(cargo.args); + let rustflags = &cargo.rustflags.0; if !rustflags.is_empty() { cargo.command.env("RUSTFLAGS", rustflags); @@ -360,6 +372,7 @@ impl From<Cargo> for BootstrapCommand { if !cargo.allow_features.is_empty() { cargo.command.env("RUSTC_ALLOW_FEATURES", cargo.allow_features); } + cargo.command } } @@ -429,13 +442,6 @@ impl Builder<'_> { assert_eq!(target, compiler.host); } - if self.config.rust_optimize.is_release() && - // cargo bench/install do not accept `--release` and miri doesn't want it - !matches!(cmd_kind, Kind::Bench | Kind::Install | Kind::Miri | Kind::MiriSetup | Kind::MiriTest) - { - cargo.arg("--release"); - } - // Remove make-related flags to ensure Cargo can correctly set things up cargo.env_remove("MAKEFLAGS"); cargo.env_remove("MFLAGS"); @@ -1218,14 +1224,20 @@ impl Builder<'_> { rustflags.arg("-Zmir_strip_debuginfo=locals-in-tiny-functions"); } + let release_build = self.config.rust_optimize.is_release() && + // cargo bench/install do not accept `--release` and miri doesn't want it + !matches!(cmd_kind, Kind::Bench | Kind::Install | Kind::Miri | Kind::MiriSetup | Kind::MiriTest); + Cargo { command: cargo, + args: vec![], compiler, target, rustflags, rustdocflags, hostflags, allow_features, + release_build, } } } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 98490118f7d..781d0e602c3 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -700,7 +700,7 @@ trait Merge { impl Merge for TomlConfig { fn merge( &mut self, - TomlConfig { build, install, llvm, rust, dist, target, profile: _, change_id }: Self, + TomlConfig { build, install, llvm, rust, dist, target, profile, change_id }: Self, replace: ReplaceOpt, ) { fn do_merge<T: Merge>(x: &mut Option<T>, y: Option<T>, replace: ReplaceOpt) { @@ -712,7 +712,10 @@ impl Merge for TomlConfig { } } } + self.change_id.inner.merge(change_id.inner, replace); + self.profile.merge(profile, replace); + do_merge(&mut self.build, build, replace); do_merge(&mut self.install, install, replace); do_merge(&mut self.llvm, llvm, replace); @@ -1505,6 +1508,10 @@ impl Config { build.cargo = build.cargo.take().or(std::env::var_os("CARGO").map(|p| p.into())); } + if GitInfo::new(false, &config.src).is_from_tarball() && toml.profile.is_none() { + toml.profile = Some("dist".into()); + } + if let Some(include) = &toml.profile { // Allows creating alias for profile names, allowing // profiles to be renamed while maintaining back compatibility diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh index 8776e0f0be9..3eb85ab215e 100755 --- a/src/ci/docker/scripts/rfl-build.sh +++ b/src/ci/docker/scripts/rfl-build.sh @@ -2,7 +2,7 @@ set -euo pipefail -LINUX_VERSION=v6.13-rc1 +LINUX_VERSION=50e57739141b41f731ab31f8380821c7969f9dc4 # Build rustc, rustdoc, cargo, clippy-driver and rustfmt ../x.py build --stage 2 library rustdoc clippy rustfmt @@ -28,7 +28,7 @@ rm -rf linux || true # Download Linux at a specific commit mkdir -p linux git -C linux init -git -C linux remote add origin https://github.com/Rust-for-Linux/linux.git +git -C linux remote add origin https://github.com/Darksonn/linux.git git -C linux fetch --depth 1 origin ${LINUX_VERSION} git -C linux checkout FETCH_HEAD diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index c6bc19f9e6c..58a9eb69666 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -5,7 +5,7 @@ runners: env: { } - &job-linux-4c - os: ubuntu-22.04 + os: ubuntu-24.04 # Free some disk space to avoid running out of space during the build. free_disk: true <<: *base-job @@ -43,10 +43,14 @@ runners: os: windows-2022-8core-32gb <<: *base-job + - &job-windows-25-8c + os: windows-2025-8core-32gb + <<: *base-job + - &job-aarch64-linux # Free some disk space to avoid running out of space during the build. free_disk: true - os: ubuntu-22.04-arm + os: ubuntu-24.04-arm - &job-aarch64-linux-8c os: ubuntu-22.04-arm64-8core-32gb @@ -521,18 +525,16 @@ auto: env: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu SCRIPT: make ci-mingw - # We are intentionally allowing an old toolchain on this builder (and that's - # incompatible with LLVM downloads today). + # There is no dist-i686-mingw-alt, so there is no prebuilt LLVM with assertions NO_DOWNLOAD_CI_LLVM: 1 - <<: *job-windows-8c + <<: *job-windows-25-8c # x86_64-mingw is split into two jobs to run tests in parallel. - name: x86_64-mingw-1 env: SCRIPT: make ci-mingw-x RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu - # We are intentionally allowing an old toolchain on this builder (and that's - # incompatible with LLVM downloads today). + # There is no dist-x86_64-mingw-alt, so there is no prebuilt LLVM with assertions NO_DOWNLOAD_CI_LLVM: 1 <<: *job-windows @@ -540,8 +542,7 @@ auto: env: SCRIPT: make ci-mingw-bootstrap RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu - # We are intentionally allowing an old toolchain on this builder (and that's - # incompatible with LLVM downloads today). + # There is no dist-x86_64-mingw-alt, so there is no prebuilt LLVM with assertions NO_DOWNLOAD_CI_LLVM: 1 <<: *job-windows @@ -557,7 +558,7 @@ auto: SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist windows-ci -- python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 CODEGEN_BACKENDS: llvm,cranelift - <<: *job-windows-8c + <<: *job-windows-25-8c - name: dist-i686-msvc env: @@ -589,9 +590,6 @@ auto: RUST_CONFIGURE_ARGS: >- --build=i686-pc-windows-gnu --enable-full-tools - # We are intentionally allowing an old toolchain on this builder (and that's - # incompatible with LLVM downloads today). - NO_DOWNLOAD_CI_LLVM: 1 SCRIPT: python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 CODEGEN_BACKENDS: llvm,cranelift @@ -603,9 +601,6 @@ auto: RUST_CONFIGURE_ARGS: >- --build=x86_64-pc-windows-gnu --enable-full-tools - # We are intentionally allowing an old toolchain on this builder (and that's - # incompatible with LLVM downloads today). - NO_DOWNLOAD_CI_LLVM: 1 DIST_REQUIRE_ALL_TOOLS: 1 CODEGEN_BACKENDS: llvm,cranelift <<: *job-windows diff --git a/src/ci/scripts/free-disk-space.sh b/src/ci/scripts/free-disk-space.sh index 4a7dad0090b..8850e168145 100755 --- a/src/ci/scripts/free-disk-space.sh +++ b/src/ci/scripts/free-disk-space.sh @@ -1,8 +1,19 @@ #!/bin/bash +set -euo pipefail # Free disk space on Linux GitHub action runners # Script inspired by https://github.com/jlumbroso/free-disk-space +isX86() { + local arch + arch=$(uname -m) + if [ "$arch" = "x86_64" ]; then + return 0 + else + return 1 + fi +} + # print a line of the specified character printSeparationLine() { for ((i = 0; i < 80; i++)); do @@ -14,11 +25,15 @@ printSeparationLine() { # compute available space # REF: https://unix.stackexchange.com/a/42049/60849 # REF: https://stackoverflow.com/a/450821/408734 -getAvailableSpace() { echo $(df -a | awk 'NR > 1 {avail+=$4} END {print avail}'); } +getAvailableSpace() { + df -a | awk 'NR > 1 {avail+=$4} END {print avail}' +} # make Kb human readable (assume the input is Kb) # REF: https://unix.stackexchange.com/a/44087/60849 -formatByteCount() { echo $(numfmt --to=iec-i --suffix=B --padding=7 $1'000'); } +formatByteCount() { + numfmt --to=iec-i --suffix=B --padding=7 "$1"'000' +} # macro to output saved space printSavedSpace() { @@ -58,11 +73,27 @@ removeDir() { dir=${1} local before - before=$(getAvailableSpace) + if [ ! -d "$dir" ]; then + echo "::warning::Directory $dir does not exist, skipping." + else + before=$(getAvailableSpace) + sudo rm -rf "$dir" + printSavedSpace "$before" "Removed $dir" + fi +} + +removeUnusedDirectories() { + local dirs_to_remove=( + "/usr/local/lib/android" + "/usr/share/dotnet" - sudo rm -rf "$dir" || true + # Haskell runtime + "/usr/local/.ghcup" + ) - printSavedSpace "$before" "$dir" + for dir in "${dirs_to_remove[@]}"; do + removeDir "$dir" + done } execAndMeasureSpaceChange() { @@ -79,21 +110,29 @@ execAndMeasureSpaceChange() { # Remove large packages # REF: https://github.com/apache/flink/blob/master/tools/azure-pipelines/free_disk_space.sh cleanPackages() { - sudo apt-get -qq remove -y --fix-missing \ - '^aspnetcore-.*' \ - '^dotnet-.*' \ - '^llvm-.*' \ - 'php.*' \ - '^mongodb-.*' \ - '^mysql-.*' \ - 'azure-cli' \ - 'google-chrome-stable' \ - 'firefox' \ - 'powershell' \ - 'mono-devel' \ - 'libgl1-mesa-dri' \ - 'google-cloud-sdk' \ - 'google-cloud-cli' + local packages=( + '^aspnetcore-.*' + '^dotnet-.*' + '^llvm-.*' + '^mongodb-.*' + '^mysql-.*' + 'azure-cli' + 'firefox' + 'libgl1-mesa-dri' + 'mono-devel' + 'php.*' + ) + + if isX86; then + packages+=( + 'google-chrome-stable' + 'google-cloud-cli' + 'google-cloud-sdk' + 'powershell' + ) + fi + + sudo apt-get -qq remove -y --fix-missing "${packages[@]}" sudo apt-get autoremove -y || echo "::warning::The command [sudo apt-get autoremove -y] failed" sudo apt-get clean || echo "::warning::The command [sudo apt-get clean] failed failed" @@ -101,9 +140,9 @@ cleanPackages() { # Remove Docker images cleanDocker() { - echo "Removing the following docker images:" + echo "=> Removing the following docker images:" sudo docker image ls - echo "Removing docker images..." + echo "=> Removing docker images..." sudo docker image prune --all --force || true } @@ -121,17 +160,12 @@ AVAILABLE_INITIAL=$(getAvailableSpace) printDF "BEFORE CLEAN-UP:" echo "" -removeDir /usr/local/lib/android -removeDir /usr/share/dotnet - -# Haskell runtime -removeDir /opt/ghc -removeDir /usr/local/.ghcup - -execAndMeasureSpaceChange cleanPackages "Large misc. packages" +execAndMeasureSpaceChange cleanPackages "Unused packages" execAndMeasureSpaceChange cleanDocker "Docker images" execAndMeasureSpaceChange cleanSwap "Swap storage" +removeUnusedDirectories + # Output saved space statistic echo "" printDF "AFTER CLEAN-UP:" diff --git a/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs b/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs index be37dd867b2..2355cb85ab3 100644 --- a/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs +++ b/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs @@ -10,6 +10,8 @@ extern crate rustc_interface; extern crate rustc_session; extern crate rustc_span; +use std::sync::{Arc, Mutex}; + use rustc_errors::emitter::Emitter; use rustc_errors::registry::{self, Registry}; use rustc_errors::translation::Translate; @@ -17,8 +19,6 @@ use rustc_errors::{DiagCtxt, DiagInner, FluentBundle}; use rustc_session::config; use rustc_span::source_map::SourceMap; -use std::sync::{Arc, Mutex}; - struct DebugEmitter { source_map: Arc<SourceMap>, diagnostics: Arc<Mutex<Vec<DiagInner>>>, @@ -67,10 +67,10 @@ fn main() { locale_resources: rustc_driver::DEFAULT_LOCALE_RESOURCES.to_owned(), lint_caps: rustc_hash::FxHashMap::default(), psess_created: Some(Box::new(|parse_sess| { - parse_sess.set_dcx(DiagCtxt::new(Box::new(DebugEmitter { + parse_sess.dcx().set_emitter(Box::new(DebugEmitter { source_map: parse_sess.clone_source_map(), diagnostics, - }))); + })); })), register_lints: None, override_queries: None, diff --git a/src/doc/rustc-dev-guide/src/building/new-target.md b/src/doc/rustc-dev-guide/src/building/new-target.md index 1d9fa1b52d5..cd215277e69 100644 --- a/src/doc/rustc-dev-guide/src/building/new-target.md +++ b/src/doc/rustc-dev-guide/src/building/new-target.md @@ -4,8 +4,13 @@ These are a set of steps to add support for a new target. There are numerous end states and paths to get there, so not all sections may be relevant to your desired goal. +See also the associated documentation in the +[target tier policy][target_tier_policy_add]. + <!-- toc --> +[target_tier_policy_add]: https://doc.rust-lang.org/rustc/target-tier-policy.html#adding-a-new-target + ## Specifying a new LLVM For very new targets, you may need to use a different fork of LLVM diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md index a2a6c8085df..e2097b26e5c 100644 --- a/src/doc/rustc-dev-guide/src/compiler-debugging.md +++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md @@ -275,7 +275,7 @@ Here are some notable ones: | `rustc_dump_def_parents` | Dumps the chain of `DefId` parents of certain definitions. | | `rustc_dump_item_bounds` | Dumps the [`item_bounds`] of an item. | | `rustc_dump_predicates` | Dumps the [`predicates_of`] an item. | -| `rustc_dump_vtable` | | +| `rustc_dump_vtable` | Dumps the vtable layout of an impl, or a type alias of a dyn type. | | `rustc_hidden_type_of_opaques` | Dumps the [hidden type of each opaque types][opaq] in the crate. | | `rustc_layout` | [See this section](#debugging-type-layouts). | | `rustc_object_lifetime_default` | Dumps the [object lifetime defaults] of an item. | diff --git a/src/doc/rustc-dev-guide/src/conventions.md b/src/doc/rustc-dev-guide/src/conventions.md index 4010e90821f..0e624a4566d 100644 --- a/src/doc/rustc-dev-guide/src/conventions.md +++ b/src/doc/rustc-dev-guide/src/conventions.md @@ -43,7 +43,7 @@ environment. ## Formatting and linting Python code -The Rust repository contains quite a lof of Python code. We try to keep +The Rust repository contains quite a lot of Python code. We try to keep it both linted and formatted by the [ruff][ruff] tool. When modifying Python code, use this command to format it: diff --git a/src/doc/rustc/src/profile-guided-optimization.md b/src/doc/rustc/src/profile-guided-optimization.md index 38b655b7542..4050494793a 100644 --- a/src/doc/rustc/src/profile-guided-optimization.md +++ b/src/doc/rustc/src/profile-guided-optimization.md @@ -3,7 +3,7 @@ `rustc` supports doing profile-guided optimization (PGO). This chapter describes what PGO is, what it is good for, and how it can be used. -## What Is Profiled-Guided Optimization? +## What Is Profile-Guided Optimization? The basic concept of PGO is to collect data about the typical execution of a program (e.g. which branches it is likely to take) and then use this data diff --git a/src/doc/rustc/src/target-tier-policy.md b/src/doc/rustc/src/target-tier-policy.md index bdcf2c0b07e..a0acfdf0e4a 100644 --- a/src/doc/rustc/src/target-tier-policy.md +++ b/src/doc/rustc/src/target-tier-policy.md @@ -122,12 +122,23 @@ To propose addition of a new target, open a pull request on [`rust-lang/rust`]: r? compiler ``` +See also the documentation in the `rustc-dev-guide` on [adding a new target to +`rustc`][rustc_dev_guide_add_target]. + +Note that adding a new target that wants to support `std` would transitively +require `cc` and `libc` support. However, these would like to know about the +target from `rustc` as well. To break this cycle, you are strongly encouraged +to add a _minimal_ `#![no_core]` target spec first to teach `rustc` about the +target's existence, and add `std` support as a follow-up once you've added +support for the target in `cc` and `libc`. + [tier3example]: https://github.com/rust-lang/rust/pull/94872 [platform_template]: https://github.com/rust-lang/rust/blob/master/src/doc/rustc/src/platform-support/TEMPLATE.md [summary]: https://github.com/rust-lang/rust/blob/master/src/doc/rustc/src/SUMMARY.md [platformsupport]: https://github.com/rust-lang/rust/blob/master/src/doc/rustc/src/platform-support.md [rust_compiler_team]: https://www.rust-lang.org/governance/teams/compiler [`rust-lang/rust`]: https://github.com/rust-lang/rust +[rustc_dev_guide_add_target]: https://rustc-dev-guide.rust-lang.org/building/new-target.html ## Tier 3 target policy diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index d1d42e47322..7eb1b8df233 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -524,6 +524,8 @@ use `-o -`. ## `-w`/`--output-format`: output format +### json + `--output-format json` emits documentation in the experimental [JSON format](https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc_json_types/). `--output-format html` has no effect, and is also accepted on stable toolchains. @@ -542,6 +544,68 @@ It can also be used with `--show-coverage`. Take a look at its [documentation](#--show-coverage-calculate-the-percentage-of-items-with-documentation) for more information. +### doctest + +`--output-format doctest` emits JSON on stdout which gives you information about doctests in the +provided crate. + +Tracking issue: [#134529](https://github.com/rust-lang/rust/issues/134529) + +You can use this option like this: + +```bash +rustdoc -Zunstable-options --output-format=doctest src/lib.rs +``` + +For this rust code: + +```rust +/// ``` +/// let x = 12; +/// ``` +pub trait Trait {} +``` + +The generated output (formatted) will look like this: + +```json +{ + "format_version": 1, + "doctests": [ + { + "file": "foo.rs", + "line": 1, + "doctest_attributes": { + "original": "", + "should_panic": false, + "no_run": false, + "ignore": "None", + "rust": true, + "test_harness": false, + "compile_fail": false, + "standalone_crate": false, + "error_codes": [], + "edition": null, + "added_css_classes": [], + "unknown": [] + }, + "original_code": "let x = 12;", + "doctest_code": "#![allow(unused)]\nfn main() {\nlet x = 12;\n}", + "name": "foo.rs - Trait (line 1)" + } + ] +} +``` + + * `format_version` gives you the current version of the generated JSON. If we change the output in any way, the number will increase. + * `doctests` contains the list of doctests present in the crate. + * `file` is the file path where the doctest is located. + * `line` is the line where the doctest starts (so where the \`\`\` is located in the current code). + * `doctest_attributes` contains computed information about the attributes used on the doctests. For more information about doctest attributes, take a look [here](write-documentation/documentation-tests.html#attributes). + * `original_code` is the code as written in the source code before rustdoc modifies it. + * `doctest_code` is the code modified by rustdoc that will be run. If there is a fatal syntax error, this field will not be present. + * `name` is the name generated by rustdoc which represents this doctest. + ## `--enable-per-target-ignores`: allow `ignore-foo` style filters for doctests * Tracking issue: [#64245](https://github.com/rust-lang/rust/issues/64245) diff --git a/src/doc/style-guide/src/editions.md b/src/doc/style-guide/src/editions.md index b9a89c20cee..19e62c4867c 100644 --- a/src/doc/style-guide/src/editions.md +++ b/src/doc/style-guide/src/editions.md @@ -36,10 +36,6 @@ For a full history of changes in the Rust 2024 style edition, see the git history of the style guide. Notable changes in the Rust 2024 style edition include: -- [#114764](https://github.com/rust-lang/rust/pull/114764) As the last member - of a delimited expression, delimited expressions are generally combinable, - regardless of the number of members. Previously only applied with exactly - one member (except for closures with explicit blocks). - Miscellaneous `rustfmt` bugfixes. - Use version-sort (sort `x8`, `x16`, `x32`, `x64`, `x128` in that order). - Change "ASCIIbetical" sort to Unicode-aware "non-lowercase before lowercase". diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md index 171a24cd89d..12037b5992e 100644 --- a/src/doc/style-guide/src/expressions.md +++ b/src/doc/style-guide/src/expressions.md @@ -818,11 +818,11 @@ E.g., `&&Some(foo)` matches, `Foo(4, Bar)` does not. ## Combinable expressions -When the last argument in a function call is formatted across -multiple-lines, format the outer call as if it were a single-line call, +Where a function call has a single argument, and that argument is formatted +across multiple-lines, format the outer call as if it were a single-line call, if the result fits. Apply the same combining behaviour to any similar expressions which have multi-line, block-indented lists of sub-expressions -delimited by parentheses, brackets, or braces. E.g., +delimited by parentheses (e.g., macros or tuple struct literals). E.g., ```rust foo(bar( @@ -848,61 +848,20 @@ let arr = [combinable( an_expr, another_expr, )]; - -let x = Thing(an_expr, another_expr, match cond { - A => 1, - B => 2, -}); - -let x = format!("Stuff: {}", [ - an_expr, - another_expr, -]); - -let x = func(an_expr, another_expr, SomeStruct { - field: this_is_long, - another_field: 123, -}); ``` Apply this behavior recursively. -If the last argument is a multi-line closure with an explicit block, -only apply the combining behavior if there are no other closure arguments. +For a function with multiple arguments, if the last argument is a multi-line +closure with an explicit block, there are no other closure arguments, and all +the arguments and the first line of the closure fit on the first line, use the +same combining behavior: ```rust -// Combinable foo(first_arg, x, |param| { action(); foo(param) }) -// Not combinable, because the closure is not the last argument -foo( - first_arg, - |param| { - action(); - foo(param) - }, - whatever, -) -// Not combinable, because the first line of the closure does not fit -foo( - first_arg, - x, - move |very_long_param_causing_line_to_overflow| -> Bar { - action(); - foo(param) - }, -) -// Not combinable, because there is more than one closure argument -foo( - first_arg, - |x| x.bar(), - |param| { - action(); - foo(param) - }, -) ``` ## Ranges diff --git a/src/doc/unstable-book/src/compiler-flags/autodiff.md b/src/doc/unstable-book/src/compiler-flags/autodiff.md new file mode 100644 index 00000000000..4e55be0ad95 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/autodiff.md @@ -0,0 +1,23 @@ +# `autodiff` + +The tracking issue for this feature is: [#124509](https://github.com/rust-lang/rust/issues/124509). + +------------------------ + +This feature allows you to differentiate functions using automatic differentiation. +Set the `-Zautodiff=<options>` compiler flag to adjust the behaviour of the autodiff feature. +Multiple options can be separated with a comma. Valid options are: + +`PrintTA` - print Type Analysis Information +`PrintAA` - print Activity Analysis Information +`PrintPerf` - print Performance Warnings from Enzyme +`Print` - prints all intermediate transformations +`PrintModBefore` - print the whole module, before running opts +`PrintModAfterOpts` - print the whole module just before we pass it to Enzyme +`PrintModAfterEnzyme` - print the module after Enzyme differentiated everything +`LooseTypes` - Enzyme's loose type debug helper (can cause incorrect gradients) +`Inline` - runs Enzyme specific Inlining +`NoModOptAfter` - do not optimize the module after Enzyme is done +`EnableFncOpt` - tell Enzyme to run LLVM Opts on each function it generated +`NoVecUnroll` - do not unroll vectorized loops +`RuntimeActivity` - allow specifying activity at runtime diff --git a/src/doc/unstable-book/src/compiler-flags/dwarf-version.md b/src/doc/unstable-book/src/compiler-flags/dwarf-version.md index c5e86f17df7..e88799d2cf0 100644 --- a/src/doc/unstable-book/src/compiler-flags/dwarf-version.md +++ b/src/doc/unstable-book/src/compiler-flags/dwarf-version.md @@ -1,5 +1,9 @@ ## `dwarf-version` +The tracking issue for this feature is: <https://github.com/rust-lang/rust/issues/103057> + +---------------------------- + This option controls the version of DWARF that the compiler emits, on platforms that use DWARF to encode debug information. It takes one of the following values: diff --git a/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024-structural.md b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024-structural.md new file mode 100644 index 00000000000..bc587686111 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024-structural.md @@ -0,0 +1,19 @@ +# `ref_pat_eat_one_layer_2024_structural` + +The tracking issue for this feature is: [#123076] + +[#123076]: https://github.com/rust-lang/rust/issues/123076 + +--- + +This feature is incomplete and not yet intended for general use. + +This implements experimental, Edition-dependent match ergonomics under consideration for inclusion +in Rust. +For more information, see the corresponding typing rules for [Editions 2024 and later]. +On earlier Editions, the current behavior is unspecified. + +For alternative experimental match ergonomics, see the feature +[`ref_pat_eat_one_layer_2024`](./ref-pat-eat-one-layer-2024.md). + +[Editions 2024 and later]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAgEBAQEBAgIAAAAAAAAAAAAAAAA%3D&mode=rules&do_cmp=false diff --git a/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md new file mode 100644 index 00000000000..43de1849a5e --- /dev/null +++ b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md @@ -0,0 +1,19 @@ +# `ref_pat_eat_one_layer_2024` + +The tracking issue for this feature is: [#123076] + +[#123076]: https://github.com/rust-lang/rust/issues/123076 + +--- + +This feature is incomplete and not yet intended for general use. + +This implements experimental, Edition-dependent match ergonomics under consideration for inclusion +in Rust. +For more information, see the corresponding typing rules for [Editions 2024 and later]. +On earlier Editions, the current behavior is unspecified. + +For alternative experimental match ergonomics, see the feature +[`ref_pat_eat_one_layer_2024_structural`](./ref-pat-eat-one-layer-2024-structural.md). + +[Editions 2024 and later]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAAABAQABAgIAAQEBAAEBAAABAAA%3D&mode=rules&do_cmp=false diff --git a/src/librustdoc/build.rs b/src/librustdoc/build.rs index 69337fb1d25..b4b0a8d0615 100644 --- a/src/librustdoc/build.rs +++ b/src/librustdoc/build.rs @@ -17,10 +17,15 @@ fn main() { "static/images/rust-logo.svg", "static/images/favicon.svg", "static/images/favicon-32x32.png", + "static/fonts/FiraSans-Italic.woff2", "static/fonts/FiraSans-Regular.woff2", "static/fonts/FiraSans-Medium.woff2", + "static/fonts/FiraSans-MediumItalic.woff2", + "static/fonts/FiraMono-Regular.woff2", + "static/fonts/FiraMono-Medium.woff2", "static/fonts/FiraSans-LICENSE.txt", "static/fonts/SourceSerif4-Regular.ttf.woff2", + "static/fonts/SourceSerif4-Semibold.ttf.woff2", "static/fonts/SourceSerif4-Bold.ttf.woff2", "static/fonts/SourceSerif4-It.ttf.woff2", "static/fonts/SourceSerif4-LICENSE.md", diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 6e817af0d6e..a44d74e6df6 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -5,9 +5,7 @@ use std::{fmt, iter}; use arrayvec::ArrayVec; use rustc_abi::{ExternAbi, VariantIdx}; -use rustc_attr_parsing::{ - AllowedThroughUnstableModules, ConstStability, Deprecation, Stability, StableSince, -}; +use rustc_attr_parsing::{ConstStability, Deprecation, Stability, StableSince}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; @@ -411,15 +409,9 @@ impl Item { .. } = stab.level { - let note = match note { - AllowedThroughUnstableModules::WithDeprecation(note) => Some(note), - // FIXME: Would be better to say *something* here about the *path* being - // deprecated rather than the item. - AllowedThroughUnstableModules::WithoutDeprecation => None, - }; Some(Deprecation { since: rustc_attr_parsing::DeprecatedSince::Unspecified, - note, + note: Some(note), suggestion: None, }) } else { diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 65722eff1da..f1921b90cc6 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -344,10 +344,8 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String { s } // array lengths are obviously usize - ty::ConstKind::Value(ty, ty::ValTree::Leaf(scalar)) - if *ty.kind() == ty::Uint(ty::UintTy::Usize) => - { - scalar.to_string() + ty::ConstKind::Value(cv) if *cv.ty.kind() == ty::Uint(ty::UintTy::Usize) => { + cv.valtree.unwrap_leaf().to_string() } _ => n.to_string(), } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 80bc6cebd2a..c6fb70eee08 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -9,8 +9,8 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::DiagCtxtHandle; use rustc_session::config::{ self, CodegenOptions, CrateType, ErrorOutputType, Externs, Input, JsonUnusedExterns, - UnstableOptions, get_cmd_lint_options, nightly_options, parse_crate_types_from_list, - parse_externs, parse_target_triple, + OptionsTargetModifiers, UnstableOptions, get_cmd_lint_options, nightly_options, + parse_crate_types_from_list, parse_externs, parse_target_triple, }; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; @@ -33,6 +33,7 @@ pub(crate) enum OutputFormat { Json, #[default] Html, + Doctest, } impl OutputFormat { @@ -48,6 +49,7 @@ impl TryFrom<&str> for OutputFormat { match value { "json" => Ok(OutputFormat::Json), "html" => Ok(OutputFormat::Html), + "doctest" => Ok(OutputFormat::Doctest), _ => Err(format!("unknown output format `{value}`")), } } @@ -387,8 +389,9 @@ impl Options { config::parse_error_format(early_dcx, matches, color, json_color, json_rendered); let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_default(); - let codegen_options = CodegenOptions::build(early_dcx, matches); - let unstable_opts = UnstableOptions::build(early_dcx, matches); + let mut target_modifiers = BTreeMap::<OptionsTargetModifiers, String>::new(); + let codegen_options = CodegenOptions::build(early_dcx, matches, &mut target_modifiers); + let unstable_opts = UnstableOptions::build(early_dcx, matches, &mut target_modifiers); let remap_path_prefix = match parse_remap_path_prefix(matches) { Ok(prefix_mappings) => prefix_mappings, @@ -445,14 +448,42 @@ impl Options { } } + let show_coverage = matches.opt_present("show-coverage"); + let output_format_s = matches.opt_str("output-format"); + let output_format = match output_format_s { + Some(ref s) => match OutputFormat::try_from(s.as_str()) { + Ok(out_fmt) => out_fmt, + Err(e) => dcx.fatal(e), + }, + None => OutputFormat::default(), + }; + // check for `--output-format=json` - if !matches!(matches.opt_str("output-format").as_deref(), None | Some("html")) - && !matches.opt_present("show-coverage") - && !nightly_options::is_unstable_enabled(matches) - { - dcx.fatal( - "the -Z unstable-options flag must be passed to enable --output-format for documentation generation (see https://github.com/rust-lang/rust/issues/76578)", - ); + match ( + output_format_s.as_ref().map(|_| output_format), + show_coverage, + nightly_options::is_unstable_enabled(matches), + ) { + (None | Some(OutputFormat::Json), true, _) => {} + (_, true, _) => { + dcx.fatal(format!( + "`--output-format={}` is not supported for the `--show-coverage` option", + output_format_s.unwrap_or_default(), + )); + } + // If `-Zunstable-options` is used, nothing to check after this point. + (_, false, true) => {} + (None | Some(OutputFormat::Html), false, _) => {} + (Some(OutputFormat::Json), false, false) => { + dcx.fatal( + "the -Z unstable-options flag must be passed to enable --output-format for documentation generation (see https://github.com/rust-lang/rust/issues/76578)", + ); + } + (Some(OutputFormat::Doctest), false, false) => { + dcx.fatal( + "the -Z unstable-options flag must be passed to enable --output-format for documentation generation (see https://github.com/rust-lang/rust/issues/134529)", + ); + } } let to_check = matches.opt_strs("check-theme"); @@ -704,8 +735,6 @@ impl Options { }) .collect(); - let show_coverage = matches.opt_present("show-coverage"); - let crate_types = match parse_crate_types_from_list(matches.opt_strs("crate-type")) { Ok(types) => types, Err(e) => { @@ -713,20 +742,6 @@ impl Options { } }; - let output_format = match matches.opt_str("output-format") { - Some(s) => match OutputFormat::try_from(s.as_str()) { - Ok(out_fmt) => { - if !out_fmt.is_json() && show_coverage { - dcx.fatal( - "html output format isn't supported for the --show-coverage option", - ); - } - out_fmt - } - Err(e) => dcx.fatal(e), - }, - None => OutputFormat::default(), - }; let crate_name = matches.opt_str("crate-name"); let bin_crate = crate_types.contains(&CrateType::Executable); let proc_macro_crate = crate_types.contains(&CrateType::ProcMacro); diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index d6b2b53d34c..6af35157a43 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -336,14 +336,14 @@ pub(crate) fn run_global_ctxt( // NOTE: These are copy/pasted from typeck/lib.rs and should be kept in sync with those changes. let _ = tcx.sess.time("wf_checking", || { - tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module)) + tcx.hir().try_par_for_each_module(|module| tcx.ensure_ok().check_mod_type_wf(module)) }); tcx.dcx().abort_if_errors(); tcx.sess.time("missing_docs", || rustc_lint::check_crate(tcx)); tcx.sess.time("check_mod_attrs", || { - tcx.hir().for_each_module(|module| tcx.ensure().check_mod_attrs(module)) + tcx.hir().for_each_module(|module| tcx.ensure_ok().check_mod_attrs(module)) }); rustc_passes::stability::check_unused_or_stable_features(tcx); diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 8c3e28ecec3..8b522e614b8 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1,3 +1,4 @@ +mod extracted; mod make; mod markdown; mod runner; @@ -30,7 +31,7 @@ use tempfile::{Builder as TempFileBuilder, TempDir}; use tracing::debug; use self::rust::HirCollector; -use crate::config::Options as RustdocOptions; +use crate::config::{Options as RustdocOptions, OutputFormat}; use crate::html::markdown::{ErrorCodes, Ignore, LangString, MdRelLine}; use crate::lint::init_lints; @@ -209,15 +210,8 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions let args_path = temp_dir.path().join("rustdoc-cfgs"); crate::wrap_return(dcx, generate_args_file(&args_path, &options)); - let CreateRunnableDocTests { - standalone_tests, - mergeable_tests, - rustdoc_options, - opts, - unused_extern_reports, - compiling_test_count, - .. - } = interface::run_compiler(config, |compiler| { + let extract_doctests = options.output_format == OutputFormat::Doctest; + let result = interface::run_compiler(config, |compiler| { let krate = rustc_interface::passes::parse(&compiler.sess); let collector = rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| { @@ -226,22 +220,53 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions let opts = scrape_test_config(crate_name, crate_attrs, args_path); let enable_per_target_ignores = options.enable_per_target_ignores; - let mut collector = CreateRunnableDocTests::new(options, opts); let hir_collector = HirCollector::new( ErrorCodes::from(compiler.sess.opts.unstable_features.is_nightly_build()), enable_per_target_ignores, tcx, ); let tests = hir_collector.collect_crate(); - tests.into_iter().for_each(|t| collector.add_test(t)); + if extract_doctests { + let mut collector = extracted::ExtractedDocTests::new(); + tests.into_iter().for_each(|t| collector.add_test(t, &opts, &options)); + + let stdout = std::io::stdout(); + let mut stdout = stdout.lock(); + if let Err(error) = serde_json::ser::to_writer(&mut stdout, &collector) { + eprintln!(); + Err(format!("Failed to generate JSON output for doctests: {error:?}")) + } else { + Ok(None) + } + } else { + let mut collector = CreateRunnableDocTests::new(options, opts); + tests.into_iter().for_each(|t| collector.add_test(t)); - collector + Ok(Some(collector)) + } }); compiler.sess.dcx().abort_if_errors(); collector }); + let CreateRunnableDocTests { + standalone_tests, + mergeable_tests, + rustdoc_options, + opts, + unused_extern_reports, + compiling_test_count, + .. + } = match result { + Ok(Some(collector)) => collector, + Ok(None) => return, + Err(error) => { + eprintln!("{error}"); + std::process::exit(1); + } + }; + run_tests(opts, &rustdoc_options, &unused_extern_reports, standalone_tests, mergeable_tests); let compiling_test_count = compiling_test_count.load(Ordering::SeqCst); diff --git a/src/librustdoc/doctest/extracted.rs b/src/librustdoc/doctest/extracted.rs new file mode 100644 index 00000000000..03c8814a4c9 --- /dev/null +++ b/src/librustdoc/doctest/extracted.rs @@ -0,0 +1,141 @@ +//! Rustdoc's doctest extraction. +//! +//! This module contains the logic to extract doctests and output a JSON containing this +//! information. + +use serde::Serialize; + +use super::{DocTestBuilder, ScrapedDocTest}; +use crate::config::Options as RustdocOptions; +use crate::html::markdown; + +/// The version of JSON output that this code generates. +/// +/// This integer is incremented with every breaking change to the API, +/// and is returned along with the JSON blob into the `format_version` root field. +/// Consuming code should assert that this value matches the format version(s) that it supports. +const FORMAT_VERSION: u32 = 1; + +#[derive(Serialize)] +pub(crate) struct ExtractedDocTests { + format_version: u32, + doctests: Vec<ExtractedDocTest>, +} + +impl ExtractedDocTests { + pub(crate) fn new() -> Self { + Self { format_version: FORMAT_VERSION, doctests: Vec::new() } + } + + pub(crate) fn add_test( + &mut self, + scraped_test: ScrapedDocTest, + opts: &super::GlobalTestOptions, + options: &RustdocOptions, + ) { + let edition = scraped_test.edition(&options); + + let ScrapedDocTest { filename, line, langstr, text, name } = scraped_test; + + let doctest = DocTestBuilder::new( + &text, + Some(&opts.crate_name), + edition, + false, + None, + Some(&langstr), + ); + let (full_test_code, size) = doctest.generate_unique_doctest( + &text, + langstr.test_harness, + &opts, + Some(&opts.crate_name), + ); + self.doctests.push(ExtractedDocTest { + file: filename.prefer_remapped_unconditionaly().to_string(), + line, + doctest_attributes: langstr.into(), + doctest_code: if size != 0 { Some(full_test_code) } else { None }, + original_code: text, + name, + }); + } +} + +#[derive(Serialize)] +pub(crate) struct ExtractedDocTest { + file: String, + line: usize, + doctest_attributes: LangString, + original_code: String, + /// `None` if the code syntax is invalid. + doctest_code: Option<String>, + name: String, +} + +#[derive(Serialize)] +pub(crate) enum Ignore { + All, + None, + Some(Vec<String>), +} + +impl From<markdown::Ignore> for Ignore { + fn from(original: markdown::Ignore) -> Self { + match original { + markdown::Ignore::All => Self::All, + markdown::Ignore::None => Self::None, + markdown::Ignore::Some(values) => Self::Some(values), + } + } +} + +#[derive(Serialize)] +struct LangString { + pub(crate) original: String, + pub(crate) should_panic: bool, + pub(crate) no_run: bool, + pub(crate) ignore: Ignore, + pub(crate) rust: bool, + pub(crate) test_harness: bool, + pub(crate) compile_fail: bool, + pub(crate) standalone_crate: bool, + pub(crate) error_codes: Vec<String>, + pub(crate) edition: Option<String>, + pub(crate) added_css_classes: Vec<String>, + pub(crate) unknown: Vec<String>, +} + +impl From<markdown::LangString> for LangString { + fn from(original: markdown::LangString) -> Self { + let markdown::LangString { + original, + should_panic, + no_run, + ignore, + rust, + test_harness, + compile_fail, + standalone_crate, + error_codes, + edition, + added_classes, + unknown, + } = original; + + Self { + original, + should_panic, + no_run, + ignore: ignore.into(), + rust, + test_harness, + compile_fail, + standalone_crate, + error_codes, + edition: edition.map(|edition| edition.to_string()), + added_css_classes: added_classes, + unknown, + } + } +} diff --git a/src/librustdoc/html/static/COPYRIGHT.txt b/src/librustdoc/html/static/COPYRIGHT.txt index 1447df792f6..111340298c5 100644 --- a/src/librustdoc/html/static/COPYRIGHT.txt +++ b/src/librustdoc/html/static/COPYRIGHT.txt @@ -36,7 +36,7 @@ included, and carry their own copyright notices and license terms: See SourceCodePro-LICENSE.txt. * Source Serif 4 (SourceSerif4-Regular.ttf.woff2, SourceSerif4-Bold.ttf.woff2, - SourceSerif4-It.ttf.woff2): + SourceSerif4-It.ttf.woff2, SourceSerif4-Semibold.ttf.woff2): Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index f487d66edac..d0612e997fd 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -38,6 +38,13 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\ --code-block-border-radius: 6px; --impl-items-indent: 0.3em; --docblock-indent: 24px; + --font-family: "Source Serif 4", NanumBarunGothic, serif; + --font-family-code: "Source Code Pro", monospace; +} + +:root.sans-serif { + --font-family: "Fira Sans", sans-serif; + --font-family-code: "Fira Mono", monospace; } /* See FiraSans-LICENSE.txt for the Fira Sans license. */ @@ -51,12 +58,44 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\ } @font-face { font-family: 'Fira Sans'; + font-style: italic; + font-weight: 400; + src: local('Fira Sans Italic'), + url("FiraSans-Italic-81dc35de.woff2") format("woff2"); + font-display: swap; +} +@font-face { + font-family: 'Fira Sans'; font-style: normal; font-weight: 500; src: local('Fira Sans Medium'), url("FiraSans-Medium-e1aa3f0a.woff2") format("woff2"); font-display: swap; } +@font-face { + font-family: 'Fira Sans'; + font-style: italic; + font-weight: 500; + src: local('Fira Sans Medium Italic'), + url("FiraSans-MediumItalic-ccf7e434.woff2") format("woff2"); + font-display: swap; +} +@font-face { + font-family: 'Fira Mono'; + font-style: normal; + font-weight: 400; + src: local('Fira Mono'), + url("FiraMono-Regular-87c26294.woff2") format("woff2"); + font-display: swap; +} +@font-face { + font-family: 'Fira Mono'; + font-style: normal; + font-weight: 500; + src: local('Fira Mono Medium'), + url("FiraMono-Medium-86f75c8c.woff2") format("woff2"); + font-display: swap; +} /* See SourceSerif4-LICENSE.md for the Source Serif 4 license. */ @font-face { @@ -78,6 +117,14 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\ @font-face { font-family: 'Source Serif 4'; font-style: normal; + font-weight: 500; + src: local('Source Serif 4 Semibold'), + url("SourceSerif4-Semibold-457a13ac.ttf.woff2") format("woff2"); + font-display: swap; +} +@font-face { + font-family: 'Source Serif 4'; + font-style: normal; font-weight: 700; src: local('Source Serif 4 Bold'), url("SourceSerif4-Bold-6d4fd4c0.ttf.woff2") format("woff2"); @@ -126,7 +173,7 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\ body { /* Line spacing at least 1.5 per Web Content Accessibility Guidelines https://www.w3.org/WAI/WCAG21/Understanding/visual-presentation.html */ - font: 1rem/1.5 "Source Serif 4", NanumBarunGothic, serif; + font: 1rem/1.5 var(--font-family); margin: 0; position: relative; /* We use overflow-wrap: break-word for Safari, which doesn't recognize @@ -380,7 +427,7 @@ details:not(.toggle) summary { } code, pre, .code-header, .type-signature { - font-family: "Source Code Pro", monospace; + font-family: var(--font-family-code); } .docblock code, .item-table dd code { border-radius: 3px; diff --git a/src/librustdoc/html/static/fonts/FiraMono-Medium.woff2 b/src/librustdoc/html/static/fonts/FiraMono-Medium.woff2 new file mode 100755 index 00000000000..610e9b2071e --- /dev/null +++ b/src/librustdoc/html/static/fonts/FiraMono-Medium.woff2 Binary files differdiff --git a/src/librustdoc/html/static/fonts/FiraMono-Regular.woff2 b/src/librustdoc/html/static/fonts/FiraMono-Regular.woff2 new file mode 100755 index 00000000000..9fa44b7cc2d --- /dev/null +++ b/src/librustdoc/html/static/fonts/FiraMono-Regular.woff2 Binary files differdiff --git a/src/librustdoc/html/static/fonts/FiraSans-Italic.woff2 b/src/librustdoc/html/static/fonts/FiraSans-Italic.woff2 new file mode 100755 index 00000000000..3f63664fee6 --- /dev/null +++ b/src/librustdoc/html/static/fonts/FiraSans-Italic.woff2 Binary files differdiff --git a/src/librustdoc/html/static/fonts/FiraSans-MediumItalic.woff2 b/src/librustdoc/html/static/fonts/FiraSans-MediumItalic.woff2 new file mode 100755 index 00000000000..2d08f9f7d45 --- /dev/null +++ b/src/librustdoc/html/static/fonts/FiraSans-MediumItalic.woff2 Binary files differdiff --git a/src/librustdoc/html/static/fonts/SourceSerif4-Semibold.ttf.woff2 b/src/librustdoc/html/static/fonts/SourceSerif4-Semibold.ttf.woff2 new file mode 100644 index 00000000000..dd55f4e95ec --- /dev/null +++ b/src/librustdoc/html/static/fonts/SourceSerif4-Semibold.ttf.woff2 Binary files differdiff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index d7b0e4b4f54..bf33e0f17e5 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -53,6 +53,12 @@ removeClass(document.documentElement, "hide-modnav"); } break; + case "sans-serif-fonts": + if (value === true) { + addClass(document.documentElement, "sans-serif"); + } else { + removeClass(document.documentElement, "sans-serif"); + } } } @@ -235,6 +241,11 @@ "js_name": "disable-shortcuts", "default": false, }, + { + "name": "Use sans serif fonts", + "js_name": "sans-serif-fonts", + "default": false, + }, ]; // Then we build the DOM. diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 4770ccc1279..10369e77320 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -279,6 +279,9 @@ if (getSettingValue("hide-toc") === "true") { if (getSettingValue("hide-modnav") === "true") { addClass(document.documentElement, "hide-modnav"); } +if (getSettingValue("sans-serif-fonts") === "true") { + addClass(document.documentElement, "sans-serif"); +} function updateSidebarWidth() { const desktopSidebarWidth = getSettingValue("desktop-sidebar-width"); if (desktopSidebarWidth && desktopSidebarWidth !== "null") { diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index 6457ac731cb..0bcaf11da0c 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -98,10 +98,15 @@ static_files! { rust_logo_svg => "static/images/rust-logo.svg", rust_favicon_svg => "static/images/favicon.svg", rust_favicon_png_32 => "static/images/favicon-32x32.png", + fira_sans_italic => "static/fonts/FiraSans-Italic.woff2", fira_sans_regular => "static/fonts/FiraSans-Regular.woff2", fira_sans_medium => "static/fonts/FiraSans-Medium.woff2", + fira_sans_medium_italic => "static/fonts/FiraSans-MediumItalic.woff2", + fira_mono_regular => "static/fonts/FiraMono-Regular.woff2", + fira_mono_medium => "static/fonts/FiraMono-Medium.woff2", fira_sans_license => "static/fonts/FiraSans-LICENSE.txt", source_serif_4_regular => "static/fonts/SourceSerif4-Regular.ttf.woff2", + source_serif_4_semibold => "static/fonts/SourceSerif4-Semibold.ttf.woff2", source_serif_4_bold => "static/fonts/SourceSerif4-Bold.ttf.woff2", source_serif_4_italic => "static/fonts/SourceSerif4-It.ttf.woff2", source_serif_4_license => "static/fonts/SourceSerif4-LICENSE.md", diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index a05d6ca8313..5ef376f4acb 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -7,7 +7,7 @@ <meta name="description" content="{{page.description}}"> {# #} <title>{{page.title}}</title> {# #} <script>if(window.location.protocol!=="file:") {# Hack to skip preloading fonts locally - see #98769 #} - document.head.insertAdjacentHTML("beforeend","{{files.source_serif_4_regular}},{{files.fira_sans_regular}},{{files.fira_sans_medium}},{{files.source_code_pro_regular}},{{files.source_code_pro_semibold}}".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}${f}">`).join("")) {# #} + document.head.insertAdjacentHTML("beforeend","{{files.source_serif_4_regular}},{{files.fira_sans_italic}},{{files.fira_sans_regular}},{{files.fira_sans_medium_italic}},{{files.fira_sans_medium}},{{files.source_code_pro_regular}},{{files.source_code_pro_semibold}}".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}${f}">`).join("")) {# #} </script> {# #} <link rel="stylesheet" {#+ #} href="{{static_root_path|safe}}{{files.normalize_css}}"> {# #} diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 45f42e61fbf..96ef400d903 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -177,9 +177,8 @@ pub fn main() { rustc_driver::init_logger(&early_dcx, rustc_log::LoggerConfig::from_env("RUSTDOC_LOG")); let exit_code = rustc_driver::catch_with_exit_code(|| { - let at_args = rustc_driver::args::raw_args(&early_dcx)?; + let at_args = rustc_driver::args::raw_args(&early_dcx); main_args(&mut early_dcx, &at_args); - Ok(()) }); process::exit(exit_code); } @@ -814,7 +813,12 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { } }; - match (options.should_test, config::markdown_input(&input)) { + let output_format = options.output_format; + + match ( + options.should_test || output_format == config::OutputFormat::Doctest, + config::markdown_input(&input), + ) { (true, Some(_)) => return wrap_return(dcx, doctest::test_markdown(&input, options)), (true, None) => return doctest::run(dcx, input, options), (false, Some(md_input)) => { @@ -849,7 +853,6 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { // plug/cleaning passes. let crate_version = options.crate_version.clone(); - let output_format = options.output_format; let scrape_examples_options = options.scrape_examples_options.clone(); let bin_crate = options.bin_crate; @@ -899,6 +902,8 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { config::OutputFormat::Json => sess.time("render_json", || { run_renderer::<json::JsonRenderer<'_>>(krate, render_opts, cache, tcx) }), + // Already handled above with doctest runners. + config::OutputFormat::Doctest => unreachable!(), } }) }) diff --git a/src/tools/cargo b/src/tools/cargo -Subproject cecde95c119a456c30e57d3e4b31fff5a7d83df +Subproject 0e3d73849ab8cbbab3ec5c65cbd555586cb2133 diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md index c26ad319f4f..48506127dee 100644 --- a/src/tools/clippy/book/src/development/adding_lints.md +++ b/src/tools/clippy/book/src/development/adding_lints.md @@ -788,7 +788,7 @@ don't hesitate to ask on [Zulip] or in the issue/PR. [`snippet`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/source/fn.snippet.html [let-chains]: https://github.com/rust-lang/rust/pull/94927 [from_expansion]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html#method.from_expansion -[in_external_macro]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/lint/fn.in_external_macro.html +[in_external_macro]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html#method.in_external_macro [span]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html [applicability]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/enum.Applicability.html [rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/ diff --git a/src/tools/clippy/book/src/development/common_tools_writing_lints.md b/src/tools/clippy/book/src/development/common_tools_writing_lints.md index b44ad80a25c..051febc2ca5 100644 --- a/src/tools/clippy/book/src/development/common_tools_writing_lints.md +++ b/src/tools/clippy/book/src/development/common_tools_writing_lints.md @@ -218,7 +218,7 @@ functions to deal with macros: > context. And so just using `span.from_expansion()` is often good enough. -- `in_external_macro(span)`: detect if the given span is from a macro defined in +- `span.in_external_macro(sm)`: detect if the given span is from a macro defined in a foreign crate. If you want the lint to work with macro-generated code, this is the next line of defense to avoid macros not defined in the current crate. It doesn't make sense to lint code that the coder can't change. @@ -227,15 +227,13 @@ functions to deal with macros: crates ```rust - use rustc_middle::lint::in_external_macro; - use a_crate_with_macros::foo; // `foo` is defined in `a_crate_with_macros` foo!("bar"); // if we lint the `match` of `foo` call and test its span - assert_eq!(in_external_macro(cx.sess(), match_span), true); + assert_eq!(match_span.in_external_macro(cx.sess().source_map()), true); ``` - `span.ctxt()`: the span's context represents whether it is from expansion, and diff --git a/src/tools/clippy/book/src/development/macro_expansions.md b/src/tools/clippy/book/src/development/macro_expansions.md index 125b6c4bc5b..36092f82e26 100644 --- a/src/tools/clippy/book/src/development/macro_expansions.md +++ b/src/tools/clippy/book/src/development/macro_expansions.md @@ -120,7 +120,7 @@ assert_ne!(x_is_some_span.ctxt(), x_unwrap_span.ctxt()); ### The `in_external_macro` function -`rustc_middle::lint` provides a function ([`in_external_macro`]) that can +`Span` provides a method ([`in_external_macro`]) that can detect if the given span is from a macro defined in a foreign crate. Therefore, if we really want a new lint to work with macro-generated code, @@ -144,7 +144,7 @@ Also assume that we get the corresponding variable `foo_span` for the results in `true` (note that `cx` can be `EarlyContext` or `LateContext`): ```rust -if in_external_macro(cx.sess(), foo_span) { +if foo_span.in_external_macro(cx.sess().source_map()) { // We should ignore macro from a foreign crate. return; } @@ -153,6 +153,6 @@ if in_external_macro(cx.sess(), foo_span) { [`ctxt`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html#method.ctxt [expansion]: https://rustc-dev-guide.rust-lang.org/macro-expansion.html#expansion-and-ast-integration [`from_expansion`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html#method.from_expansion -[`in_external_macro`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_middle/lint/fn.in_external_macro.html +[`in_external_macro`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html#method.in_external_macro [Span]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html [SyntaxContext]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/hygiene/struct.SyntaxContext.html diff --git a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs index 2af5178920d..0f7f779e8ea 100644 --- a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs +++ b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs @@ -5,7 +5,6 @@ use clippy_utils::source::{trim_span, walk_span_to_context}; use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; declare_clippy_lint! { @@ -45,7 +44,7 @@ impl EarlyLintPass for AlmostCompleteRange { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) { if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind && is_incomplete_range(start, end) - && !in_external_macro(cx.sess(), e.span) + && !e.span.in_external_macro(cx.sess().source_map()) { span_lint_and_then( cx, @@ -74,7 +73,7 @@ impl EarlyLintPass for AlmostCompleteRange { if let PatKind::Range(Some(start), Some(end), kind) = &p.kind && matches!(kind.node, RangeEnd::Excluded) && is_incomplete_range(start, end) - && !in_external_macro(cx.sess(), p.span) + && !p.span.in_external_macro(cx.sess().source_map()) { span_lint_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs index 0389223c3e0..f519a65fc27 100644 --- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs +++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs @@ -9,7 +9,6 @@ use rustc_hir::{ Variant, VariantData, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; declare_clippy_lint! { @@ -248,7 +247,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { ItemKind::Enum(enum_def, _generics) if self.enable_ordering_for_enum => { let mut cur_v: Option<&Variant<'_>> = None; for variant in enum_def.variants { - if in_external_macro(cx.sess(), variant.span) { + if variant.span.in_external_macro(cx.sess().source_map()) { continue; } @@ -263,7 +262,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { ItemKind::Struct(VariantData::Struct { fields, .. }, _generics) if self.enable_ordering_for_struct => { let mut cur_f: Option<&FieldDef<'_>> = None; for field in *fields { - if in_external_macro(cx.sess(), field.span) { + if field.span.in_external_macro(cx.sess().source_map()) { continue; } @@ -281,7 +280,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { let mut cur_t: Option<&TraitItemRef> = None; for item in *item_ref { - if in_external_macro(cx.sess(), item.span) { + if item.span.in_external_macro(cx.sess().source_map()) { continue; } @@ -304,7 +303,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { let mut cur_t: Option<&ImplItemRef> = None; for item in trait_impl.items { - if in_external_macro(cx.sess(), item.span) { + if item.span.in_external_macro(cx.sess().source_map()) { continue; } @@ -348,7 +347,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { // as no sorting by source map/line of code has to be applied. // for item in items { - if in_external_macro(cx.sess(), item.span) { + if item.span.in_external_macro(cx.sess().source_map()) { continue; } diff --git a/src/tools/clippy/clippy_lints/src/as_conversions.rs b/src/tools/clippy/clippy_lints/src/as_conversions.rs index fefd8195f8e..847653ed6e9 100644 --- a/src/tools/clippy/clippy_lints/src/as_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/as_conversions.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; declare_clippy_lint! { @@ -49,7 +48,7 @@ declare_lint_pass!(AsConversions => [AS_CONVERSIONS]); impl<'tcx> LateLintPass<'tcx> for AsConversions { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { if let ExprKind::Cast(_, _) = expr.kind - && !in_external_macro(cx.sess(), expr.span) + && !expr.span.in_external_macro(cx.sess().source_map()) && !is_from_proc_macro(cx, expr) { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs index 1879391ec29..53d9725703c 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs @@ -4,11 +4,10 @@ use clippy_utils::is_from_proc_macro; use rustc_ast::{AttrStyle, Attribute}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, LintContext}; -use rustc_middle::lint::in_external_macro; // Separate each crate's features. pub fn check<'cx>(cx: &EarlyContext<'cx>, attr: &'cx Attribute) { - if !in_external_macro(cx.sess(), attr.span) + if !attr.span.in_external_macro(cx.sess().source_map()) && let AttrStyle::Outer = attr.style && let Some(ident) = attr.ident() && !is_from_proc_macro(cx, attr) diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs index 788377fe83c..5bf077990e1 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs @@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use rustc_ast::{MetaItemInner, MetaItemKind}; use rustc_lint::{EarlyContext, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_span::sym; use rustc_span::symbol::Symbol; @@ -17,7 +16,7 @@ pub(super) fn check<'cx>(cx: &EarlyContext<'cx>, name: Symbol, items: &[MetaItem } // Check if the attribute is in an external macro and therefore out of the developer's control - if in_external_macro(cx.sess(), attr.span) || is_from_proc_macro(cx, attr) { + if attr.span.in_external_macro(cx.sess().source_map()) || is_from_proc_macro(cx, attr) { return; } diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs index e7158a6a6b6..e3e081ce08e 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs @@ -5,14 +5,13 @@ use clippy_utils::source::{SpanRangeExt, first_line_of_span}; use rustc_ast::{Attribute, Item, ItemKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_span::sym; pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { let skip_unused_imports = attrs.iter().any(|attr| attr.has_name(sym::macro_use)); for attr in attrs { - if in_external_macro(cx.sess(), attr.span) { + if attr.span.in_external_macro(cx.sess().source_map()) { return; } if let Some(lint_list) = &attr.meta_item_list() { diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs index eb05dc96cde..aab0af0d743 100644 --- a/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs +++ b/src/tools/clippy/clippy_lints/src/blocks_in_conditions.rs @@ -4,7 +4,6 @@ use clippy_utils::{higher, is_from_proc_macro}; use rustc_errors::Applicability; use rustc_hir::{BlockCheckMode, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; declare_clippy_lint! { @@ -54,7 +53,7 @@ const BRACED_EXPR_MESSAGE: &str = "omit braces around single expression conditio impl<'tcx> LateLintPass<'tcx> for BlocksInConditions { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if in_external_macro(cx.sess(), expr.span) { + if expr.span.in_external_macro(cx.sess().source_map()) { return; } diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs index 79fd6ffe46c..3b861848f94 100644 --- a/src/tools/clippy/clippy_lints/src/box_default.rs +++ b/src/tools/clippy/clippy_lints/src/box_default.rs @@ -7,7 +7,6 @@ use rustc_hir::def::Res; use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty}; use rustc_hir::{AmbigArg, Block, Expr, ExprKind, HirId, LetStmt, Node, QPath, Ty, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; use rustc_span::{Span, sym}; @@ -50,7 +49,7 @@ impl LateLintPass<'_> for BoxDefault { // This is the `T::default()` (or default equivalent) of `Box::new(T::default())` && let ExprKind::Call(arg_path, _) = arg.kind // And we are not in a foreign crate's macro - && !in_external_macro(cx.sess(), expr.span) + && !expr.span.in_external_macro(cx.sess().source_map()) // And the argument expression has the same context as the outer call expression // or that we are inside a `vec!` macro expansion && (expr.span.eq_ctxt(arg.span) || is_local_vec_expn(cx, arg, expr)) diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs index d90cf124fe4..521bd394901 100644 --- a/src/tools/clippy/clippy_lints/src/casts/mod.rs +++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs @@ -29,7 +29,6 @@ use clippy_utils::is_hir_ty_cfg_dependant; use clippy_utils::msrvs::{self, Msrv}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; declare_clippy_lint! { @@ -796,7 +795,7 @@ impl_lint_pass!(Casts => [ impl<'tcx> LateLintPass<'tcx> for Casts { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if in_external_macro(cx.sess(), expr.span) { + if expr.span.in_external_macro(cx.sess().source_map()) { return; } diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs index 9e1876e40f9..7885f171461 100644 --- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs @@ -8,7 +8,6 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind, Lit, Node, Path, QPath, TyKind, UnOp}; use rustc_lint::{LateContext, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, FloatTy, InferTy, Ty}; use std::ops::ControlFlow; @@ -142,7 +141,7 @@ pub(super) fn check<'tcx>( } } - if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) { + if cast_from.kind() == cast_to.kind() && !expr.span.in_external_macro(cx.sess().source_map()) { if let Some(id) = path_to_local(cast_expr) && !cx.tcx.hir().span(id).eq_ctxt(cast_expr.span) { diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs index 1edfde97422..9516af7334d 100644 --- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs @@ -6,7 +6,6 @@ use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; declare_clippy_lint! { @@ -64,7 +63,7 @@ impl LateLintPass<'_> for CheckedConversions { }, _ => return, } - && !in_external_macro(cx.sess(), item.span) + && !item.span.in_external_macro(cx.sess().source_map()) && !is_in_const_context(cx) && self.msrv.meets(msrvs::TRY_FROM) && let Some(cv) = match op2 { diff --git a/src/tools/clippy/clippy_lints/src/ctfe.rs b/src/tools/clippy/clippy_lints/src/ctfe.rs index 589b99518a0..7bae04a10f1 100644 --- a/src/tools/clippy/clippy_lints/src/ctfe.rs +++ b/src/tools/clippy/clippy_lints/src/ctfe.rs @@ -21,6 +21,6 @@ impl<'tcx> LateLintPass<'tcx> for ClippyCtfe { _: Span, defid: LocalDefId, ) { - cx.tcx.ensure().mir_drops_elaborated_and_const_checked(defid); // Lint + cx.tcx.ensure_ok().mir_drops_elaborated_and_const_checked(defid); // Lint } } diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs index a96c86f0765..06376c57119 100644 --- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs +++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs @@ -7,7 +7,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::{Span, SyntaxContext, sym}; @@ -60,7 +59,7 @@ impl LateLintPass<'_> for DbgMacro { if cur_syntax_ctxt != self.prev_ctxt && let Some(macro_call) = first_dbg_macro_in_expansion(cx, expr.span) && - !in_external_macro(cx.sess(), macro_call.span) && + !macro_call.span.in_external_macro(cx.sess().source_map()) && self.checked_dbg_call_site.insert(macro_call.span) && // allows `dbg!` in test code if allow-dbg-in-test is set to true in clippy.toml !(self.allow_dbg_in_tests && is_in_test(cx.tcx, expr.hir_id)) diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index ca3eaae7b85..772268e7899 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -9,7 +9,6 @@ use rustc_hir::{ StructTailExpr, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty}; use rustc_session::declare_lint_pass; use std::iter; @@ -86,7 +85,7 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> { /// Check whether a passed literal has potential to cause fallback or not. fn check_lit(&self, lit: &Lit, lit_ty: Ty<'tcx>, emit_hir_id: HirId) { - if !in_external_macro(self.cx.sess(), lit.span) + if !lit.span.in_external_macro(self.cx.sess().source_map()) && matches!(self.ty_bounds.last(), Some(ExplicitTyBound(false))) && matches!( lit.node, diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index 15530c3dbc5..3d8ce7becdb 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -22,7 +22,6 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AnonConst, Attribute, Expr, ImplItemKind, ItemKind, Node, Safety, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_resolve::rustdoc::{ DocFragment, add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range, @@ -675,7 +674,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation { match item.kind { ItemKind::Fn { sig, body: body_id, .. } => { if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) - || in_external_macro(cx.tcx.sess, item.span)) + || item.span.in_external_macro(cx.tcx.sess.source_map())) { let body = cx.tcx.hir().body(body_id); @@ -711,7 +710,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation { }, Node::TraitItem(trait_item) => { if let TraitItemKind::Fn(sig, ..) = trait_item.kind - && !in_external_macro(cx.tcx.sess, trait_item.span) + && !trait_item.span.in_external_macro(cx.tcx.sess.source_map()) { missing_headers::check( cx, @@ -726,7 +725,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation { }, Node::ImplItem(impl_item) => { if let ImplItemKind::Fn(sig, body_id) = impl_item.kind - && !in_external_macro(cx.tcx.sess, impl_item.span) + && !impl_item.span.in_external_macro(cx.tcx.sess.source_map()) && !is_trait_impl_item(cx, impl_item.hir_id()) { let body = cx.tcx.hir().body(body_id); @@ -791,7 +790,7 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[ let (fragments, _) = attrs_to_doc_fragments( attrs.iter().filter_map(|attr| { - if in_external_macro(cx.sess(), attr.span) { + if attr.span.in_external_macro(cx.sess().source_map()) { None } else { Some((attr, None)) diff --git a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs index 5315f55ba38..a38e853172f 100644 --- a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs +++ b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::ast::{Expr, ExprKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; declare_clippy_lint! { @@ -50,7 +49,7 @@ impl EarlyLintPass for ElseIfWithoutElse { fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) { if let ExprKind::If(_, _, Some(ref els)) = item.kind && let ExprKind::If(_, _, None) = els.kind - && !in_external_macro(cx.sess(), item.span) + && !item.span.in_external_macro(cx.sess().source_map()) { #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/endian_bytes.rs b/src/tools/clippy/clippy_lints/src/endian_bytes.rs index 209104c5385..29deaaf3bc7 100644 --- a/src/tools/clippy/clippy_lints/src/endian_bytes.rs +++ b/src/tools/clippy/clippy_lints/src/endian_bytes.rs @@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_lint_allowed; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::Ty; use rustc_session::declare_lint_pass; use rustc_span::Symbol; @@ -119,7 +118,7 @@ impl LateLintPass<'_> for EndianBytes { }, _ => return, }; - if !in_external_macro(cx.sess(), expr.span) + if !expr.span.in_external_macro(cx.sess().source_map()) && let ty = cx.typeck_results().expr_ty(ty_expr) && ty.is_primitive_ty() { diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs index 7ca2c953699..cd9ab2764ac 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -4,7 +4,6 @@ use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::Ty; use rustc_session::declare_lint_pass; @@ -72,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let ExprKind::Let(let_expr) = expr.kind && unary_pattern(let_expr.pat) - && !in_external_macro(cx.sess(), expr.span) + && !expr.span.in_external_macro(cx.sess().source_map()) { let exp_ty = cx.typeck_results().expr_ty(let_expr.init); let pat_ty = cx.typeck_results().pat_ty(let_expr.pat); diff --git a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs index dfea40db182..36567b3ded0 100644 --- a/src/tools/clippy/clippy_lints/src/excessive_nesting.rs +++ b/src/tools/clippy/clippy_lints/src/excessive_nesting.rs @@ -5,7 +5,6 @@ use rustc_ast::node_id::NodeSet; use rustc_ast::visit::{Visitor, walk_block, walk_item}; use rustc_ast::{Block, Crate, Inline, Item, ItemKind, ModKind, NodeId}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::Span; @@ -125,7 +124,7 @@ struct NestingVisitor<'conf, 'cx> { impl NestingVisitor<'_, '_> { fn check_indent(&mut self, span: Span, id: NodeId) -> bool { - if self.nest_level > self.conf.excessive_nesting_threshold && !in_external_macro(self.cx.sess(), span) { + if self.nest_level > self.conf.excessive_nesting_threshold && !span.in_external_macro(self.cx.sess().source_map()) { self.conf.nodes.insert(id); return true; diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs index cdbfe7af8f9..5d93aceb33f 100644 --- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs +++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs @@ -10,7 +10,6 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::Span; use rustc_span::def_id::{DefId, LocalDefId}; @@ -261,7 +260,7 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters { && !generics.params.is_empty() && !is_empty_body(cx, body_id) && (!self.avoid_breaking_exported_api || !cx.effective_visibilities.is_exported(item.owner_id.def_id)) - && !in_external_macro(cx.sess(), item.span) + && !item.span.in_external_macro(cx.sess().source_map()) && !is_from_proc_macro(cx, item) { let mut walker = TypeWalker::new(cx, generics); @@ -277,7 +276,7 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters { && trait_ref_of_method(cx, item.owner_id.def_id).is_none() && !is_empty_body(cx, body_id) && (!self.avoid_breaking_exported_api || !cx.effective_visibilities.is_exported(item.owner_id.def_id)) - && !in_external_macro(cx.sess(), item.span) + && !item.span.in_external_macro(cx.sess().source_map()) && !is_from_proc_macro(cx, item) { let mut walker = TypeWalker::new(cx, item.generics); diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs index 34e93bdb9b9..c8fe7ac73cb 100644 --- a/src/tools/clippy/clippy_lints/src/formatting.rs +++ b/src/tools/clippy/clippy_lints/src/formatting.rs @@ -3,7 +3,6 @@ use clippy_utils::is_span_if; use clippy_utils::source::snippet_opt; use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; use rustc_span::Span; @@ -202,7 +201,7 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::If(_, then, Some(else_)) = &expr.kind && (is_block(else_) || is_if(else_)) && !then.span.from_expansion() && !else_.span.from_expansion() - && !in_external_macro(cx.sess(), expr.span) + && !expr.span.in_external_macro(cx.sess().source_map()) // workaround for rust-lang/rust#43081 && expr.span.lo().0 != 0 && expr.span.hi().0 != 0 diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index 90d3db2700f..e480805cac2 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -5,7 +5,6 @@ use rustc_hir::def_id::DefIdSet; use rustc_hir::{self as hir, Attribute, QPath}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_span::{Span, sym}; @@ -107,7 +106,7 @@ fn check_needless_must_use( attrs: &[Attribute], sig: &FnSig<'_>, ) { - if in_external_macro(cx.sess(), item_span) { + if item_span.in_external_macro(cx.sess().source_map()) { return; } if returns_unit(decl) { @@ -185,7 +184,7 @@ fn check_must_use_candidate<'tcx>( ) { if has_mutable_arg(cx, body) || mutates_static(cx, body) - || in_external_macro(cx.sess(), item_span) + || item_span.in_external_macro(cx.sess().source_map()) || returns_unit(decl) || !cx.effective_visibilities.is_exported(item_id.def_id) || is_must_use_ty(cx, return_ty(cx, item_id)) diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs index 9c396986f62..74d365a7255 100644 --- a/src/tools/clippy/clippy_lints/src/functions/result.rs +++ b/src/tools/clippy/clippy_lints/src/functions/result.rs @@ -2,7 +2,6 @@ use clippy_utils::msrvs::{self, Msrv}; use rustc_errors::Diag; use rustc_hir as hir; use rustc_lint::{LateContext, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_span::{Span, sym}; @@ -20,7 +19,7 @@ fn result_err_ty<'tcx>( id: hir::def_id::LocalDefId, item_span: Span, ) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> { - if !in_external_macro(cx.sess(), item_span) + if !item_span.in_external_macro(cx.sess().source_map()) && let hir::FnRetTy::Return(hir_ty) = decl.output && let ty = cx .tcx diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs index 0f5ce340c44..4f90d9655b4 100644 --- a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs +++ b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs @@ -3,7 +3,6 @@ use clippy_utils::source::SpanRangeExt; use rustc_hir as hir; use rustc_hir::intravisit::FnKind; use rustc_lint::{LateContext, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_span::Span; use super::TOO_MANY_LINES; @@ -17,7 +16,7 @@ pub(super) fn check_fn( ) { // Closures must be contained in a parent body, which will be checked for `too_many_lines`. // Don't check closures for `too_many_lines` to avoid duplicated lints. - if matches!(kind, FnKind::Closure) || in_external_macro(cx.sess(), span) { + if matches!(kind, FnKind::Closure) || span.in_external_macro(cx.sess().source_map()) { return; } diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs index 3fc0a696522..51e2944e6f9 100644 --- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs +++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs @@ -11,7 +11,6 @@ use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; declare_clippy_lint! { @@ -79,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { && is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone) && !is_else_clause(cx.tcx, expr) && !is_in_const_context(cx) - && !in_external_macro(cx.sess(), expr.span) + && !expr.span.in_external_macro(cx.sess().source_map()) && self.msrv.meets(msrvs::BOOL_THEN) && !contains_return(then_block.stmts) { diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs index ba06567b957..5f95464e4d4 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_return.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs @@ -7,7 +7,6 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, SyntaxContext}; @@ -227,7 +226,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn { ) { if (!matches!(kind, FnKind::Closure) && matches!(decl.output, FnRetTy::DefaultReturn(_))) || !span.eq_ctxt(body.value.span) - || in_external_macro(cx.sess(), span) + || span.in_external_macro(cx.sess().source_map()) { return; } diff --git a/src/tools/clippy/clippy_lints/src/items_after_statements.rs b/src/tools/clippy/clippy_lints/src/items_after_statements.rs index 4f066113aea..f5ad79a0027 100644 --- a/src/tools/clippy/clippy_lints/src/items_after_statements.rs +++ b/src/tools/clippy/clippy_lints/src/items_after_statements.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_hir; use rustc_hir::{Block, ItemKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; declare_clippy_lint! { @@ -70,7 +69,7 @@ impl LateLintPass<'_> for ItemsAfterStatements { // Don't use `next` due to the complex filter chain. .for_each(|item| { // Only do the macro check once, but delay it until it's needed. - if !*in_external.get_or_insert_with(|| in_external_macro(cx.sess(), block.span)) { + if !*in_external.get_or_insert_with(|| block.span.in_external_macro(cx.sess().source_map())) { span_lint_hir( cx, ITEMS_AFTER_STATEMENTS, diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs index 906da81b183..238f66d6675 100644 --- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs +++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs @@ -6,7 +6,6 @@ use rustc_ast::Mutability; use rustc_errors::Applicability; use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; use rustc_span::sym; @@ -131,7 +130,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter { && trait_ref .trait_def_id() .is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did)) - && !in_external_macro(cx.sess(), item.span) + && !item.span.in_external_macro(cx.sess().source_map()) && let &ty::Ref(_, ty, mtbl) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind() && let expected_method_name = match mtbl { Mutability::Mut => sym::iter_mut, @@ -193,7 +192,7 @@ impl {self_ty_without_ref} {{ _ => return, }; - if !in_external_macro(cx.sess(), item.span) + if !item.span.in_external_macro(cx.sess().source_map()) && let ImplItemKind::Fn(sig, _) = item.kind && let FnRetTy::Return(ret) = sig.decl.output && is_nameable_in_impl_trait(ret) diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs index 623b6b4fcc1..cabf10b7e0e 100644 --- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs @@ -56,9 +56,8 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { && !item.span.from_expansion() && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() && let ty::Array(element_type, cst) = ty.kind() - && let Some((ty::ValTree::Leaf(element_count), _)) = cx.tcx - .try_normalize_erasing_regions(cx.typing_env(), *cst).unwrap_or(*cst).try_to_valtree() - && let element_count = element_count.to_target_usize(cx.tcx) + && let Some(element_count) = cx.tcx + .try_normalize_erasing_regions(cx.typing_env(), *cst).unwrap_or(*cst).try_to_target_usize(cx.tcx) && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size) { diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs index 923089c7223..d9953dbc261 100644 --- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs +++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs @@ -5,7 +5,6 @@ use clippy_utils::ty::{AdtVariantInfo, approx_ty_size, is_copy}; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; use rustc_span::Span; @@ -78,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() && let ty::Adt(adt, subst) = ty.kind() && adt.variants().len() > 1 - && !in_external_macro(cx.tcx.sess, item.span) + && !item.span.in_external_macro(cx.tcx.sess.source_map()) { let variants_size = AdtVariantInfo::new(cx, *adt, subst); diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs index 46d7df6995a..6f5c5d6b3ea 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs @@ -8,7 +8,7 @@ use clippy_utils::source::snippet; use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::{self, ConstKind}; +use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::{Span, sym}; @@ -81,8 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { && let ExprKind::Repeat(_, _) | ExprKind::Array(_) = expr.kind && !self.is_from_vec_macro(cx, expr.span) && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind() - && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind() - && let element_count = element_count.to_target_usize(cx.tcx) + && let Some(element_count) = cst.try_to_target_usize(cx.tcx) && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) && !cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, node)| { matches!( diff --git a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs index fb46bdcab6e..6f2ce04e8f8 100644 --- a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs +++ b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs @@ -7,7 +7,6 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::{ExprKind, Item, ItemKind, QPath, UseKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; use rustc_span::{Symbol, sym}; @@ -54,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { // so lint on the `use` statement directly. if let ItemKind::Use(path, kind @ (UseKind::Single | UseKind::Glob)) = item.kind && self.msrv.meets(msrvs::NUMERIC_ASSOCIATED_CONSTANTS) - && !in_external_macro(cx.sess(), item.span) + && !item.span.in_external_macro(cx.sess().source_map()) && let Some(def_id) = path.res[0].opt_def_id() { let module = if is_integer_module(cx, def_id) { @@ -139,7 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { }; if self.msrv.meets(msrvs::NUMERIC_ASSOCIATED_CONSTANTS) - && !in_external_macro(cx.sess(), expr.span) + && !expr.span.in_external_macro(cx.sess().source_map()) && !is_from_proc_macro(cx, expr) { span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| { diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs index b522c22a44d..bdbf5b37c5f 100644 --- a/src/tools/clippy/clippy_lints/src/let_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs @@ -3,7 +3,6 @@ use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type}; use clippy_utils::{is_from_proc_macro, is_must_use_func_call, paths}; use rustc_hir::{LetStmt, LocalSource, PatKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{GenericArgKind, IsSuggestable}; use rustc_session::declare_lint_pass; use rustc_span::{BytePos, Span}; @@ -141,7 +140,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { if matches!(local.source, LocalSource::Normal) && let PatKind::Wild = local.pat.kind && let Some(init) = local.init - && !in_external_macro(cx.tcx.sess, local.span) + && !local.span.in_external_macro(cx.tcx.sess.source_map()) { let init_ty = cx.typeck_results().expr_ty(init); let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() { diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs index 34ded6c6500..9c8488ff381 100644 --- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::is_from_proc_macro; use rustc_hir::{LetStmt, TyKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; declare_clippy_lint! { @@ -30,7 +29,7 @@ impl<'tcx> LateLintPass<'tcx> for UnderscoreTyped { if let Some(ty) = local.ty // Ensure that it has a type defined && let TyKind::Infer(()) = &ty.kind // that type is '_' && local.span.eq_ctxt(ty.span) - && !in_external_macro(cx.tcx.sess, local.span) + && !local.span.in_external_macro(cx.tcx.sess.source_map()) && !is_from_proc_macro(cx, ty) { span_lint_and_help( diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index c9ab0beb5df..860c0584acc 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -21,7 +21,6 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter as middle_nested_filter; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::Span; use rustc_span::def_id::LocalDefId; @@ -164,7 +163,7 @@ fn check_fn_inner<'tcx>( report_extra_lifetimes: bool, msrv: &Msrv, ) { - if in_external_macro(cx.sess(), span) || has_where_lifetimes(cx, generics) { + if span.in_external_macro(cx.sess().source_map()) || has_where_lifetimes(cx, generics) { return; } diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs index a4cedf3bed3..805de23408b 100644 --- a/src/tools/clippy/clippy_lints/src/literal_representation.rs +++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs @@ -6,7 +6,6 @@ use rustc_ast::ast::{Expr, ExprKind, LitKind}; use rustc_ast::token; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::Span; use std::iter; @@ -207,7 +206,7 @@ impl_lint_pass!(LiteralDigitGrouping => [ impl EarlyLintPass for LiteralDigitGrouping { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::Lit(lit) = expr.kind - && !in_external_macro(cx.sess(), expr.span) + && !expr.span.in_external_macro(cx.sess().source_map()) { self.check_lit(cx, lit, expr.span); } @@ -421,7 +420,7 @@ impl_lint_pass!(DecimalLiteralRepresentation => [DECIMAL_LITERAL_REPRESENTATION] impl EarlyLintPass for DecimalLiteralRepresentation { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::Lit(lit) = expr.kind - && !in_external_macro(cx.sess(), expr.span) + && !expr.span.in_external_macro(cx.sess().source_map()) { self.check_lit(cx, lit, expr.span); } diff --git a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs index 6be30f3c957..4d206850c99 100644 --- a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs @@ -6,7 +6,6 @@ use rustc_ast::Label; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_span::sym; use super::INFINITE_LOOP; @@ -30,7 +29,7 @@ pub(super) fn check<'tcx>( return; } - if in_external_macro(cx.sess(), expr.span) || is_from_proc_macro(cx, expr) { + if expr.span.in_external_macro(cx.sess().source_map()) || is_from_proc_macro(cx, expr) { return; } 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 a1951b9da44..052e6502da9 100644 --- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs +++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs @@ -9,7 +9,6 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::{BinOpKind, Constness, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; @@ -142,7 +141,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { // 16 possible alignments of constants/operands. For now, let's use `partition`. && let mut exprs = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs] && exprs.iter_mut().partition_in_place(|i| path_to_local(i).is_some()) == 2 - && !in_external_macro(cx.sess(), expr.span) + && !expr.span.in_external_macro(cx.sess().source_map()) && ( is_not_const(cx.tcx, cx.tcx.hir().enclosing_body_owner(expr.hir_id).into()) || self.msrv.meets(msrvs::CONST_FLOAT_CLASSIFY) diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs index 274785061b3..3643b8c4425 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -9,7 +9,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_span::Span; use rustc_span::symbol::{Symbol, sym}; @@ -55,7 +54,7 @@ impl<'tcx> QuestionMark { && init.span.eq_ctxt(stmt.span) && let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init) && self.msrv.meets(msrvs::LET_ELSE) - && !in_external_macro(cx.sess(), stmt.span) + && !stmt.span.in_external_macro(cx.sess().source_map()) { match if_let_or_match { IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else, ..) => { diff --git a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs index 2e5a92915d9..bf4f2bff319 100644 --- a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs @@ -5,7 +5,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::{PatExpr, PatExprKind, PatKind, RangeEnd}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; use rustc_span::{DUMMY_SP, Span}; @@ -80,7 +79,7 @@ impl LateLintPass<'_> for ManualRangePatterns { // like described https://github.com/rust-lang/rust-clippy/issues/11825) if let PatKind::Or(pats) = pat.kind && (pats.len() >= 3 || (pats.len() > 1 && pats.iter().any(|p| matches!(p.kind, PatKind::Range(..))))) - && !in_external_macro(cx.sess(), pat.span) + && !pat.span.in_external_macro(cx.sess().source_map()) { let mut min = Num::dummy(i128::MAX); let mut max = Num::dummy(i128::MIN); diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs index 8aeec89f0bf..469b4b7cf89 100644 --- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs +++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs @@ -7,7 +7,6 @@ use clippy_utils::{is_in_const_context, path_to_local}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; declare_clippy_lint! { @@ -60,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { && rem_rhs.span.ctxt() == ctxt && add_lhs.span.ctxt() == ctxt && add_rhs.span.ctxt() == ctxt - && !in_external_macro(cx.sess(), expr.span) + && !expr.span.in_external_macro(cx.sess().source_map()) && self.msrv.meets(msrvs::REM_EUCLID) && (self.msrv.meets(msrvs::REM_EUCLID_CONST) || !is_in_const_context(cx)) && let Some(const1) = check_for_unsigned_int_constant(cx, rem_rhs) diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index a7fdd483c16..9ca914af281 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -33,7 +33,6 @@ use clippy_utils::{ }; use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::{SpanData, SyntaxContext}; @@ -1054,7 +1053,7 @@ impl_lint_pass!(Matches => [ impl<'tcx> LateLintPass<'tcx> for Matches { #[expect(clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if is_direct_expn_of(expr.span, "matches").is_none() && in_external_macro(cx.sess(), expr.span) { + if is_direct_expn_of(expr.span, "matches").is_none() && expr.span.in_external_macro(cx.sess().source_map()) { return; } let from_expansion = expr.span.from_expansion(); diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs index 5597cd85abc..41528c5dee3 100644 --- a/src/tools/clippy/clippy_lints/src/mem_replace.rs +++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs @@ -11,7 +11,6 @@ use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::Span; use rustc_span::symbol::sym; @@ -188,7 +187,7 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr< if is_non_aggregate_primitive_type(expr_type) { return; } - if is_default_equivalent(cx, src) && !in_external_macro(cx.tcx.sess, expr_span) { + if is_default_equivalent(cx, src) && !expr_span.in_external_macro(cx.tcx.sess.source_map()) { let Some(top_crate) = std_or_core(cx) else { return }; span_lint_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs index 129e6925428..d550c145466 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs @@ -6,13 +6,12 @@ use clippy_utils::{is_from_proc_macro, is_trait_method, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::Binder; use rustc_middle::ty::adjustment::Adjust; use rustc_span::{Span, sym}; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &Expr<'_>, call_span: Span) { - if !in_external_macro(cx.sess(), expr.span) + if !expr.span.in_external_macro(cx.sess().source_map()) && is_trait_method(cx, expr, sym::Iterator) && let ExprKind::Closure(closure) = arg.kind && let body = cx.tcx.hir().body(closure.body) diff --git a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs index a0c21faaa4c..92c81b3c49d 100644 --- a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs +++ b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs @@ -4,7 +4,6 @@ use clippy_utils::macros::{is_assert_macro, root_macro_call}; use clippy_utils::{find_binding_init, get_parent_expr, is_inside_always_const_context, path_to_local}; use rustc_hir::{Expr, HirId}; use rustc_lint::{LateContext, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_span::sym; use super::CONST_IS_EMPTY; @@ -12,7 +11,7 @@ use super::CONST_IS_EMPTY; /// Expression whose initialization depend on a constant conditioned by a `#[cfg(…)]` directive will /// not trigger the lint. pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_>) { - if in_external_macro(cx.sess(), expr.span) || !receiver.span.eq_ctxt(expr.span) { + if expr.span.in_external_macro(cx.sess().source_map()) || !receiver.span.eq_ctxt(expr.span) { return; } if let Some(parent) = get_parent_expr(cx, expr) { diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs index 4a48d4b547c..a56378b5b73 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs @@ -7,7 +7,6 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_span::{Span, sym}; use super::MANUAL_TRY_FOLD; @@ -20,7 +19,7 @@ pub(super) fn check<'tcx>( fold_span: Span, msrv: &Msrv, ) { - if !in_external_macro(cx.sess(), fold_span) + if !fold_span.in_external_macro(cx.sess().source_map()) && msrv.meets(msrvs::ITERATOR_TRY_FOLD) && is_trait_method(cx, expr, sym::Iterator) && let init_ty = cx.typeck_results().expr_ty(init) diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 42418318fda..2f447775fa5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -152,7 +152,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, TraitRef, Ty}; use rustc_session::impl_lint_pass; use rustc_span::{Span, sym}; @@ -4625,7 +4624,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { #[allow(clippy::too_many_lines)] fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { - if in_external_macro(cx.sess(), impl_item.span) { + if impl_item.span.in_external_macro(cx.sess().source_map()) { return; } let name = impl_item.ident.name.as_str(); @@ -4713,7 +4712,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { - if in_external_macro(cx.tcx.sess, item.span) { + if item.span.in_external_macro(cx.tcx.sess.source_map()) { return; } diff --git a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs index a99e21d938c..4119b1d1051 100644 --- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs +++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs @@ -6,7 +6,6 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{Visitor, walk_item, walk_trait_item}; use rustc_hir::{GenericParamKind, HirId, Item, ItemKind, ItemLocalId, Node, Pat, PatKind, TraitItem, UsePath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::Span; use std::borrow::Cow; @@ -55,7 +54,7 @@ impl MinIdentChars { #[expect(clippy::cast_possible_truncation)] fn is_ident_too_short(&self, cx: &LateContext<'_>, str: &str, span: Span) -> bool { - !in_external_macro(cx.sess(), span) + !span.in_external_macro(cx.sess().source_map()) && str.len() <= self.min_ident_chars_threshold as usize && !str.starts_with('_') && !str.is_empty() diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index b511b1e46b3..fa0eb9a94b7 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -13,7 +13,6 @@ use rustc_hir::{ BinOpKind, BindingMode, Body, ByRef, Expr, ExprKind, FnDecl, Mutability, PatKind, QPath, Stmt, StmtKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; use rustc_span::Span; use rustc_span::def_id::LocalDefId; @@ -162,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { for arg in iter_input_pats(decl, body) { if let PatKind::Binding(BindingMode(ByRef::Yes(_), _), ..) = arg.pat.kind && is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id) - && !in_external_macro(cx.tcx.sess, arg.span) + && !arg.span.in_external_macro(cx.tcx.sess.source_map()) { span_lint_hir( cx, @@ -183,7 +182,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { && let Some(init) = local.init // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue. && is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id) - && !in_external_macro(cx.tcx.sess, stmt.span) + && !stmt.span.in_external_macro(cx.tcx.sess.source_map()) { let ctxt = local.span.ctxt(); let mut app = Applicability::MachineApplicable; @@ -239,7 +238,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if in_external_macro(cx.sess(), expr.span) + if expr.span.in_external_macro(cx.sess().source_map()) || expr.span.desugaring_kind().is_some() || in_automatically_derived(cx.tcx, expr.hir_id) { diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs index 637d6ed3ad2..f880f1f329f 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs @@ -14,7 +14,6 @@ use rustc_ast::token; use rustc_ast::visit::FnKind; use rustc_data_structures::fx::FxHashMap; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; use rustc_span::Span; @@ -350,7 +349,7 @@ impl EarlyLintPass for MiscEarlyLints { } fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) { - if in_external_macro(cx.sess(), pat.span) { + if pat.span.in_external_macro(cx.sess().source_map()) { return; } @@ -387,7 +386,7 @@ impl EarlyLintPass for MiscEarlyLints { } fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if in_external_macro(cx.sess(), expr.span) { + if expr.span.in_external_macro(cx.sess().source_map()) { return; } diff --git a/src/tools/clippy/clippy_lints/src/misc_early/redundant_at_rest_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/redundant_at_rest_pattern.rs index 0c81ee5eced..f2cf93465c0 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/redundant_at_rest_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/redundant_at_rest_pattern.rs @@ -2,12 +2,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast::{Pat, PatKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, LintContext}; -use rustc_middle::lint::in_external_macro; use super::REDUNDANT_AT_REST_PATTERN; pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { - if !in_external_macro(cx.sess(), pat.span) + if !pat.span.in_external_macro(cx.sess().source_map()) && let PatKind::Slice(slice) = &pat.kind && let [one] = &**slice && let PatKind::Ident(annotation, ident, Some(rest)) = &one.kind diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index 2572e186ce6..962d85c6a9d 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -8,7 +8,6 @@ use rustc_hir::def_id::CRATE_DEF_ID; use rustc_hir::intravisit::FnKind; use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::Span; @@ -106,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { return; } - if in_external_macro(cx.tcx.sess, span) || is_entrypoint_fn(cx, def_id.to_def_id()) { + if span.in_external_macro(cx.tcx.sess.source_map()) || is_entrypoint_fn(cx, def_id.to_def_id()) { return; } diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index bba1b63be27..18385ac9269 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -88,7 +88,7 @@ declare_lint_pass!(MissingInline => [MISSING_INLINE_IN_PUBLIC_ITEMS]); impl<'tcx> LateLintPass<'tcx> for MissingInline { fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) { - if rustc_middle::lint::in_external_macro(cx.sess(), it.span) || is_executable_or_proc_macro(cx) { + if it.span.in_external_macro(cx.sess().source_map()) || is_executable_or_proc_macro(cx) { return; } @@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { - if rustc_middle::lint::in_external_macro(cx.sess(), impl_item.span) || is_executable_or_proc_macro(cx) { + if impl_item.span.in_external_macro(cx.sess().source_map()) || is_executable_or_proc_macro(cx) { return; } diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs index aad6ae52a6d..302db2c914c 100644 --- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs +++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs @@ -6,7 +6,6 @@ use hir::{BlockCheckMode, ExprKind, QPath, UnOp}; use rustc_ast::Mutability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::declare_lint_pass; use rustc_span::{DesugaringKind, Span}; @@ -65,7 +64,7 @@ declare_lint_pass!(MultipleUnsafeOpsPerBlock => [MULTIPLE_UNSAFE_OPS_PER_BLOCK]) impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) { if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) - || in_external_macro(cx.tcx.sess, block.span) + || block.span.in_external_macro(cx.tcx.sess.source_map()) || block.span.is_desugaring(DesugaringKind::Await) { return; diff --git a/src/tools/clippy/clippy_lints/src/mut_mut.rs b/src/tools/clippy/clippy_lints/src/mut_mut.rs index 0ee851a4cf9..3c4ba5141dd 100644 --- a/src/tools/clippy/clippy_lints/src/mut_mut.rs +++ b/src/tools/clippy/clippy_lints/src/mut_mut.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_hir}; use clippy_utils::higher; use rustc_hir::{self as hir, AmbigArg, intravisit}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::declare_lint_pass; @@ -38,7 +37,7 @@ impl<'tcx> LateLintPass<'tcx> for MutMut { && mty.mutbl == hir::Mutability::Mut && let hir::TyKind::Ref(_, mty) = mty.ty.kind && mty.mutbl == hir::Mutability::Mut - && !in_external_macro(cx.sess(), ty.span) + && !ty.span.in_external_macro(cx.sess().source_map()) { span_lint( cx, @@ -56,7 +55,7 @@ pub struct MutVisitor<'a, 'tcx> { impl<'tcx> intravisit::Visitor<'tcx> for MutVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) { - if in_external_macro(self.cx.sess(), expr.span) { + if expr.span.in_external_macro(self.cx.sess().source_map()) { return; } diff --git a/src/tools/clippy/clippy_lints/src/needless_if.rs b/src/tools/clippy/clippy_lints/src/needless_if.rs index 8e14fbf2f80..7eefb016aca 100644 --- a/src/tools/clippy/clippy_lints/src/needless_if.rs +++ b/src/tools/clippy/clippy_lints/src/needless_if.rs @@ -5,7 +5,6 @@ use clippy_utils::source::SpanRangeExt; use rustc_errors::Applicability; use rustc_hir::{ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; declare_clippy_lint! { @@ -47,7 +46,7 @@ impl LateLintPass<'_> for NeedlessIf { && let ExprKind::Block(block, ..) = then.kind && block.stmts.is_empty() && block.expr.is_none() - && !in_external_macro(cx.sess(), expr.span) + && !expr.span.in_external_macro(cx.sess().source_map()) && then.span.check_source_text(cx, |src| { // Ignore // - empty macro expansions diff --git a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index fa90ee60612..4f62ba2e58d 100644 --- a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::implements_trait; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; use rustc_span::sym; @@ -48,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd { if let ExprKind::Unary(UnOp::Not, inner) = expr.kind && let ExprKind::Binary(ref op, left, _) = inner.kind && let BinOpKind::Le | BinOpKind::Ge | BinOpKind::Lt | BinOpKind::Gt = op.node - && !in_external_macro(cx.sess(), expr.span) + && !expr.span.in_external_macro(cx.sess().source_map()) { let ty = cx.typeck_results().expr_ty(left); diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs index 688374b5676..cc56df3a23d 100644 --- a/src/tools/clippy/clippy_lints/src/new_without_default.rs +++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs @@ -6,7 +6,6 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::HirIdSet; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::sym; @@ -69,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { for assoc_item in *items { if assoc_item.kind == (hir::AssocItemKind::Fn { has_self: false }) { let impl_item = cx.tcx.hir().impl_item(assoc_item.id); - if in_external_macro(cx.sess(), impl_item.span) { + if impl_item.span.in_external_macro(cx.sess().source_map()) { return; } if let hir::ImplItemKind::Fn(ref sig, _) = impl_item.kind { diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index ccd50758044..4d3e6aa79d0 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -12,7 +12,6 @@ use rustc_hir::{ }; use rustc_infer::infer::TyCtxtInferExt as _; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::Span; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; @@ -268,7 +267,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { if let StmtKind::Semi(expr) = stmt.kind - && !in_external_macro(cx.sess(), stmt.span) + && !stmt.span.in_external_macro(cx.sess().source_map()) && let ctxt = stmt.span.ctxt() && expr.span.ctxt() == ctxt && let Some(reduced) = reduce_expression(cx, expr) diff --git a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs index 94855c46567..dad1e8a3d6a 100644 --- a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs +++ b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs @@ -5,7 +5,6 @@ use rustc_errors::Applicability; use rustc_hir::def_id::LocalDefId; use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, LangItem, Node, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::EarlyBinder; use rustc_session::declare_lint_pass; use rustc_span::sym; @@ -129,7 +128,7 @@ impl LateLintPass<'_> for NonCanonicalImpls { let ExprKind::Block(block, ..) = body.value.kind else { return; }; - if in_external_macro(cx.sess(), block.span) || is_from_proc_macro(cx, impl_item) { + if block.span.in_external_macro(cx.sess().source_map()) || is_from_proc_macro(cx, impl_item) { return; } diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs index 56c4157d6fe..1a3b43cbb10 100644 --- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs +++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs @@ -5,7 +5,6 @@ use rustc_ast::ast::{ }; use rustc_ast::visit::{Visitor, walk_block, walk_expr, walk_pat}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{Span, sym}; @@ -381,7 +380,7 @@ impl<'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'_, 'tcx> { impl EarlyLintPass for NonExpressiveNames { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if in_external_macro(cx.sess(), item.span) { + if item.span.in_external_macro(cx.sess().source_map()) { return; } @@ -396,7 +395,7 @@ impl EarlyLintPass for NonExpressiveNames { } fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &AssocItem) { - if in_external_macro(cx.sess(), item.span) { + if item.span.in_external_macro(cx.sess().source_map()) { return; } diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs index 793eb5d9456..9542fed3875 100644 --- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -7,7 +7,6 @@ use rustc_ast::ImplPolarity; use rustc_hir::def_id::DefId; use rustc_hir::{FieldDef, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, GenericArgKind, Ty}; use rustc_session::impl_lint_pass; use rustc_span::sym; @@ -81,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy { // We start from `Send` impl instead of `check_field_def()` because // single `AdtDef` may have multiple `Send` impls due to generic // parameters, and the lint is much easier to implement in this way. - if !in_external_macro(cx.tcx.sess, item.span) + if !item.span.in_external_macro(cx.tcx.sess.source_map()) && let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send) && let ItemKind::Impl(hir_impl) = &item.kind && let Some(trait_ref) = &hir_impl.of_trait diff --git a/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs b/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs index 312610db042..22116505a1c 100644 --- a/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs +++ b/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs @@ -9,7 +9,6 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::{self as hir, BodyId, Expr, ExprKind, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::Span; @@ -139,7 +138,7 @@ impl<'hir> LateLintPass<'hir> for NonStdLazyStatic { return; } - if in_external_macro(cx.sess(), item.span) { + if item.span.in_external_macro(cx.sess().source_map()) { return; } diff --git a/src/tools/clippy/clippy_lints/src/octal_escapes.rs b/src/tools/clippy/clippy_lints/src/octal_escapes.rs index 2eae9b23746..6e7ee727965 100644 --- a/src/tools/clippy/clippy_lints/src/octal_escapes.rs +++ b/src/tools/clippy/clippy_lints/src/octal_escapes.rs @@ -4,7 +4,6 @@ use rustc_ast::token::LitKind; use rustc_ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; use rustc_span::{BytePos, Pos, SpanData}; @@ -59,7 +58,7 @@ impl EarlyLintPass for OctalEscapes { LitKind::ByteStr | LitKind::CStr => 2, _ => return, }) - && !in_external_macro(cx.sess(), expr.span) + && !expr.span.in_external_macro(cx.sess().source_map()) { let s = lit.symbol.as_str(); let mut iter = s.as_bytes().iter(); diff --git a/src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs b/src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs index 7f100a746d5..bc1821a48a3 100644 --- a/src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs +++ b/src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::eq_expr_value; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::declare_lint_pass; @@ -72,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for PanickingOverflowChecks { && matches!(ty.kind(), ty::Uint(_)) && ty == typeck.expr_ty(op_rhs) && ty == typeck.expr_ty(other) - && !in_external_macro(cx.tcx.sess, expr.span) + && !expr.span.in_external_macro(cx.tcx.sess.source_map()) && (eq_expr_value(cx, op_lhs, other) || (commutative && eq_expr_value(cx, op_rhs, other))) { span_lint( diff --git a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs index 668f09bbfd5..b653b459b04 100644 --- a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs +++ b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs @@ -7,7 +7,6 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPath, Stmt, StmtKind, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::{Span, Symbol, sym}; @@ -136,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for PathbufThenPush<'tcx> { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) { if let Some(init_expr) = local.init && let PatKind::Binding(BindingMode::MUT, id, name, None) = local.pat.kind - && !in_external_macro(cx.sess(), local.span) + && !local.span.in_external_macro(cx.sess().source_map()) && let ty = cx.typeck_results().pat_ty(local.pat) && is_type_diagnostic_item(cx, ty, sym::PathBuf) { @@ -157,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for PathbufThenPush<'tcx> { && let ExprKind::Path(QPath::Resolved(None, path)) = left.kind && let [name] = &path.segments && let Res::Local(id) = path.res - && !in_external_macro(cx.sess(), expr.span) + && !expr.span.in_external_macro(cx.sess().source_map()) && let ty = cx.typeck_results().expr_ty(left) && is_type_diagnostic_item(cx, ty, sym::PathBuf) { diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs index 42fbba8ef6d..8f1a1ee76c6 100644 --- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs @@ -3,7 +3,6 @@ use rustc_hir::{ Body, Expr, ExprKind, FnDecl, LetExpr, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind, intravisit, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::declare_lint_pass; use rustc_span::Span; @@ -84,7 +83,7 @@ declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]); impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if let StmtKind::Let(local) = stmt.kind { - if in_external_macro(cx.sess(), local.pat.span) { + if local.pat.span.in_external_macro(cx.sess().source_map()) { return; } let deref_possible = match local.source { @@ -171,7 +170,7 @@ fn find_first_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option<(Span, Mut if result.is_some() { return false; } - if in_external_macro(cx.sess(), p.span) { + if p.span.in_external_macro(cx.sess().source_map()) { return true; } let adjust_pat = match p.kind { diff --git a/src/tools/clippy/clippy_lints/src/raw_strings.rs b/src/tools/clippy/clippy_lints/src/raw_strings.rs index 23d0e768c2f..c6e6e782f9d 100644 --- a/src/tools/clippy/clippy_lints/src/raw_strings.rs +++ b/src/tools/clippy/clippy_lints/src/raw_strings.rs @@ -5,7 +5,6 @@ use rustc_ast::ast::{Expr, ExprKind}; use rustc_ast::token::LitKind; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Pos, Span}; use std::iter::once; @@ -72,7 +71,7 @@ impl RawStrings { impl EarlyLintPass for RawStrings { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::FormatArgs(format_args) = &expr.kind - && !in_external_macro(cx.sess(), format_args.span) + && !format_args.span.in_external_macro(cx.sess().source_map()) && format_args.span.check_source_text(cx, |src| src.starts_with('r')) && let Some(str) = snippet_opt(cx.sess(), format_args.span) && let count_hash = str.bytes().skip(1).take_while(|b| *b == b'#').count() @@ -95,7 +94,7 @@ impl EarlyLintPass for RawStrings { LitKind::CStrRaw(max) => ("cr", max), _ => return, } - && !in_external_macro(cx.sess(), expr.span) + && !expr.span.in_external_macro(cx.sess().source_map()) && expr.span.check_source_text(cx, |src| src.starts_with(prefix)) { self.check_raw_string(cx, lit.symbol.as_str(), expr.span, prefix, max, lit.kind.descr()); diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs index 3ade6bcee84..65fd312b3a0 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs @@ -10,7 +10,6 @@ use rustc_hir::{ Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, MatchSource, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::UpvarCapture; use rustc_session::declare_lint_pass; @@ -47,7 +46,7 @@ declare_lint_pass!(RedundantAsyncBlock => [REDUNDANT_ASYNC_BLOCK]); impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let span = expr.span; - if !in_external_macro(cx.tcx.sess, span) && + if !span.in_external_macro(cx.tcx.sess.source_map()) && let Some(body_expr) = desugar_async_block(cx, expr) && let Some(expr) = desugar_await(peel_blocks(body_expr)) && // The await prefix must not come from a macro as its content could change in the future. diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index b4dadef57a3..91d023500ca 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -10,7 +10,6 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::declare_lint_pass; use rustc_span::ExpnKind; @@ -138,7 +137,7 @@ fn get_parent_call_exprs<'tcx>( impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { - if in_external_macro(cx.sess(), expr.span) { + if expr.span.in_external_macro(cx.sess().source_map()) { return; } diff --git a/src/tools/clippy/clippy_lints/src/redundant_else.rs b/src/tools/clippy/clippy_lints/src/redundant_else.rs index a27f9b63114..3476f56cf33 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_else.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_else.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_ast::ast::{Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_ast::visit::{Visitor, walk_expr}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; declare_clippy_lint! { @@ -46,7 +45,7 @@ declare_lint_pass!(RedundantElse => [REDUNDANT_ELSE]); impl EarlyLintPass for RedundantElse { fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &Stmt) { - if in_external_macro(cx.sess(), stmt.span) { + if stmt.span.in_external_macro(cx.sess().source_map()) { return; } // Only look at expressions that are a whole statement diff --git a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs index 347540e7344..707abc008a8 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs @@ -4,7 +4,6 @@ use clippy_utils::msrvs::{self, Msrv}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; declare_clippy_lint! { @@ -56,7 +55,7 @@ impl EarlyLintPass for RedundantFieldNames { return; } - if in_external_macro(cx.sess(), expr.span) { + if expr.span.in_external_macro(cx.sess().source_map()) { return; } if let ExprKind::Struct(ref se) = expr.kind { diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs index 658d93e634c..ebe3e7c2019 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs @@ -6,7 +6,6 @@ use rustc_hir::def::Res; use rustc_hir::{BindingMode, ByRef, ExprKind, HirId, LetStmt, Node, Pat, PatKind, QPath}; use rustc_hir_typeck::expr_use_visitor::PlaceBase; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::UpvarCapture; use rustc_session::declare_lint_pass; use rustc_span::DesugaringKind; @@ -69,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals { // the local does not affect the code's drop behavior && !needs_ordered_drop(cx, cx.typeck_results().expr_ty(expr)) // the local is user-controlled - && !in_external_macro(cx.sess(), local.span) + && !local.span.in_external_macro(cx.sess().source_map()) && !is_from_proc_macro(cx, expr) && !is_by_value_closure_capture(cx, local.hir_id, binding_id) { diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs index 8d6b1c7274d..6a17b83b3d0 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs @@ -4,7 +4,6 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::def_id::CRATE_DEF_ID; @@ -51,7 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { && !cx.effective_visibilities.is_exported(item.owner_id.def_id) && self.is_exported.last() == Some(&false) && is_not_macro_export(item) - && !in_external_macro(cx.sess(), item.span) + && !item.span.in_external_macro(cx.sess().source_map()) { let span = item.span.with_hi(item.ident.span.hi()); let descr = cx.tcx.def_kind(item.owner_id).descr(item.owner_id.to_def_id()); diff --git a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs index 6157adad059..152d7450f5f 100644 --- a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs @@ -6,7 +6,6 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::Span; @@ -72,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) { if let Some(init_expr) = local.init && let PatKind::Binding(BindingMode::MUT, id, _, None) = local.pat.kind - && !in_external_macro(cx.sess(), local.span) + && !local.span.in_external_macro(cx.sess().source_map()) && let Some(init) = get_vec_init_kind(cx, init_expr) && !matches!( init, @@ -101,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { && let ExprKind::Assign(left, right, _) = expr.kind && let ExprKind::Path(QPath::Resolved(None, path)) = left.kind && let Res::Local(id) = path.res - && !in_external_macro(cx.sess(), expr.span) + && !expr.span.in_external_macro(cx.sess().source_map()) && let Some(init) = get_vec_init_kind(cx, right) && !matches!( init, diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs index 42d9cf2c88c..5a25483c397 100644 --- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs +++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs @@ -5,7 +5,6 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, OwnerId, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; use rustc_span::{Span, sym}; @@ -69,7 +68,7 @@ declare_clippy_lint! { declare_lint_pass!(ReturnSelfNotMustUse => [RETURN_SELF_NOT_MUST_USE]); fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, span: Span, owner_id: OwnerId) { - if !in_external_macro(cx.sess(), span) + if !span.in_external_macro(cx.sess().source_map()) // If it comes from an external macro, better ignore it. && decl.implicit_self.has_implicit_self() // We only show this warning for public exported methods. diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 664e984fece..a1cf16e6ce9 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -17,7 +17,6 @@ use rustc_hir::{ StmtKind, }; use rustc_lint::{LateContext, LateLintPass, Level, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, GenericArgKind, Ty}; use rustc_session::declare_lint_pass; @@ -191,7 +190,7 @@ fn stmt_needs_never_type(cx: &LateContext<'_>, stmt_hir_id: HirId) -> bool { impl<'tcx> LateLintPass<'tcx> for Return { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { - if !in_external_macro(cx.sess(), stmt.span) + if !stmt.span.in_external_macro(cx.sess().source_map()) && let StmtKind::Semi(expr) = stmt.kind && let ExprKind::Ret(Some(ret)) = expr.kind // return Err(...)? desugars to a match @@ -237,8 +236,8 @@ impl<'tcx> LateLintPass<'tcx> for Return { && let PatKind::Binding(_, local_id, _, _) = local.pat.kind && path_to_local_id(retexpr, local_id) && !last_statement_borrows(cx, initexpr) - && !in_external_macro(cx.sess(), initexpr.span) - && !in_external_macro(cx.sess(), retexpr.span) + && !initexpr.span.in_external_macro(cx.sess().source_map()) + && !retexpr.span.in_external_macro(cx.sess().source_map()) && !local.span.from_expansion() && !span_contains_cfg(cx, stmt.span.between(retexpr.span)) { diff --git a/src/tools/clippy/clippy_lints/src/single_call_fn.rs b/src/tools/clippy/clippy_lints/src/single_call_fn.rs index 0176077c70e..fdbccbaa8a5 100644 --- a/src/tools/clippy/clippy_lints/src/single_call_fn.rs +++ b/src/tools/clippy/clippy_lints/src/single_call_fn.rs @@ -6,7 +6,6 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::{Expr, ExprKind, HirId, Node}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::Span; @@ -88,7 +87,7 @@ impl SingleCallFn { fn_span: Span, ) -> bool { (self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(fn_def_id)) - || in_external_macro(cx.sess(), fn_span) + || fn_span.in_external_macro(cx.sess().source_map()) || cx .tcx .hir() diff --git a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs index d92b890950a..50a6ee316c8 100644 --- a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs +++ b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::ast::{GenericParam, GenericParamKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; declare_clippy_lint! { @@ -42,7 +41,7 @@ declare_lint_pass!(SingleCharLifetimeNames => [SINGLE_CHAR_LIFETIME_NAMES]); impl EarlyLintPass for SingleCharLifetimeNames { fn check_generic_param(&mut self, ctx: &EarlyContext<'_>, param: &GenericParam) { - if in_external_macro(ctx.sess(), param.ident.span) { + if param.ident.span.in_external_macro(ctx.sess().source_map()) { return; } diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs index 8ec7bfe9edd..59c13a1e2c5 100644 --- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs +++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs @@ -8,7 +8,6 @@ use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_hir::{HirId, Path, PathSegment}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; use rustc_span::{Span, sym}; @@ -112,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { if let Res::Def(_, def_id) = path.res && let Some(first_segment) = get_first_segment(path) && is_stable(cx, def_id, &self.msrv) - && !in_external_macro(cx.sess(), path.span) + && !path.span.in_external_macro(cx.sess().source_map()) && !is_from_proc_macro(cx, &first_segment.ident) { let (lint, used_mod, replace_with) = match first_segment.ident.name { diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 2925f355d0b..6164a6191db 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -9,7 +9,6 @@ use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, Node, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; @@ -147,7 +146,7 @@ declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN, STRING_SLICE]); impl<'tcx> LateLintPass<'tcx> for StringAdd { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if in_external_macro(cx.sess(), e.span) { + if e.span.in_external_macro(cx.sess().source_map()) { return; } match e.kind { @@ -284,7 +283,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { ); } - if !in_external_macro(cx.sess(), e.span) + if !e.span.in_external_macro(cx.sess().source_map()) && let ExprKind::MethodCall(path, receiver, ..) = &e.kind && path.ident.name.as_str() == "as_bytes" && let ExprKind::Lit(lit) = &receiver.kind diff --git a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs index d1d822a5532..e55d17818e4 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs @@ -5,7 +5,6 @@ use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; declare_clippy_lint! { @@ -32,7 +31,7 @@ declare_lint_pass!(ConfusingXorAndPow => [SUSPICIOUS_XOR_USED_AS_POW]); impl LateLintPass<'_> for ConfusingXorAndPow { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if !in_external_macro(cx.sess(), expr.span) + if !expr.span.in_external_macro(cx.sess().source_map()) && let ExprKind::Binary(op, left, right) = &expr.kind && op.node == BinOpKind::BitXor && left.span.eq_ctxt(right.span) diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs index 9b4c3d275ae..7176d533b61 100644 --- a/src/tools/clippy/clippy_lints/src/swap.rs +++ b/src/tools/clippy/clippy_lints/src/swap.rs @@ -12,7 +12,6 @@ use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, LetStmt, PatKind, QPath, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; @@ -212,7 +211,7 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) { if let Some((lhs0, rhs0)) = parse(first) && let Some((lhs1, rhs1)) = parse(second) && first.span.eq_ctxt(second.span) - && !in_external_macro(cx.sess(), first.span) + && !first.span.in_external_macro(cx.sess().source_map()) && is_same(cx, lhs0, rhs1) && is_same(cx, lhs1, rhs0) && !is_same(cx, lhs1, rhs1) // Ignore a = b; a = a (#10421) diff --git a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs index bed4e60ba62..4961dd6b280 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs @@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_errors::Applicability; use rustc_hir::{GenericArg, HirId, LetStmt, Node, Path, TyKind}; use rustc_lint::LateContext; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::Ty; use crate::transmute::MISSING_TRANSMUTE_ANNOTATIONS; @@ -44,7 +43,7 @@ pub(super) fn check<'tcx>( expr_hir_id: HirId, ) -> bool { let last = path.segments.last().unwrap(); - if in_external_macro(cx.tcx.sess, last.ident.span) { + if last.ident.span.in_external_macro(cx.tcx.sess.source_map()) { // If it comes from a non-local macro, we ignore it. return false; } diff --git a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs index 008e09dd8bd..c7aefc65f70 100644 --- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs @@ -7,7 +7,6 @@ use itertools::Itertools; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind, Node, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; use std::iter::once; @@ -56,7 +55,7 @@ impl TupleArrayConversions { impl LateLintPass<'_> for TupleArrayConversions { fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if in_external_macro(cx.sess(), expr.span) || !self.msrv.meets(msrvs::TUPLE_ARRAY_CONVERSIONS) { + if expr.span.in_external_macro(cx.sess().source_map()) || !self.msrv.meets(msrvs::TUPLE_ARRAY_CONVERSIONS) { return; } diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs index 45d730985bb..5e5d6a9e333 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -11,7 +11,6 @@ use rustc_hir as hir; use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource}; use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Pos, RelativeBytePos, Span, SyntaxContext}; @@ -111,7 +110,7 @@ impl_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS, UNNECES impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) - && !in_external_macro(cx.tcx.sess, block.span) + && !block.span.in_external_macro(cx.tcx.sess.source_map()) && !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id) && !is_unsafe_from_proc_macro(cx, block.span) && !block_has_safety_comment(cx, block.span) @@ -143,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { if let Some(tail) = block.expr && !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, tail.hir_id) - && !in_external_macro(cx.tcx.sess, tail.span) + && !tail.span.in_external_macro(cx.tcx.sess.source_map()) && let HasSafetyComment::Yes(pos) = stmt_has_safety_comment(cx, tail.span, tail.hir_id) && let Some(help_span) = expr_has_unnecessary_safety_comment(cx, tail, pos) { @@ -167,7 +166,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { return; }; if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, stmt.hir_id) - && !in_external_macro(cx.tcx.sess, stmt.span) + && !stmt.span.in_external_macro(cx.tcx.sess.source_map()) && let HasSafetyComment::Yes(pos) = stmt_has_safety_comment(cx, stmt.span, stmt.hir_id) && let Some(help_span) = expr_has_unnecessary_safety_comment(cx, expr, pos) { @@ -184,7 +183,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { } fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { - if in_external_macro(cx.tcx.sess, item.span) { + if item.span.in_external_macro(cx.tcx.sess.source_map()) { return; } diff --git a/src/tools/clippy/clippy_lints/src/uninhabited_references.rs b/src/tools/clippy/clippy_lints/src/uninhabited_references.rs index ee9ef017253..b342f37f0c5 100644 --- a/src/tools/clippy/clippy_lints/src/uninhabited_references.rs +++ b/src/tools/clippy/clippy_lints/src/uninhabited_references.rs @@ -3,7 +3,6 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, Expr, ExprKind, FnDecl, FnRetTy, TyKind, UnOp}; use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; use rustc_span::Span; use rustc_span::def_id::LocalDefId; @@ -40,7 +39,7 @@ declare_lint_pass!(UninhabitedReferences => [UNINHABITED_REFERENCES]); impl LateLintPass<'_> for UninhabitedReferences { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { - if in_external_macro(cx.tcx.sess, expr.span) { + if expr.span.in_external_macro(cx.tcx.sess.source_map()) { return; } @@ -66,7 +65,7 @@ impl LateLintPass<'_> for UninhabitedReferences { span: Span, _: LocalDefId, ) { - if in_external_macro(cx.tcx.sess, span) || matches!(kind, FnKind::Closure) { + if span.in_external_macro(cx.tcx.sess.source_map()) || matches!(kind, FnKind::Closure) { return; } if let FnRetTy::Return(hir_ty) = fndecl.output diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs index 93ed15777e0..7803d5115c9 100644 --- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs +++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs @@ -4,7 +4,6 @@ use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty}; use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while}; use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::declare_lint_pass; use rustc_span::{Span, sym}; @@ -64,7 +63,7 @@ declare_lint_pass!(UninitVec => [UNINIT_VEC]); // Threads: https://github.com/rust-lang/rust-clippy/pull/7682#discussion_r710998368 impl<'tcx> LateLintPass<'tcx> for UninitVec { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) { - if !in_external_macro(cx.tcx.sess, block.span) { + if !block.span.in_external_macro(cx.tcx.sess.source_map()) { for w in block.stmts.windows(2) { if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = w[1].kind { handle_uninit_vec_pair(cx, &w[0], expr); diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs index 660bdb9e2be..00b80e827d8 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs @@ -7,7 +7,6 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{Visitor, walk_body}; use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, LetStmt, MatchSource, Node, PatKind, QPath, TyKind}; use rustc_lint::{LateContext, LintContext}; -use rustc_middle::lint::{in_external_macro, is_from_async_await}; use rustc_middle::ty; use super::LET_UNIT_VALUE; @@ -22,8 +21,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) { if let Some(init) = local.init && !local.pat.span.from_expansion() - && !in_external_macro(cx.sess(), local.span) - && !is_from_async_await(local.span) + && !local.span.in_external_macro(cx.sess().source_map()) + && !local.span.is_from_async_await() && cx.typeck_results().pat_ty(local.pat).is_unit() { // skip `let awa = ()` diff --git a/src/tools/clippy/clippy_lints/src/unused_result_ok.rs b/src/tools/clippy/clippy_lints/src/unused_result_ok.rs index 0c0d10eac5b..958f19d1833 100644 --- a/src/tools/clippy/clippy_lints/src/unused_result_ok.rs +++ b/src/tools/clippy/clippy_lints/src/unused_result_ok.rs @@ -4,7 +4,6 @@ use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir::{ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; use rustc_span::sym; @@ -39,7 +38,7 @@ impl LateLintPass<'_> for UnusedResultOk { && let ExprKind::MethodCall(ok_path, recv, [], ..) = expr.kind //check is expr.ok() has type Result<T,E>.ok(, _) && ok_path.ident.as_str() == "ok" && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result) - && !in_external_macro(cx.sess(), stmt.span) + && !stmt.span.in_external_macro(cx.sess().source_map()) { let ctxt = expr.span.ctxt(); let mut applicability = Applicability::MaybeIncorrect; diff --git a/src/tools/clippy/clippy_lints/src/unused_trait_names.rs b/src/tools/clippy/clippy_lints/src/unused_trait_names.rs index 17ee5fc20ca..f8341583435 100644 --- a/src/tools/clippy/clippy_lints/src/unused_trait_names.rs +++ b/src/tools/clippy/clippy_lints/src/unused_trait_names.rs @@ -7,7 +7,6 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Item, ItemKind, UseKind}; use rustc_lint::{LateContext, LateLintPass, LintContext as _}; -use rustc_middle::lint::in_external_macro; use rustc_middle::ty::Visibility; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; @@ -63,7 +62,7 @@ impl_lint_pass!(UnusedTraitNames => [UNUSED_TRAIT_NAMES]); impl<'tcx> LateLintPass<'tcx> for UnusedTraitNames { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if self.msrv.meets(msrvs::UNDERSCORE_IMPORTS) - && !in_external_macro(cx.sess(), item.span) + && !item.span.in_external_macro(cx.sess().source_map()) && let ItemKind::Use(path, UseKind::Single) = item.kind // Ignore imports that already use Underscore && item.ident.name != kw::Underscore diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index eaa119b045f..6a952c0d97a 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -8,7 +8,6 @@ use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, PathSegmen use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceWithHirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; -use rustc_middle::lint::in_external_macro; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::declare_lint_pass; @@ -292,7 +291,7 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { // Shouldn't lint when `expr` is in macro. - if in_external_macro(self.cx.tcx.sess, expr.span) { + if expr.span.in_external_macro(self.cx.tcx.sess.source_map()) { return; } if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr) { diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs index c3843279ba2..3449468ef48 100644 --- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs +++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs @@ -4,7 +4,6 @@ use core::mem::replace; use rustc_errors::Applicability; use rustc_hir::{HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::symbol::Ident; @@ -126,7 +125,7 @@ fn check_ident(cx: &LateContext<'_>, ident: &Ident, hir_id: HirId, be_aggressive impl LateLintPass<'_> for UpperCaseAcronyms { fn check_item(&mut self, cx: &LateContext<'_>, it: &Item<'_>) { // do not lint public items or in macros - if in_external_macro(cx.sess(), it.span) + if it.span.in_external_macro(cx.sess().source_map()) || (self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(it.owner_id.def_id)) { return; diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs index d87d554eb07..3c23662e9d1 100644 --- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs +++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs @@ -8,7 +8,6 @@ use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, Mutability, PatKind, QPath, Stmt, StmtKind, UnOp}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::{Span, Symbol}; @@ -158,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) { if let Some(init_expr) = local.init && let PatKind::Binding(BindingMode::MUT, id, name, None) = local.pat.kind - && !in_external_macro(cx.sess(), local.span) + && !local.span.in_external_macro(cx.sess().source_map()) && let Some(init) = get_vec_init_kind(cx, init_expr) && !matches!(init, VecInitKind::WithExprCapacity(_)) { @@ -181,7 +180,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush { && let ExprKind::Path(QPath::Resolved(None, path)) = left.kind && let [name] = &path.segments && let Res::Local(id) = path.res - && !in_external_macro(cx.sess(), expr.span) + && !expr.span.in_external_macro(cx.sess().source_map()) && let Some(init) = get_vec_init_kind(cx, right) && !matches!(init, VecInitKind::WithExprCapacity(_)) { diff --git a/src/tools/clippy/clippy_lints/src/visibility.rs b/src/tools/clippy/clippy_lints/src/visibility.rs index 2e5fc5834e2..d17b3df9921 100644 --- a/src/tools/clippy/clippy_lints/src/visibility.rs +++ b/src/tools/clippy/clippy_lints/src/visibility.rs @@ -3,7 +3,6 @@ use clippy_utils::source::SpanRangeExt; use rustc_ast::ast::{Item, VisibilityKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; use rustc_session::declare_lint_pass; use rustc_span::Span; use rustc_span::symbol::kw; @@ -79,7 +78,7 @@ declare_lint_pass!(Visibility => [NEEDLESS_PUB_SELF, PUB_WITH_SHORTHAND, PUB_WIT impl EarlyLintPass for Visibility { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { - if !in_external_macro(cx.sess(), item.span) + if !item.span.in_external_macro(cx.sess().source_map()) && let VisibilityKind::Restricted { path, shorthand, .. } = &item.vis.kind { if **path == kw::SelfLower && !is_from_proc_macro(cx, item.vis.span) { diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 287bdc9a6fd..0aaef91e48a 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -116,6 +116,7 @@ fn check_rvalue<'tcx>( Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body, msrv), Rvalue::Repeat(operand, _) | Rvalue::Use(operand) + | Rvalue::WrapUnsafeBinder(operand, _) | Rvalue::Cast( CastKind::PointerWithExposedProvenance | CastKind::IntToInt @@ -289,7 +290,8 @@ fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &B | ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } | ProjectionElem::Subtype(_) - | ProjectionElem::Index(_) => {}, + | ProjectionElem::Index(_) + | ProjectionElem::UnwrapUnsafeBinder(_) => {}, } } diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index 8201f332d33..e4092bcd105 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -166,6 +166,8 @@ impl rustc_driver::Callbacks for ClippyCallbacks { // MIR passes can be enabled / disabled separately, we should figure out, what passes to // use for Clippy. config.opts.unstable_opts.mir_opt_level = Some(0); + config.opts.unstable_opts.mir_enable_passes = + vec![("CheckNull".to_owned(), false), ("CheckAlignment".to_owned(), false)]; // Disable flattening and inlining of format_args!(), so the HIR matches with the AST. config.opts.unstable_opts.flatten_format_args = false; @@ -195,7 +197,7 @@ pub fn main() { }); exit(rustc_driver::catch_with_exit_code(move || { - let mut orig_args = rustc_driver::args::raw_args(&early_dcx)?; + let mut orig_args = rustc_driver::args::raw_args(&early_dcx); let has_sysroot_arg = |args: &mut [String]| -> bool { if has_arg(args, "--sysroot") { @@ -237,7 +239,7 @@ pub fn main() { pass_sysroot_env_if_given(&mut args, sys_root_env); rustc_driver::run_compiler(&args, &mut DefaultCallbacks); - return Ok(()); + return; } if orig_args.iter().any(|a| a == "--version" || a == "-V") { @@ -299,7 +301,6 @@ pub fn main() { } else { rustc_driver::run_compiler(&args, &mut RustcCallbacks { clippy_args_var }); } - Ok(()) })) } diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs index acdb3cbdd45..a7ac875d0a3 100644 --- a/src/tools/compiletest/src/directive-list.rs +++ b/src/tools/compiletest/src/directive-list.rs @@ -39,6 +39,10 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-android", "ignore-apple", "ignore-arm", + "ignore-arm-unknown-linux-gnueabi", + "ignore-arm-unknown-linux-gnueabihf", + "ignore-arm-unknown-linux-musleabi", + "ignore-arm-unknown-linux-musleabihf", "ignore-avr", "ignore-beta", "ignore-cdb", @@ -177,6 +181,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-bpf", "only-cdb", "only-dist", + "only-emscripten", "only-gnu", "only-i686-pc-windows-gnu", "only-i686-pc-windows-msvc", diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 8c96554738e..452a2e9a9d5 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -882,14 +882,6 @@ fn iter_header( } let ln = ln.trim(); - // Assume that any directives will be found before the first module or function. This - // doesn't seem to be an optimization with a warm page cache. Maybe with a cold one. - // FIXME(jieyouxu): this will cause `//@` directives in the rest of the test file to - // not be checked. - if ln.starts_with("fn") || ln.starts_with("mod") { - return; - } - let Some(directive_line) = line_directive(line_number, comment, ln) else { continue; }; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index ca48abda5fc..0e2da2b02ca 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1417,9 +1417,7 @@ impl<'test> TestCx<'test> { } fn is_rustdoc(&self) -> bool { - self.config.src_base.ends_with("rustdoc-ui") - || self.config.src_base.ends_with("rustdoc-js") - || self.config.src_base.ends_with("rustdoc-json") + matches!(self.config.suite.as_str(), "rustdoc-ui" | "rustdoc-js" | "rustdoc-json") } fn get_mir_dump_dir(&self) -> PathBuf { diff --git a/src/tools/compiletest/src/runtest/rustdoc_json.rs b/src/tools/compiletest/src/runtest/rustdoc_json.rs index 31fdb0a5d13..bf7eb2e109a 100644 --- a/src/tools/compiletest/src/runtest/rustdoc_json.rs +++ b/src/tools/compiletest/src/runtest/rustdoc_json.rs @@ -16,13 +16,12 @@ impl TestCx<'_> { self.fatal_proc_rec("rustdoc failed!", &proc_res); } - let root = self.config.find_rust_src_root().unwrap(); let mut json_out = out_dir.join(self.testpaths.file.file_stem().unwrap()); json_out.set_extension("json"); let res = self.run_command_to_procres( Command::new(self.config.jsondocck_path.as_ref().unwrap()) .arg("--doc-dir") - .arg(root.join(&out_dir)) + .arg(&out_dir) .arg("--template") .arg(&self.testpaths.file), ); diff --git a/src/tools/enzyme b/src/tools/enzyme -Subproject 2fe5164a2423dd67ef25e2c4fb204fd06362494 +Subproject 0e5fa4a3d475f4dece489c9e06b11164f83789f diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index 363b96fdff1..57a757f9085 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -351,7 +351,19 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", ] [[package]] @@ -529,12 +541,12 @@ dependencies = [ "chrono-tz", "colored", "directories", - "getrandom", + "getrandom 0.3.1", "libc", "libffi", "libloading", "measureme", - "rand", + "rand 0.9.0", "regex", "rustc_version", "smallvec", @@ -662,7 +674,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" dependencies = [ "phf_shared", - "rand", + "rand 0.8.5", ] [[package]] @@ -692,7 +704,7 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -729,19 +741,28 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "libc", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ "rand_chacha", - "rand_core", + "rand_core 0.9.0", + "zerocopy 0.8.14", ] [[package]] name = "rand_chacha" -version = "0.3.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.9.0", ] [[package]] @@ -749,8 +770,15 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rand_core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" dependencies = [ - "getrandom", + "getrandom 0.3.1", + "zerocopy 0.8.14", ] [[package]] @@ -768,7 +796,7 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ - "getrandom", + "getrandom 0.2.15", "libredox", "thiserror", ] @@ -1051,9 +1079,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ui_test" -version = "0.26.5" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32ee4c40e5a5f9fa6864ff976473e5d6a6e9884b6ce68b40690d9f87e1994c83" +checksum = "7484683d60d50ca1d1b6433c3dbf6c5ad71d20387acdcfb16fe79573f3fba576" dependencies = [ "annotate-snippets", "anyhow", @@ -1106,6 +1134,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1245,13 +1282,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags", +] + +[[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a367f292d93d4eab890745e75a778da40909cab4d6ff8173693812f79c4a2468" +dependencies = [ + "zerocopy-derive 0.8.14", ] [[package]] @@ -1264,3 +1319,14 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zerocopy-derive" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3931cb58c62c13adec22e38686b559c86a30565e16ad6e8510a337cedc611e1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index 6e8e270985e..de80722fc3d 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -18,8 +18,8 @@ test = false # we have no unit tests doctest = false # and no doc tests [dependencies] -getrandom = { version = "0.2", features = ["std"] } -rand = "0.8" +getrandom = { version = "0.3", features = ["std"] } +rand = "0.9" smallvec = { version = "1.7", features = ["drain_filter"] } aes = { version = "0.8.3", features = ["hazmat"] } measureme = "11" @@ -47,8 +47,8 @@ windows-sys = { version = "0.52", features = [ ] } [dev-dependencies] +ui_test = "0.28.0" colored = "2" -ui_test = "0.26.5" rustc_version = "0.4" regex = "1.5.5" tempfile = "3" diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index fb3fc621565..5583030b490 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -14,9 +14,7 @@ function endgroup { begingroup "Building Miri" # Global configuration -# We are getting some odd linker warnings on macOS, make sure they do not fail the build. -# (See <https://github.com/rust-lang/rust/issues/136086>.) -export RUSTFLAGS="-D warnings -A linker-messages" +export RUSTFLAGS="-D warnings" export CARGO_INCREMENTAL=0 export CARGO_EXTRA_FLAGS="--locked" diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 0d405f532fc..6e84524c8aa 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -2f0ad2a71e4a4528bb80bcb24bf8fa4e50cb87c2 +6dd75f0d6802f56564f5f9c947a85ded286d3986 diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 3d0fc5590eb..a4f2a117b18 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -217,7 +217,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // We have to pick a fresh address. // Leave some space to the previous allocation, to give it some chance to be less aligned. // We ensure that `(global_state.next_base_addr + slack) % 16` is uniformly distributed. - let slack = rng.gen_range(0..16); + let slack = rng.random_range(0..16); // From next_base_addr + slack, round up to adjust for alignment. let base_addr = global_state .next_base_addr diff --git a/src/tools/miri/src/alloc_addresses/reuse_pool.rs b/src/tools/miri/src/alloc_addresses/reuse_pool.rs index b0c7ee7dff5..c0d24a9fbbc 100644 --- a/src/tools/miri/src/alloc_addresses/reuse_pool.rs +++ b/src/tools/miri/src/alloc_addresses/reuse_pool.rs @@ -58,7 +58,7 @@ impl ReusePool { // We don't remember stack addresses: there's a lot of them (so the perf impact is big), // and we only want to reuse stack slots within the same thread or else we'll add a lot of // undesired synchronization. - if kind == MemoryKind::Stack || !rng.gen_bool(self.address_reuse_rate) { + if kind == MemoryKind::Stack || !rng.random_bool(self.address_reuse_rate) { return; } let clock = clock(); @@ -88,10 +88,10 @@ impl ReusePool { thread: ThreadId, ) -> Option<(u64, Option<VClock>)> { // Determine whether we'll even attempt a reuse. As above, we don't do reuse for stack addresses. - if kind == MemoryKind::Stack || !rng.gen_bool(self.address_reuse_rate) { + if kind == MemoryKind::Stack || !rng.random_bool(self.address_reuse_rate) { return None; } - let cross_thread_reuse = rng.gen_bool(self.address_reuse_cross_thread_rate); + let cross_thread_reuse = rng.random_bool(self.address_reuse_cross_thread_rate); // Determine the pool to take this from. let subpool = self.subpool(align); // Let's see if we can find something of the right size. We want to find the full range of @@ -118,7 +118,7 @@ impl ReusePool { return None; } // Pick a random element with the desired size. - let idx = rng.gen_range(begin..end); + let idx = rng.random_range(begin..end); // Remove it from the pool and return. let (chosen_addr, chosen_size, chosen_thread, clock) = subpool.remove(idx); debug_assert!(chosen_size >= size && chosen_addr % align.bytes() == 0); diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 988a0be6327..685f5670ab4 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -379,10 +379,8 @@ fn run_compiler_and_exit( callbacks: &mut (dyn rustc_driver::Callbacks + Send), ) -> ! { // Invoke compiler, and handle return code. - let exit_code = rustc_driver::catch_with_exit_code(move || { - rustc_driver::run_compiler(args, callbacks); - Ok(()) - }); + let exit_code = + rustc_driver::catch_with_exit_code(move || rustc_driver::run_compiler(args, callbacks)); std::process::exit(exit_code) } @@ -461,7 +459,7 @@ fn main() { // (`install_ice_hook` might change `RUST_BACKTRACE`.) let env_snapshot = env::vars_os().collect::<Vec<_>>(); - let args = rustc_driver::args::raw_args(&early_dcx) + let args = rustc_driver::catch_fatal_errors(|| rustc_driver::args::raw_args(&early_dcx)) .unwrap_or_else(|_| std::process::exit(rustc_driver::EXIT_FAILURE)); // Install the ctrlc handler that sets `rustc_const_eval::CTRL_C_RECEIVED`, even if @@ -723,8 +721,8 @@ fn main() { // Ensure we have parallelism for many-seeds mode. if many_seeds.is_some() && !rustc_args.iter().any(|arg| arg.starts_with("-Zthreads=")) { - // Clamp to 8 threads; things get a lot less efficient beyond that due to lock contention. - let threads = std::thread::available_parallelism().map_or(1, |n| n.get()).min(8); + // Clamp to 10 threads; things get a lot less efficient beyond that due to lock contention. + let threads = std::thread::available_parallelism().map_or(1, |n| n.get()).min(10); rustc_args.push(format!("-Zthreads={threads}")); } let many_seeds = diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index bcc8668dbc1..18a5a0612bb 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -865,7 +865,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let new_perm = NewPermission::from_ref_ty(val.layout.ty, kind, this); let cause = match kind { - RetagKind::TwoPhase { .. } => RetagCause::TwoPhase, + RetagKind::TwoPhase => RetagCause::TwoPhase, RetagKind::FnEntry => unreachable!(), RetagKind::Raw | RetagKind::Default => RetagCause::Normal, }; @@ -880,7 +880,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let retag_fields = this.machine.borrow_tracker.as_mut().unwrap().get_mut().retag_fields; let retag_cause = match kind { - RetagKind::TwoPhase { .. } => unreachable!(), // can only happen in `retag_ptr_value` + RetagKind::TwoPhase => unreachable!(), // can only happen in `retag_ptr_value` RetagKind::FnEntry => RetagCause::FnEntry, RetagKind::Default | RetagKind::Raw => RetagCause::Normal, }; @@ -904,10 +904,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { new_perm: NewPermission, ) -> InterpResult<'tcx> { let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?; - let val = self.ecx.sb_retag_reference(&val, new_perm, RetagInfo { - cause: self.retag_cause, - in_field: self.in_field, - })?; + let val = self.ecx.sb_retag_reference( + &val, + new_perm, + RetagInfo { cause: self.retag_cause, in_field: self.in_field }, + )?; self.ecx.write_immediate(*val, place)?; interp_ok(()) } @@ -996,10 +997,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { access: Some(AccessKind::Write), protector: Some(ProtectorKind::StrongProtector), }; - this.sb_retag_place(place, new_perm, RetagInfo { - cause: RetagCause::InPlaceFnPassing, - in_field: false, - }) + this.sb_retag_place( + place, + new_perm, + RetagInfo { cause: RetagCause::InPlaceFnPassing, in_field: false }, + ) } /// Mark the given tag as exposed. It was found on a pointer with the given AllocId. diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs index 5d7c3d8c219..5c12ce39d10 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs @@ -379,14 +379,18 @@ pub mod diagnostics { use super::*; impl fmt::Display for PermissionPriv { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", match self { - ReservedFrz { conflicted: false } => "Reserved", - ReservedFrz { conflicted: true } => "Reserved (conflicted)", - ReservedIM => "Reserved (interior mutable)", - Active => "Active", - Frozen => "Frozen", - Disabled => "Disabled", - }) + write!( + f, + "{}", + match self { + ReservedFrz { conflicted: false } => "Reserved", + ReservedFrz { conflicted: true } => "Reserved (conflicted)", + ReservedIM => "Reserved (interior mutable)", + Active => "Active", + Frozen => "Frozen", + Disabled => "Disabled", + } + ) } } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index fd69278f20a..3389b1c602c 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -581,15 +581,18 @@ impl Tree { let mut debug_info = NodeDebugInfo::new(root_tag, root_default_perm, span); // name the root so that all allocations contain one named pointer debug_info.add_name("root of the allocation"); - nodes.insert(root_idx, Node { - tag: root_tag, - parent: None, - children: SmallVec::default(), - default_initial_perm: root_default_perm, - // The root may never be skipped, all accesses will be local. - default_initial_idempotent_foreign_access: IdempotentForeignAccess::None, - debug_info, - }); + nodes.insert( + root_idx, + Node { + tag: root_tag, + parent: None, + children: SmallVec::default(), + default_initial_perm: root_default_perm, + // The root may never be skipped, all accesses will be local. + default_initial_idempotent_foreign_access: IdempotentForeignAccess::None, + debug_info, + }, + ); nodes }; let rperms = { @@ -624,14 +627,17 @@ impl<'tcx> Tree { let parent_idx = self.tag_mapping.get(&parent_tag).unwrap(); let strongest_idempotent = default_initial_perm.strongest_idempotent_foreign_access(prot); // Create the node - self.nodes.insert(idx, Node { - tag: new_tag, - parent: Some(parent_idx), - children: SmallVec::default(), - default_initial_perm, - default_initial_idempotent_foreign_access: strongest_idempotent, - debug_info: NodeDebugInfo::new(new_tag, default_initial_perm, span), - }); + self.nodes.insert( + idx, + Node { + tag: new_tag, + parent: Some(parent_idx), + children: SmallVec::default(), + default_initial_perm, + default_initial_idempotent_foreign_access: strongest_idempotent, + debug_info: NodeDebugInfo::new(new_tag, default_initial_perm, span), + }, + ); // Register new_tag as a child of parent_tag self.nodes.get_mut(parent_idx).unwrap().children.push(idx); // Initialize perms diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 4cdc9348dc9..b1ca434361b 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -830,7 +830,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { let success_rate = 1.0 - this.machine.cmpxchg_weak_failure_rate; let cmpxchg_success = eq.to_scalar().to_bool()? && if can_fail_spuriously { - this.machine.rng.get_mut().gen_bool(success_rate) + this.machine.rng.get_mut().random_bool(success_rate) } else { true }; diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index 14c72e9398a..268268848ed 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -128,7 +128,7 @@ struct Condvar { /// The futex state. #[derive(Default, Debug)] struct Futex { - waiters: VecDeque<FutexWaiter>, + waiters: Vec<FutexWaiter>, /// Tracks the happens-before relationship /// between a futex-wake and a futex-wait /// during a non-spurious wake event. @@ -140,6 +140,12 @@ struct Futex { #[derive(Default, Clone)] pub struct FutexRef(Rc<RefCell<Futex>>); +impl FutexRef { + pub fn waiters(&self) -> usize { + self.0.borrow().waiters.len() + } +} + impl VisitProvenance for FutexRef { fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { // No provenance in `Futex`. @@ -728,25 +734,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(true) } - /// Wait for the futex to be signaled, or a timeout. - /// On a signal, `retval_succ` is written to `dest`. - /// On a timeout, `retval_timeout` is written to `dest` and `errno_timeout` is set as the last error. + /// Wait for the futex to be signaled, or a timeout. Once the thread is + /// unblocked, `callback` is called with the unblock reason. fn futex_wait( &mut self, futex_ref: FutexRef, bitset: u32, timeout: Option<(TimeoutClock, TimeoutAnchor, Duration)>, - retval_succ: Scalar, - retval_timeout: Scalar, - dest: MPlaceTy<'tcx>, - errno_timeout: IoError, + callback: DynUnblockCallback<'tcx>, ) { let this = self.eval_context_mut(); let thread = this.active_thread(); let mut futex = futex_ref.0.borrow_mut(); let waiters = &mut futex.waiters; assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting"); - waiters.push_back(FutexWaiter { thread, bitset }); + waiters.push(FutexWaiter { thread, bitset }); drop(futex); this.block_thread( @@ -755,10 +757,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { callback!( @capture<'tcx> { futex_ref: FutexRef, - retval_succ: Scalar, - retval_timeout: Scalar, - dest: MPlaceTy<'tcx>, - errno_timeout: IoError, + callback: DynUnblockCallback<'tcx>, } |this, unblock: UnblockKind| { match unblock { @@ -768,29 +767,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if let Some(data_race) = &this.machine.data_race { data_race.acquire_clock(&futex.clock, &this.machine.threads); } - // Write the return value. - this.write_scalar(retval_succ, &dest)?; - interp_ok(()) }, UnblockKind::TimedOut => { // Remove the waiter from the futex. let thread = this.active_thread(); let mut futex = futex_ref.0.borrow_mut(); futex.waiters.retain(|waiter| waiter.thread != thread); - // Set errno and write return value. - this.set_last_error(errno_timeout)?; - this.write_scalar(retval_timeout, &dest)?; - interp_ok(()) }, } + + callback.call(this, unblock) } ), ); } - /// Wake up the first thread in the queue that matches any of the bits in the bitset. - /// Returns whether anything was woken. - fn futex_wake(&mut self, futex_ref: &FutexRef, bitset: u32) -> InterpResult<'tcx, bool> { + /// Wake up `count` of the threads in the queue that match any of the bits + /// in the bitset. Returns how many threads were woken. + fn futex_wake( + &mut self, + futex_ref: &FutexRef, + bitset: u32, + count: usize, + ) -> InterpResult<'tcx, usize> { let this = self.eval_context_mut(); let mut futex = futex_ref.0.borrow_mut(); let data_race = &this.machine.data_race; @@ -800,13 +799,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { data_race.release_clock(&this.machine.threads, |clock| futex.clock.clone_from(clock)); } - // Wake up the first thread in the queue that matches any of the bits in the bitset. - let Some(i) = futex.waiters.iter().position(|w| w.bitset & bitset != 0) else { - return interp_ok(false); - }; - let waiter = futex.waiters.remove(i).unwrap(); + // Remove `count` of the threads in the queue that match any of the bits in the bitset. + // We collect all of them before unblocking because the unblock callback may access the + // futex state to retrieve the remaining number of waiters on macOS. + let waiters: Vec<_> = + futex.waiters.extract_if(.., |w| w.bitset & bitset != 0).take(count).collect(); drop(futex); - this.unblock_thread(waiter.thread, BlockReason::Futex)?; - interp_ok(true) + + let woken = waiters.len(); + for waiter in waiters { + this.unblock_thread(waiter.thread, BlockReason::Futex)?; + } + + interp_ok(woken) } } diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 6d22dd8d68d..a8a2491304d 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -1138,7 +1138,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { use rand::Rng as _; let this = self.eval_context_mut(); - if this.machine.rng.get_mut().gen_bool(this.machine.preemption_rate) { + if this.machine.rng.get_mut().random_bool(this.machine.preemption_rate) { this.yield_active_thread(); } } diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index c8f04e25207..36b15dbf623 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -558,15 +558,15 @@ where match chars.next() { Some('"') => { - cmd.extend(iter::repeat('\\').take(nslashes * 2 + 1)); + cmd.extend(iter::repeat_n('\\', nslashes * 2 + 1)); cmd.push('"'); } Some(c) => { - cmd.extend(iter::repeat('\\').take(nslashes)); + cmd.extend(iter::repeat_n('\\', nslashes)); cmd.push(c); } None => { - cmd.extend(iter::repeat('\\').take(nslashes * 2)); + cmd.extend(iter::repeat_n('\\', nslashes * 2)); break; } } diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index c5538351d7d..a26f12cdfb1 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -421,7 +421,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if this.machine.communicate() { // Fill the buffer using the host's rng. - getrandom::getrandom(&mut data) + getrandom::fill(&mut data) .map_err(|err| err_unsup_format!("host getrandom failed: {}", err))?; } else { let rng = this.machine.rng.get_mut(); @@ -678,6 +678,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) } + /// Helper function used inside shims of foreign functions to check that the target OS + /// is one of `target_oses`. It returns an error containing the `name` of the foreign function + /// in a message if this is not the case. + fn check_target_os(&self, target_oses: &[&str], name: Symbol) -> InterpResult<'tcx> { + let target_os = self.eval_context_ref().tcx.sess.target.os.as_ref(); + if !target_oses.contains(&target_os) { + throw_unsup_format!("`{name}` is not supported on {target_os}"); + } + interp_ok(()) + } + /// Helper function used inside the shims of foreign functions to assert that the target OS /// is part of the UNIX family. It panics showing a message with the `name` of the foreign function /// if this is not the case. @@ -991,6 +1002,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { check_arg_count(args) } + /// Check shim for variadic function. + /// Returns a tuple that consisting of an array of fixed args, and a slice of varargs. + fn check_shim_variadic<'a, const N: usize>( + &mut self, + abi: &FnAbi<'tcx, Ty<'tcx>>, + exp_abi: Conv, + link_name: Symbol, + args: &'a [OpTy<'tcx>], + ) -> InterpResult<'tcx, (&'a [OpTy<'tcx>; N], &'a [OpTy<'tcx>])> + where + &'a [OpTy<'tcx>; N]: TryFrom<&'a [OpTy<'tcx>]>, + { + self.check_abi_and_shim_symbol_clash(abi, exp_abi, link_name)?; + check_vargarg_fixed_arg_count(link_name, abi, args) + } + /// Mark a machine allocation that was just created as immutable. fn mark_immutable(&mut self, mplace: &MPlaceTy<'tcx>) { let this = self.eval_context_mut(); @@ -1184,8 +1211,10 @@ where throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N) } -/// Check that the number of args is at least the minumim what we expect. -pub fn check_min_arg_count<'a, 'tcx, const N: usize>( +/// Check that the number of varargs is at least the minimum what we expect. +/// Fixed args should not be included. +/// Use `check_vararg_fixed_arg_count` to extract the varargs slice from full function arguments. +pub fn check_min_vararg_count<'a, 'tcx, const N: usize>( name: &'a str, args: &'a [OpTy<'tcx>], ) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> { @@ -1193,7 +1222,35 @@ pub fn check_min_arg_count<'a, 'tcx, const N: usize>( return interp_ok(ops); } throw_ub_format!( - "incorrect number of arguments for `{name}`: got {}, expected at least {}", + "not enough variadic arguments for `{name}`: got {}, expected at least {}", + args.len(), + N + ) +} + +/// Check the number of fixed args of a vararg function. +/// Returns a tuple that consisting of an array of fixed args, and a slice of varargs. +fn check_vargarg_fixed_arg_count<'a, 'tcx, const N: usize>( + link_name: Symbol, + abi: &FnAbi<'tcx, Ty<'tcx>>, + args: &'a [OpTy<'tcx>], +) -> InterpResult<'tcx, (&'a [OpTy<'tcx>; N], &'a [OpTy<'tcx>])> { + if !abi.c_variadic { + throw_ub_format!("calling a variadic function with a non-variadic caller-side signature"); + } + if abi.fixed_count != u32::try_from(N).unwrap() { + throw_ub_format!( + "incorrect number of fixed arguments for variadic function `{}`: got {}, expected {N}", + link_name.as_str(), + abi.fixed_count + ) + } + if let Some(args) = args.split_first_chunk() { + return interp_ok(args); + } + throw_ub_format!( + "incorrect number of arguments for `{}`: got {}, expected at least {}", + link_name.as_str(), args.len(), N ) diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 9eebbc5d363..bce78adcaea 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -141,7 +141,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // FIXME: should we check for validity here? It's tricky because we do not have a // place. Codegen does not seem to set any attributes like `noundef` for intrinsic // calls, so we don't *have* to do anything. - let branch: bool = this.machine.rng.get_mut().gen(); + let branch: bool = this.machine.rng.get_mut().random(); this.write_scalar(Scalar::from_bool(branch), dest)?; } @@ -289,7 +289,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let a = this.read_scalar(a)?.to_f32()?; let b = this.read_scalar(b)?.to_f32()?; let c = this.read_scalar(c)?.to_f32()?; - let fuse: bool = this.machine.rng.get_mut().gen(); + let fuse: bool = this.machine.rng.get_mut().random(); let res = if fuse { // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11 a.to_host().mul_add(b.to_host(), c.to_host()).to_soft() @@ -304,7 +304,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let a = this.read_scalar(a)?.to_f64()?; let b = this.read_scalar(b)?.to_f64()?; let c = this.read_scalar(c)?.to_f64()?; - let fuse: bool = this.machine.rng.get_mut().gen(); + let fuse: bool = this.machine.rng.get_mut().random(); let res = if fuse { // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11 a.to_host().mul_add(b.to_host(), c.to_host()).to_soft() diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index 54bdd3f02c2..45e316b190a 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -304,7 +304,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let c = this.read_scalar(&this.project_index(&c, i)?)?; let dest = this.project_index(&dest, i)?; - let fuse: bool = intrinsic_name == "fma" || this.machine.rng.get_mut().gen(); + let fuse: bool = intrinsic_name == "fma" || this.machine.rng.get_mut().random(); // Works for f32 and f64. // FIXME: using host floats to work around https://github.com/rust-lang/miri/issues/2468. @@ -639,8 +639,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let (right, right_len) = this.project_to_simd(right)?; let (dest, dest_len) = this.project_to_simd(dest)?; - let index = - generic_args[2].expect_const().try_to_valtree().unwrap().0.unwrap_branch(); + let index = generic_args[2].expect_const().to_value().valtree.unwrap_branch(); let index_len = index.len(); assert_eq!(left_len, right_len); diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 2955dc38a8c..45054c37c40 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -15,6 +15,8 @@ #![feature(unqualified_local_imports)] #![feature(derive_coerce_pointee)] #![feature(arbitrary_self_types)] +#![feature(unsigned_is_multiple_of)] +#![feature(extract_if)] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, @@ -36,6 +38,7 @@ clippy::needless_question_mark, clippy::needless_lifetimes, clippy::too_long_first_doc_paragraph, + // We don't use translatable diagnostics rustc::diagnostic_outside_of_impl, // We are not implementing queries here so it's fine rustc::potential_query_instability, @@ -168,7 +171,7 @@ pub const MIRI_DEFAULT_ARGS: &[&str] = &[ "-Zmir-emit-retag", "-Zmir-keep-place-mention", "-Zmir-opt-level=0", - "-Zmir-enable-passes=-CheckAlignment", + "-Zmir-enable-passes=-CheckAlignment,-CheckNull", // Deduplicating diagnostics means we miss events when tracking what happens during an // execution. Let's not do that. "-Zdeduplicate-diagnostics=no", diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 845ba484326..4735db48e81 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -11,6 +11,7 @@ use std::{fmt, process}; use rand::rngs::StdRng; use rand::{Rng, SeedableRng}; use rustc_abi::{Align, ExternAbi, Size}; +use rustc_apfloat::{Float, FloatConvert}; use rustc_attr_parsing::InlineAttr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; #[allow(unused)] @@ -1111,10 +1112,13 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { // Call the lang item. let panic = ecx.tcx.lang_items().get(reason.lang_item()).unwrap(); let panic = ty::Instance::mono(ecx.tcx.tcx, panic); - ecx.call_function(panic, ExternAbi::Rust, &[], None, StackPopCleanup::Goto { - ret: None, - unwind: mir::UnwindAction::Unreachable, - })?; + ecx.call_function( + panic, + ExternAbi::Rust, + &[], + None, + StackPopCleanup::Goto { ret: None, unwind: mir::UnwindAction::Unreachable }, + )?; interp_ok(()) } @@ -1129,20 +1133,24 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { } #[inline(always)] - fn generate_nan< - F1: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F2>, - F2: rustc_apfloat::Float, - >( + fn generate_nan<F1: Float + FloatConvert<F2>, F2: Float>( ecx: &InterpCx<'tcx, Self>, inputs: &[F1], ) -> F2 { ecx.generate_nan(inputs) } + #[inline(always)] + fn equal_float_min_max<F: Float>(ecx: &MiriInterpCx<'tcx>, a: F, b: F) -> F { + ecx.equal_float_min_max(a, b) + } + + #[inline(always)] fn ub_checks(ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool> { interp_ok(ecx.tcx.sess.ub_checks()) } + #[inline(always)] fn thread_local_static_pointer( ecx: &mut MiriInterpCx<'tcx>, def_id: DefId, @@ -1496,7 +1504,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { catch_unwind: None, timing, is_user_relevant: ecx.machine.is_user_relevant(&frame), - salt: ecx.machine.rng.borrow_mut().gen::<usize>() % ADDRS_PER_ANON_GLOBAL, + salt: ecx.machine.rng.borrow_mut().random_range(0..ADDRS_PER_ANON_GLOBAL), data_race: ecx.machine.data_race.as_ref().map(|_| data_race::FrameState::default()), }; @@ -1711,7 +1719,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { if unique { CTFE_ALLOC_SALT } else { - ecx.machine.rng.borrow_mut().gen::<usize>() % ADDRS_PER_ANON_GLOBAL + ecx.machine.rng.borrow_mut().random_range(0..ADDRS_PER_ANON_GLOBAL) } } diff --git a/src/tools/miri/src/math.rs b/src/tools/miri/src/math.rs index ed3d2d55678..7117f722fee 100644 --- a/src/tools/miri/src/math.rs +++ b/src/tools/miri/src/math.rs @@ -1,9 +1,12 @@ use rand::Rng as _; -use rand::distributions::Distribution as _; use rustc_apfloat::Float as _; use rustc_apfloat::ieee::IeeeFloat; -/// Disturbes a floating-point result by a relative error on the order of (-2^scale, 2^scale). +/// Disturbes a floating-point result by a relative error in the range (-2^scale, 2^scale). +/// +/// For a 2^N ULP error, you can use an `err_scale` of `-(F::PRECISION - 1 - N)`. +/// In other words, a 1 ULP (absolute) error is the same as a `2^-(F::PRECISION-1)` relative error. +/// (Subtracting 1 compensates for the integer bit.) pub(crate) fn apply_random_float_error<F: rustc_apfloat::Float>( ecx: &mut crate::MiriInterpCx<'_>, val: F, @@ -11,12 +14,15 @@ pub(crate) fn apply_random_float_error<F: rustc_apfloat::Float>( ) -> F { let rng = ecx.machine.rng.get_mut(); // Generate a random integer in the range [0, 2^PREC). - let dist = rand::distributions::Uniform::new(0, 1 << F::PRECISION); - let err = F::from_u128(dist.sample(rng)) - .value - .scalbn(err_scale.strict_sub(F::PRECISION.try_into().unwrap())); + // (When read as binary, the position of the first `1` determines the exponent, + // and the remaining bits fill the mantissa. `PREC` is one plus the size of the mantissa, + // so this all works out.) + let r = F::from_u128(rng.random_range(0..(1 << F::PRECISION))).value; + // Multiply this with 2^(scale - PREC). The result is between 0 and + // 2^PREC * 2^(scale - PREC) = 2^scale. + let err = r.scalbn(err_scale.strict_sub(F::PRECISION.try_into().unwrap())); // give it a random sign - let err = if rng.gen::<bool>() { -err } else { err }; + let err = if rng.random() { -err } else { err }; // multiple the value with (1+err) (val * (F::from_u128(1).value + err).value).value } diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs index 0017a3991b5..c588b6fc7f1 100644 --- a/src/tools/miri/src/operator.rs +++ b/src/tools/miri/src/operator.rs @@ -108,11 +108,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Pick one of the NaNs. let nan = nans.choose(&mut *rand).unwrap(); // Non-deterministically flip the sign. - if rand.gen() { + if rand.random() { // This will properly flip even for NaN. -nan } else { nan } } + + fn equal_float_min_max<F: Float>(&self, a: F, b: F) -> F { + let this = self.eval_context_ref(); + // Return one side non-deterministically. + let mut rand = this.machine.rng.borrow_mut(); + if rand.random() { a } else { b } + } } diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs index 0fda13e0616..323b95d5f5f 100644 --- a/src/tools/miri/src/shims/alloc.rs +++ b/src/tools/miri/src/shims/alloc.rs @@ -81,7 +81,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn malloc(&mut self, size: u64, init: AllocInit) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); let align = this.malloc_align(size); - let ptr = this.allocate_ptr(Size::from_bytes(size), align, MiriMemoryKind::C.into(), init)?; + let ptr = + this.allocate_ptr(Size::from_bytes(size), align, MiriMemoryKind::C.into(), init)?; interp_ok(ptr.into()) } @@ -92,7 +93,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { size: &OpTy<'tcx>, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let memptr = this.deref_pointer(memptr)?; + let memptr = this.deref_pointer_as(memptr, this.machine.layouts.mut_raw_ptr)?; let align = this.read_target_usize(align)?; let size = this.read_target_usize(size)?; @@ -105,7 +106,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::C.into(), - AllocInit::Uninit + AllocInit::Uninit, )?; this.write_pointer(ptr, &memptr)?; interp_ok(Scalar::from_i32(0)) @@ -138,7 +139,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Size::from_bytes(new_size), new_align, MiriMemoryKind::C.into(), - AllocInit::Uninit + AllocInit::Uninit, )?; interp_ok(new_ptr.into()) } @@ -179,7 +180,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::C.into(), - AllocInit::Uninit + AllocInit::Uninit, )?; interp_ok(ptr.into()) } diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index 1622ef280d2..7e667e70a17 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -4,7 +4,6 @@ use rustc_middle::ty::{self, Instance, Ty}; use rustc_span::{BytePos, Loc, Symbol, hygiene}; use rustc_target::callconv::{Conv, FnAbi}; -use crate::helpers::check_min_arg_count; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -34,13 +33,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { abi: &FnAbi<'tcx, Ty<'tcx>>, link_name: Symbol, args: &[OpTy<'tcx>], - dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let tcx = this.tcx; + let ptr_ty = this.machine.layouts.mut_raw_ptr.ty; + let ptr_layout = this.layout_of(ptr_ty)?; + + let [flags, buf] = this.check_shim(abi, Conv::Rust, link_name, args)?; - let [flags] = check_min_arg_count("miri_get_backtrace", args)?; let flags = this.read_scalar(flags)?.to_u64()?; + let buf_place = this.deref_pointer_as(buf, ptr_layout)?; let mut data = Vec::new(); for frame in this.active_thread_stack().iter().rev() { @@ -63,44 +64,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }) .collect(); - let len: u64 = ptrs.len().try_into().unwrap(); - - let ptr_ty = this.machine.layouts.mut_raw_ptr.ty; - let array_layout = this.layout_of(Ty::new_array(tcx.tcx, ptr_ty, len)).unwrap(); - match flags { - // storage for pointers is allocated by miri - // deallocating the slice is undefined behavior with a custom global allocator 0 => { - let [_flags] = this.check_shim(abi, Conv::Rust, link_name, args)?; - - let alloc = this.allocate(array_layout, MiriMemoryKind::Rust.into())?; - - // Write pointers into array - for (i, ptr) in ptrs.into_iter().enumerate() { - let place = this.project_index(&alloc, i as u64)?; - - this.write_pointer(ptr, &place)?; - } - - this.write_immediate(Immediate::new_slice(alloc.ptr(), len, this), dest)?; + throw_unsup_format!("miri_get_backtrace: v0 is not supported any more"); } - // storage for pointers is allocated by the caller - 1 => { - let [_flags, buf] = this.check_shim(abi, Conv::Rust, link_name, args)?; - - let buf_place = this.deref_pointer(buf)?; - - let ptr_layout = this.layout_of(ptr_ty)?; - + 1 => for (i, ptr) in ptrs.into_iter().enumerate() { let offset = ptr_layout.size.checked_mul(i.try_into().unwrap(), this).unwrap(); let op_place = buf_place.offset(offset, ptr_layout, this)?; this.write_pointer(ptr, &op_place)?; - } - } + }, _ => throw_unsup_format!("unknown `miri_get_backtrace` flags {}", flags), }; diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs index f0aebfe1693..20dd3c8db2a 100644 --- a/src/tools/miri/src/shims/extern_static.rs +++ b/src/tools/miri/src/shims/extern_static.rs @@ -60,10 +60,10 @@ impl<'tcx> MiriMachine<'tcx> { match ecx.tcx.sess.target.os.as_ref() { "linux" => { - Self::null_ptr_extern_statics(ecx, &[ - "__cxa_thread_atexit_impl", - "__clock_gettime64", - ])?; + Self::null_ptr_extern_statics( + ecx, + &["__cxa_thread_atexit_impl", "__clock_gettime64"], + )?; Self::weak_symbol_extern_statics(ecx, &["getrandom", "statx"])?; } "freebsd" => { diff --git a/src/tools/miri/src/shims/files.rs b/src/tools/miri/src/shims/files.rs index 73425eee515..6b4f4cdc922 100644 --- a/src/tools/miri/src/shims/files.rs +++ b/src/tools/miri/src/shims/files.rs @@ -1,6 +1,6 @@ use std::any::Any; use std::collections::BTreeMap; -use std::io::{IsTerminal, Read, SeekFrom, Write}; +use std::io::{IsTerminal, SeekFrom, Write}; use std::marker::CoercePointee; use std::ops::Deref; use std::rc::{Rc, Weak}; @@ -140,8 +140,8 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt { _communicate_allowed: bool, _ptr: Pointer, _len: usize, - _dest: &MPlaceTy<'tcx>, _ecx: &mut MiriInterpCx<'tcx>, + _finish: DynMachineCallback<'tcx, Result<usize, IoError>>, ) -> InterpResult<'tcx> { throw_unsup_format!("cannot read from {}", self.name()); } @@ -154,8 +154,8 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt { _communicate_allowed: bool, _ptr: Pointer, _len: usize, - _dest: &MPlaceTy<'tcx>, _ecx: &mut MiriInterpCx<'tcx>, + _finish: DynMachineCallback<'tcx, Result<usize, IoError>>, ) -> InterpResult<'tcx> { throw_unsup_format!("cannot write to {}", self.name()); } @@ -207,19 +207,16 @@ impl FileDescription for io::Stdin { communicate_allowed: bool, ptr: Pointer, len: usize, - dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, + finish: DynMachineCallback<'tcx, Result<usize, IoError>>, ) -> InterpResult<'tcx> { - let mut bytes = vec![0; len]; if !communicate_allowed { // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin. helpers::isolation_abort_error("`read` from stdin")?; } - let result = Read::read(&mut &*self, &mut bytes); - match result { - Ok(read_size) => ecx.return_read_success(ptr, &bytes, read_size, dest), - Err(e) => ecx.set_last_error_and_return(e, dest), - } + + let result = ecx.read_from_host(&*self, len, ptr)?; + finish.call(ecx, result) } fn is_tty(&self, communicate_allowed: bool) -> bool { @@ -237,22 +234,19 @@ impl FileDescription for io::Stdout { _communicate_allowed: bool, ptr: Pointer, len: usize, - dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, + finish: DynMachineCallback<'tcx, Result<usize, IoError>>, ) -> InterpResult<'tcx> { - let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; - // We allow writing to stderr even with isolation enabled. - let result = Write::write(&mut &*self, bytes); + // We allow writing to stdout even with isolation enabled. + let result = ecx.write_to_host(&*self, len, ptr)?; // Stdout is buffered, flush to make sure it appears on the // screen. This is the write() syscall of the interpreted // program, we want it to correspond to a write() syscall on // the host -- there is no good in adding extra buffering // here. io::stdout().flush().unwrap(); - match result { - Ok(write_size) => ecx.return_write_success(write_size, dest), - Err(e) => ecx.set_last_error_and_return(e, dest), - } + + finish.call(ecx, result) } fn is_tty(&self, communicate_allowed: bool) -> bool { @@ -270,17 +264,13 @@ impl FileDescription for io::Stderr { _communicate_allowed: bool, ptr: Pointer, len: usize, - dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, + finish: DynMachineCallback<'tcx, Result<usize, IoError>>, ) -> InterpResult<'tcx> { - let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; // We allow writing to stderr even with isolation enabled. + let result = ecx.write_to_host(&*self, len, ptr)?; // No need to flush, stderr is not buffered. - let result = Write::write(&mut &*self, bytes); - match result { - Ok(write_size) => ecx.return_write_success(write_size, dest), - Err(e) => ecx.set_last_error_and_return(e, dest), - } + finish.call(ecx, result) } fn is_tty(&self, communicate_allowed: bool) -> bool { @@ -302,11 +292,11 @@ impl FileDescription for NullOutput { _communicate_allowed: bool, _ptr: Pointer, len: usize, - dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, + finish: DynMachineCallback<'tcx, Result<usize, IoError>>, ) -> InterpResult<'tcx> { // We just don't write anything, but report to the user that we did. - ecx.return_write_success(len, dest) + finish.call(ecx, Ok(len)) } } @@ -405,40 +395,41 @@ impl FdTable { impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { - /// Helper to implement `FileDescription::read`: - /// This is only used when `read` is successful. - /// `actual_read_size` should be the return value of some underlying `read` call that used - /// `bytes` as its output buffer. - /// The length of `bytes` must not exceed either the host's or the target's `isize`. - /// `bytes` is written to `buf` and the size is written to `dest`. - fn return_read_success( + /// Read data from a host `Read` type, store the result into machine memory, + /// and return whether that worked. + fn read_from_host( &mut self, - buf: Pointer, - bytes: &[u8], - actual_read_size: usize, - dest: &MPlaceTy<'tcx>, - ) -> InterpResult<'tcx> { + mut file: impl io::Read, + len: usize, + ptr: Pointer, + ) -> InterpResult<'tcx, Result<usize, IoError>> { let this = self.eval_context_mut(); - // If reading to `bytes` did not fail, we write those bytes to the buffer. - // Crucially, if fewer than `bytes.len()` bytes were read, only write - // that much into the output buffer! - this.write_bytes_ptr(buf, bytes[..actual_read_size].iter().copied())?; - // The actual read size is always less than what got originally requested so this cannot fail. - this.write_int(u64::try_from(actual_read_size).unwrap(), dest)?; - interp_ok(()) + let mut bytes = vec![0; len]; + let result = file.read(&mut bytes); + match result { + Ok(read_size) => { + // If reading to `bytes` did not fail, we write those bytes to the buffer. + // Crucially, if fewer than `bytes.len()` bytes were read, only write + // that much into the output buffer! + this.write_bytes_ptr(ptr, bytes[..read_size].iter().copied())?; + interp_ok(Ok(read_size)) + } + Err(e) => interp_ok(Err(IoError::HostError(e))), + } } - /// Helper to implement `FileDescription::write`: - /// This function is only used when `write` is successful, and writes `actual_write_size` to `dest` - fn return_write_success( + /// Write data to a host `Write` type, withthe bytes taken from machine memory. + fn write_to_host( &mut self, - actual_write_size: usize, - dest: &MPlaceTy<'tcx>, - ) -> InterpResult<'tcx> { + mut file: impl io::Write, + len: usize, + ptr: Pointer, + ) -> InterpResult<'tcx, Result<usize, IoError>> { let this = self.eval_context_mut(); - // The actual write size is always less than what got originally requested so this cannot fail. - this.write_int(u64::try_from(actual_write_size).unwrap(), dest)?; - interp_ok(()) + + let bytes = this.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; + let result = file.write(bytes); + interp_ok(result.map_err(IoError::HostError)) } } diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 1ce0c209de9..97bfb04f1f4 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -357,7 +357,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Obtains a Miri backtrace. See the README for details. "miri_get_backtrace" => { // `check_shim` happens inside `handle_miri_get_backtrace`. - this.handle_miri_get_backtrace(abi, link_name, args, dest)?; + this.handle_miri_get_backtrace(abi, link_name, args)?; } // Resolves a Miri backtrace frame. See the README for details. "miri_resolve_frame" => { @@ -509,7 +509,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { Size::from_bytes(size), Align::from_bytes(align).unwrap(), memory_kind.into(), - AllocInit::Uninit + AllocInit::Uninit, )?; ecx.write_pointer(ptr, dest) @@ -538,7 +538,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), - AllocInit::Zero + AllocInit::Zero, )?; this.write_pointer(ptr, dest) }); @@ -599,7 +599,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { Size::from_bytes(new_size), align, MiriMemoryKind::Rust.into(), - AllocInit::Uninit + AllocInit::Uninit, )?; this.write_pointer(new_ptr, dest) }); @@ -861,7 +861,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { "lgammaf_r" => { let [x, signp] = this.check_shim(abi, Conv::C, link_name, args)?; let x = this.read_scalar(x)?.to_f32()?; - let signp = this.deref_pointer(signp)?; + let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?; // Using host floats (but it's fine, these operations do not have guaranteed precision). let (res, sign) = x.to_host().ln_gamma(); @@ -872,7 +872,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { "lgamma_r" => { let [x, signp] = this.check_shim(abi, Conv::C, link_name, args)?; let x = this.read_scalar(x)?.to_f64()?; - let signp = this.deref_pointer(signp)?; + let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?; // Using host floats (but it's fine, these operations do not have guaranteed precision). let (res, sign) = x.to_host().ln_gamma(); diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index 93479540009..83f331bb173 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -247,10 +247,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Call the lang item associated with this message. let fn_item = this.tcx.require_lang_item(msg.panic_function(), None); let instance = ty::Instance::mono(this.tcx.tcx, fn_item); - this.call_function(instance, ExternAbi::Rust, &[], None, StackPopCleanup::Goto { - ret: None, - unwind, - })?; + this.call_function( + instance, + ExternAbi::Rust, + &[], + None, + StackPopCleanup::Goto { ret: None, unwind }, + )?; } } interp_ok(()) diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index d6c77d9c4d9..64b3ce6b4e4 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -132,16 +132,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.assert_target_os_is_unix("localtime_r"); this.check_no_isolation("`localtime_r`")?; - let timep = this.deref_pointer(timep)?; + let time_layout = this.libc_ty_layout("time_t"); + let timep = this.deref_pointer_as(timep, time_layout)?; let result = this.deref_pointer_as(result_op, this.libc_ty_layout("tm"))?; // The input "represents the number of seconds elapsed since the Epoch, // 1970-01-01 00:00:00 +0000 (UTC)". - let sec_since_epoch: i64 = this - .read_scalar(&timep)? - .to_int(this.libc_ty_layout("time_t").size)? - .try_into() - .unwrap(); + let sec_since_epoch: i64 = + this.read_scalar(&timep)?.to_int(time_layout.size)?.try_into().unwrap(); let dt_utc: DateTime<Utc> = DateTime::from_timestamp(sec_since_epoch, 0).expect("Invalid timestamp"); @@ -254,7 +252,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let qpc = i64::try_from(duration.as_nanos()).map_err(|_| { err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported") })?; - this.write_scalar(Scalar::from_i64(qpc), &this.deref_pointer(lpPerformanceCount_op)?)?; + this.write_scalar( + Scalar::from_i64(qpc), + &this.deref_pointer_as(lpPerformanceCount_op, this.machine.layouts.i64)?, + )?; interp_ok(Scalar::from_i32(-1)) // return non-zero on success } diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs index 8d5d4a52b6e..c7e2c4d507b 100644 --- a/src/tools/miri/src/shims/unix/android/thread.rs +++ b/src/tools/miri/src/shims/unix/android/thread.rs @@ -3,7 +3,7 @@ use rustc_middle::ty::Ty; use rustc_span::Symbol; use rustc_target::callconv::{Conv, FnAbi}; -use crate::helpers::check_min_arg_count; +use crate::helpers::check_min_vararg_count; use crate::shims::unix::thread::{EvalContextExt as _, ThreadNameResult}; use crate::*; @@ -16,18 +16,15 @@ pub fn prctl<'tcx>( args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { - // We do not use `check_shim` here because `prctl` is variadic. The argument - // count is checked bellow. - ecx.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?; + let ([op], varargs) = ecx.check_shim_variadic(abi, Conv::C, link_name, args)?; // FIXME: Use constants once https://github.com/rust-lang/libc/pull/3941 backported to the 0.2 branch. let pr_set_name = 15; let pr_get_name = 16; - let [op] = check_min_arg_count("prctl", args)?; let res = match ecx.read_scalar(op)?.to_i32()? { op if op == pr_set_name => { - let [_, name] = check_min_arg_count("prctl(PR_SET_NAME, ...)", args)?; + let [name] = check_min_vararg_count("prctl(PR_SET_NAME, ...)", varargs)?; let name = ecx.read_scalar(name)?; let thread = ecx.pthread_self()?; // The Linux kernel silently truncates long names. @@ -38,7 +35,7 @@ pub fn prctl<'tcx>( Scalar::from_u32(0) } op if op == pr_get_name => { - let [_, name] = check_min_arg_count("prctl(PR_GET_NAME, ...)", args)?; + let [name] = check_min_vararg_count("prctl(PR_GET_NAME, ...)", varargs)?; let name = ecx.read_scalar(name)?; let thread = ecx.pthread_self()?; let len = Scalar::from_target_usize(TASK_COMM_LEN as u64, ecx); diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 0b59490308b..3f85b9ae9bd 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -6,7 +6,7 @@ use std::io::ErrorKind; use rustc_abi::Size; -use crate::helpers::check_min_arg_count; +use crate::helpers::check_min_vararg_count; use crate::shims::files::FileDescription; use crate::shims::unix::linux_like::epoll::EpollReadyEvents; use crate::shims::unix::*; @@ -30,8 +30,8 @@ pub trait UnixFileDescription: FileDescription { _offset: u64, _ptr: Pointer, _len: usize, - _dest: &MPlaceTy<'tcx>, _ecx: &mut MiriInterpCx<'tcx>, + _finish: DynMachineCallback<'tcx, Result<usize, IoError>>, ) -> InterpResult<'tcx> { throw_unsup_format!("cannot pread from {}", self.name()); } @@ -46,8 +46,8 @@ pub trait UnixFileDescription: FileDescription { _ptr: Pointer, _len: usize, _offset: u64, - _dest: &MPlaceTy<'tcx>, _ecx: &mut MiriInterpCx<'tcx>, + _finish: DynMachineCallback<'tcx, Result<usize, IoError>>, ) -> InterpResult<'tcx> { throw_unsup_format!("cannot pwrite to {}", self.name()); } @@ -127,11 +127,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) } - fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> { + fn fcntl( + &mut self, + fd_num: &OpTy<'tcx>, + cmd: &OpTy<'tcx>, + varargs: &[OpTy<'tcx>], + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let [fd_num, cmd] = check_min_arg_count("fcntl", args)?; - let fd_num = this.read_scalar(fd_num)?.to_i32()?; let cmd = this.read_scalar(cmd)?.to_i32()?; @@ -163,7 +166,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "fcntl(fd, F_DUPFD_CLOEXEC, ...)" }; - let [_, _, start] = check_min_arg_count(cmd_name, args)?; + let [start] = check_min_vararg_count(cmd_name, varargs)?; let start = this.read_scalar(start)?.to_i32()?; if let Some(fd) = this.machine.fds.get(fd_num) { @@ -233,7 +236,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let count = usize::try_from(count).unwrap(); // now it fits in a `usize` let communicate = this.machine.communicate(); - // We temporarily dup the FD to be able to retain mutable access to `this`. + // Get the FD. let Some(fd) = this.machine.fds.get(fd_num) else { trace!("read: FD not found"); return this.set_last_error_and_return(LibcError("EBADF"), dest); @@ -244,13 +247,33 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // because it was a target's `usize`. Also we are sure that its smaller than // `usize::MAX` because it is bounded by the host's `isize`. + let finish = { + let dest = dest.clone(); + callback!( + @capture<'tcx> { + count: usize, + dest: MPlaceTy<'tcx>, + } + |this, result: Result<usize, IoError>| { + match result { + Ok(read_size) => { + assert!(read_size <= count); + // This must fit since `count` fits. + this.write_int(u64::try_from(read_size).unwrap(), &dest) + } + Err(e) => { + this.set_last_error_and_return(e, &dest) + } + }} + ) + }; match offset { - None => fd.read(communicate, buf, count, dest, this)?, + None => fd.read(communicate, buf, count, this, finish)?, Some(offset) => { let Ok(offset) = u64::try_from(offset) else { return this.set_last_error_and_return(LibcError("EINVAL"), dest); }; - fd.as_unix().pread(communicate, offset, buf, count, dest, this)? + fd.as_unix().pread(communicate, offset, buf, count, this, finish)? } }; interp_ok(()) @@ -284,13 +307,33 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return this.set_last_error_and_return(LibcError("EBADF"), dest); }; + let finish = { + let dest = dest.clone(); + callback!( + @capture<'tcx> { + count: usize, + dest: MPlaceTy<'tcx>, + } + |this, result: Result<usize, IoError>| { + match result { + Ok(write_size) => { + assert!(write_size <= count); + // This must fit since `count` fits. + this.write_int(u64::try_from(write_size).unwrap(), &dest) + } + Err(e) => { + this.set_last_error_and_return(e, &dest) + } + }} + ) + }; match offset { - None => fd.write(communicate, buf, count, dest, this)?, + None => fd.write(communicate, buf, count, this, finish)?, Some(offset) => { let Ok(offset) = u64::try_from(offset) else { return this.set_last_error_and_return(LibcError("EINVAL"), dest); }; - fd.as_unix().pwrite(communicate, buf, count, offset, dest, this)? + fd.as_unix().pwrite(communicate, buf, count, offset, this, finish)? } }; interp_ok(()) diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 3353cf2cc59..d459ec7cb77 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -205,10 +205,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "fcntl" => { - // `fcntl` is variadic. The argument count is checked based on the first argument - // in `this.fcntl()`, so we do not use `check_shim` here. - this.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?; - let result = this.fcntl(args)?; + let ([fd_num, cmd], varargs) = + this.check_shim_variadic(abi, Conv::C, link_name, args)?; + let result = this.fcntl(fd_num, cmd, varargs)?; this.write_scalar(result, dest)?; } "dup" => { @@ -236,8 +235,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "open" | "open64" => { // `open` is variadic, the third argument is only present when the second argument // has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set - this.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?; - let result = this.open(args)?; + let ([path_raw, flag], varargs) = + this.check_shim_variadic(abi, Conv::C, link_name, args)?; + let result = this.open(path_raw, flag, varargs)?; this.write_scalar(result, dest)?; } "unlink" => { @@ -354,10 +354,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pipe2" => { // Currently this function does not exist on all Unixes, e.g. on macOS. - if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "solaris" | "illumos") - { - throw_unsup_format!("`pipe2` is not supported on {}", this.tcx.sess.target.os); - } + this.check_target_os(&["linux", "freebsd", "solaris", "illumos"], link_name)?; let [pipefd, flags] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.pipe2(pipefd, Some(flags))?; this.write_scalar(result, dest)?; @@ -402,12 +399,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "reallocarray" => { // Currently this function does not exist on all Unixes, e.g. on macOS. - if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "android") { - throw_unsup_format!( - "`reallocarray` is not supported on {}", - this.tcx.sess.target.os - ); - } + this.check_target_os(&["linux", "freebsd", "android"], link_name)?; let [ptr, nmemb, size] = this.check_shim(abi, Conv::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; let nmemb = this.read_target_usize(nmemb)?; @@ -656,13 +648,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "sched_getaffinity" => { // Currently this function does not exist on all Unixes, e.g. on macOS. - if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "android") { - throw_unsup_format!( - "`sched_getaffinity` is not supported on {}", - this.tcx.sess.target.os - ); - } - + this.check_target_os(&["linux", "freebsd", "android"], link_name)?; let [pid, cpusetsize, mask] = this.check_shim(abi, Conv::C, link_name, args)?; let pid = this.read_scalar(pid)?.to_u32()?; let cpusetsize = this.read_target_usize(cpusetsize)?; @@ -699,13 +685,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "sched_setaffinity" => { // Currently this function does not exist on all Unixes, e.g. on macOS. - if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "android") { - throw_unsup_format!( - "`sched_setaffinity` is not supported on {}", - this.tcx.sess.target.os - ); - } - + this.check_target_os(&["linux", "freebsd", "android"], link_name)?; let [pid, cpusetsize, mask] = this.check_shim(abi, Conv::C, link_name, args)?; let pid = this.read_scalar(pid)?.to_u32()?; let cpusetsize = this.read_target_usize(cpusetsize)?; @@ -761,16 +741,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "getentropy" => { // This function is non-standard but exists with the same signature and behavior on // Linux, macOS, FreeBSD and Solaris/Illumos. - if !matches!( - &*this.tcx.sess.target.os, - "linux" | "macos" | "freebsd" | "illumos" | "solaris" | "android" - ) { - throw_unsup_format!( - "`getentropy` is not supported on {}", - this.tcx.sess.target.os - ); - } - + this.check_target_os( + &["linux", "macos", "freebsd", "illumos", "solaris", "android"], + link_name, + )?; let [buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?; let buf = this.read_pointer(buf)?; let bufsize = this.read_target_usize(bufsize)?; @@ -797,15 +771,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "getrandom" => { // This function is non-standard but exists with the same signature and behavior on // Linux, FreeBSD and Solaris/Illumos. - if !matches!( - &*this.tcx.sess.target.os, - "linux" | "freebsd" | "illumos" | "solaris" | "android" - ) { - throw_unsup_format!( - "`getrandom` is not supported on {}", - this.tcx.sess.target.os - ); - } + this.check_target_os( + &["linux", "freebsd", "illumos", "solaris", "android"], + link_name, + )?; let [ptr, len, flags] = this.check_shim(abi, Conv::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; let len = this.read_target_usize(len)?; @@ -817,12 +786,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "arc4random_buf" => { // This function is non-standard but exists with the same signature and // same behavior (eg never fails) on FreeBSD and Solaris/Illumos. - if !matches!(&*this.tcx.sess.target.os, "freebsd" | "illumos" | "solaris") { - throw_unsup_format!( - "`arc4random_buf` is not supported on {}", - this.tcx.sess.target.os - ); - } + this.check_target_os(&["freebsd", "illumos", "solaris"], link_name)?; let [ptr, len] = this.check_shim(abi, Conv::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; let len = this.read_target_usize(len)?; @@ -842,15 +806,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // For arm32 they did something custom, but similar enough that the same // `_Unwind_RaiseException` impl in miri should work: // https://github.com/ARM-software/abi-aa/blob/main/ehabi32/ehabi32.rst - if !matches!( - &*this.tcx.sess.target.os, - "linux" | "freebsd" | "illumos" | "solaris" | "android" | "macos" - ) { - throw_unsup_format!( - "`_Unwind_RaiseException` is not supported on {}", - this.tcx.sess.target.os - ); - } + this.check_target_os( + &["linux", "freebsd", "illumos", "solaris", "android", "macos"], + link_name, + )?; // This function looks and behaves excatly like miri_start_unwind. let [payload] = this.check_shim(abi, Conv::C, link_name, args)?; this.handle_miri_start_unwind(payload)?; @@ -866,8 +825,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" if this.frame_in_std() => { let [_attr, guard_size] = this.check_shim(abi, Conv::C, link_name, args)?; - let guard_size = this.deref_pointer(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t"); + let guard_size = this.deref_pointer_as(guard_size, guard_size_layout)?; this.write_scalar( Scalar::from_uint(this.machine.page_size, guard_size_layout.size), &guard_size, @@ -893,8 +852,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.check_shim(abi, Conv::C, link_name, args)?; let _attr_place = this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?; - let addr_place = this.deref_pointer(addr_place)?; - let size_place = this.deref_pointer(size_place)?; + let addr_place = this.deref_pointer_as(addr_place, this.machine.layouts.usize)?; + let size_place = this.deref_pointer_as(size_place, this.machine.layouts.usize)?; this.write_scalar( Scalar::from_uint(this.machine.stack_addr, this.pointer_size()), @@ -928,7 +887,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let pwd = this.deref_pointer_as(pwd, this.libc_ty_layout("passwd"))?; let buf = this.read_pointer(buf)?; let buflen = this.read_target_usize(buflen)?; - let result = this.deref_pointer(result)?; + let result = this.deref_pointer_as(result, this.machine.layouts.mut_raw_ptr)?; // Must be for "us". if uid != UID { diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 03dbd931329..08d06fe5d4c 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -60,17 +60,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // since freebsd 12 the former form can be expected. "stat" | "stat@FBSD_1.0" => { let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?; - let result = this.macos_fbsd_solaris_stat(path, buf)?; + let result = this.macos_fbsd_solarish_stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" | "lstat@FBSD_1.0" => { let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?; - let result = this.macos_fbsd_solaris_lstat(path, buf)?; + let result = this.macos_fbsd_solarish_lstat(path, buf)?; this.write_scalar(result, dest)?; } "fstat" | "fstat@FBSD_1.0" => { let [fd, buf] = this.check_shim(abi, Conv::C, link_name, args)?; - let result = this.macos_fbsd_solaris_fstat(fd, buf)?; + let result = this.macos_fbsd_solarish_fstat(fd, buf)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r@FBSD_1.0" => { diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index cafce62cfed..c7399b00d3f 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -13,7 +13,7 @@ use rustc_abi::Size; use rustc_data_structures::fx::FxHashMap; use self::shims::time::system_time_to_duration; -use crate::helpers::check_min_arg_count; +use crate::helpers::check_min_vararg_count; use crate::shims::files::{EvalContextExt as _, FileDescription, FileDescriptionRef}; use crate::shims::os_str::bytes_to_os_str; use crate::shims::unix::fd::{FlockOp, UnixFileDescription}; @@ -35,16 +35,13 @@ impl FileDescription for FileHandle { communicate_allowed: bool, ptr: Pointer, len: usize, - dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, + finish: DynMachineCallback<'tcx, Result<usize, IoError>>, ) -> InterpResult<'tcx> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); - let mut bytes = vec![0; len]; - let result = (&mut &self.file).read(&mut bytes); - match result { - Ok(read_size) => ecx.return_read_success(ptr, &bytes, read_size, dest), - Err(e) => ecx.set_last_error_and_return(e, dest), - } + + let result = ecx.read_from_host(&self.file, len, ptr)?; + finish.call(ecx, result) } fn write<'tcx>( @@ -52,16 +49,13 @@ impl FileDescription for FileHandle { communicate_allowed: bool, ptr: Pointer, len: usize, - dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, + finish: DynMachineCallback<'tcx, Result<usize, IoError>>, ) -> InterpResult<'tcx> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); - let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; - let result = (&mut &self.file).write(bytes); - match result { - Ok(write_size) => ecx.return_write_success(write_size, dest), - Err(e) => ecx.set_last_error_and_return(e, dest), - } + + let result = ecx.write_to_host(&self.file, len, ptr)?; + finish.call(ecx, result) } fn seek<'tcx>( @@ -119,8 +113,8 @@ impl UnixFileDescription for FileHandle { offset: u64, ptr: Pointer, len: usize, - dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, + finish: DynMachineCallback<'tcx, Result<usize, IoError>>, ) -> InterpResult<'tcx> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); let mut bytes = vec![0; len]; @@ -137,11 +131,17 @@ impl UnixFileDescription for FileHandle { .expect("failed to restore file position, this shouldn't be possible"); res }; - let result = f(); - match result { - Ok(read_size) => ecx.return_read_success(ptr, &bytes, read_size, dest), - Err(e) => ecx.set_last_error_and_return(e, dest), - } + let result = match f() { + Ok(read_size) => { + // If reading to `bytes` did not fail, we write those bytes to the buffer. + // Crucially, if fewer than `bytes.len()` bytes were read, only write + // that much into the output buffer! + ecx.write_bytes_ptr(ptr, bytes[..read_size].iter().copied())?; + Ok(read_size) + } + Err(e) => Err(IoError::HostError(e)), + }; + finish.call(ecx, result) } fn pwrite<'tcx>( @@ -150,8 +150,8 @@ impl UnixFileDescription for FileHandle { ptr: Pointer, len: usize, offset: u64, - dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, + finish: DynMachineCallback<'tcx, Result<usize, IoError>>, ) -> InterpResult<'tcx> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); // Emulates pwrite using seek + write + seek to restore cursor position. @@ -169,10 +169,7 @@ impl UnixFileDescription for FileHandle { res }; let result = f(); - match result { - Ok(write_size) => ecx.return_write_success(write_size, dest), - Err(e) => ecx.set_last_error_and_return(e, dest), - } + finish.call(ecx, result.map_err(IoError::HostError)) } fn flock<'tcx>( @@ -273,7 +270,7 @@ impl UnixFileDescription for FileHandle { impl<'tcx> EvalContextExtPrivate<'tcx> for crate::MiriInterpCx<'tcx> {} trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> { - fn macos_fbsd_solaris_write_buf( + fn macos_fbsd_solarish_write_stat_buf( &mut self, metadata: FileMetadata, buf_op: &OpTy<'tcx>, @@ -321,9 +318,9 @@ trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> { } if matches!(&*this.tcx.sess.target.os, "solaris" | "illumos") { - // FIXME: write st_fstype field once libc is updated. - // https://github.com/rust-lang/libc/pull/4145 - //this.write_int_fields_named(&[("st_fstype", 0)], &buf)?; + let st_fstype = this.project_field_named(&buf, "st_fstype")?; + // This is an array; write 0 into first element so that it encodes the empty string. + this.write_int(0, &this.project_index(&st_fstype, 0)?)?; } interp_ok(0) @@ -452,9 +449,12 @@ fn maybe_sync_file( impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { - fn open(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> { - let [path_raw, flag] = check_min_arg_count("open", args)?; - + fn open( + &mut self, + path_raw: &OpTy<'tcx>, + flag: &OpTy<'tcx>, + varargs: &[OpTy<'tcx>], + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let path_raw = this.read_pointer(path_raw)?; @@ -507,7 +507,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Get the mode. On macOS, the argument type `mode_t` is actually `u16`, but // C integer promotion rules mean that on the ABI level, it gets passed as `u32` // (see https://github.com/rust-lang/rust/issues/71915). - let [_, _, mode] = check_min_arg_count("open(pathname, O_CREAT, ...)", args)?; + let [mode] = check_min_vararg_count("open(pathname, O_CREAT, ...)", varargs)?; let mode = this.read_scalar(mode)?.to_u32()?; #[cfg(unix)] @@ -668,7 +668,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) } - fn macos_fbsd_solaris_stat( + fn macos_fbsd_solarish_stat( &mut self, path_op: &OpTy<'tcx>, buf_op: &OpTy<'tcx>, @@ -694,11 +694,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Err(err) => return this.set_last_error_and_return_i32(err), }; - interp_ok(Scalar::from_i32(this.macos_fbsd_solaris_write_buf(metadata, buf_op)?)) + interp_ok(Scalar::from_i32(this.macos_fbsd_solarish_write_stat_buf(metadata, buf_op)?)) } // `lstat` is used to get symlink metadata. - fn macos_fbsd_solaris_lstat( + fn macos_fbsd_solarish_lstat( &mut self, path_op: &OpTy<'tcx>, buf_op: &OpTy<'tcx>, @@ -726,10 +726,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Err(err) => return this.set_last_error_and_return_i32(err), }; - interp_ok(Scalar::from_i32(this.macos_fbsd_solaris_write_buf(metadata, buf_op)?)) + interp_ok(Scalar::from_i32(this.macos_fbsd_solarish_write_stat_buf(metadata, buf_op)?)) } - fn macos_fbsd_solaris_fstat( + fn macos_fbsd_solarish_fstat( &mut self, fd_op: &OpTy<'tcx>, buf_op: &OpTy<'tcx>, @@ -756,7 +756,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(metadata) => metadata, Err(err) => return this.set_last_error_and_return_i32(err), }; - interp_ok(Scalar::from_i32(this.macos_fbsd_solaris_write_buf(metadata, buf_op)?)) + interp_ok(Scalar::from_i32(this.macos_fbsd_solarish_write_stat_buf(metadata, buf_op)?)) } fn linux_statx( @@ -1109,7 +1109,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Size::from_bytes(size), dirent_layout.align.abi, MiriMemoryKind::Runtime.into(), - AllocInit::Uninit + AllocInit::Uninit, )?; let entry: Pointer = entry.into(); @@ -1169,6 +1169,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } let dirp = this.read_target_usize(dirp_op)?; + let result_place = this.deref_pointer_as(result_op, this.machine.layouts.mut_raw_ptr)?; // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { @@ -1254,15 +1255,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } _ => unreachable!(), } - - let result_place = this.deref_pointer(result_op)?; this.write_scalar(this.read_scalar(entry_op)?, &result_place)?; Scalar::from_i32(0) } None => { // end of stream: return 0, assign *result=NULL - this.write_null(&this.deref_pointer(result_op)?)?; + this.write_null(&result_place)?; Scalar::from_i32(0) } Some(Err(e)) => { @@ -1548,7 +1547,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } fn mkstemp(&mut self, template_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { - use rand::seq::SliceRandom; + use rand::seq::IndexedRandom; // POSIX defines the template string. const TEMPFILE_TEMPLATE_STR: &str = "XXXXXX"; diff --git a/src/tools/miri/src/shims/unix/linux/mem.rs b/src/tools/miri/src/shims/unix/linux/mem.rs index 6418d749d3d..8e5a3021b1c 100644 --- a/src/tools/miri/src/shims/unix/linux/mem.rs +++ b/src/tools/miri/src/shims/unix/linux/mem.rs @@ -49,7 +49,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Size::from_bytes(new_size), align, MiriMemoryKind::Mmap.into(), - AllocInit::Zero + AllocInit::Zero, )?; interp_ok(Scalar::from_pointer(ptr, this)) diff --git a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs index 4b76bbb2b4d..936d436bd82 100644 --- a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs +++ b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs @@ -51,20 +51,20 @@ impl FileDescription for EventFd { _communicate_allowed: bool, ptr: Pointer, len: usize, - dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, + finish: DynMachineCallback<'tcx, Result<usize, IoError>>, ) -> InterpResult<'tcx> { // We're treating the buffer as a `u64`. let ty = ecx.machine.layouts.u64; // Check the size of slice, and return error only if the size of the slice < 8. if len < ty.size.bytes_usize() { - return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest); + return finish.call(ecx, Err(ErrorKind::InvalidInput.into())); } // Turn the pointer into a place at the right type. let buf_place = ecx.ptr_to_mplace_unaligned(ptr, ty); - eventfd_read(buf_place, dest, self, ecx) + eventfd_read(buf_place, self, ecx, finish) } /// A write call adds the 8-byte integer value supplied in @@ -84,20 +84,20 @@ impl FileDescription for EventFd { _communicate_allowed: bool, ptr: Pointer, len: usize, - dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, + finish: DynMachineCallback<'tcx, Result<usize, IoError>>, ) -> InterpResult<'tcx> { // We're treating the buffer as a `u64`. let ty = ecx.machine.layouts.u64; // Check the size of slice, and return error only if the size of the slice < 8. if len < ty.layout.size.bytes_usize() { - return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest); + return finish.call(ecx, Err(ErrorKind::InvalidInput.into())); } // Turn the pointer into a place at the right type. let buf_place = ecx.ptr_to_mplace_unaligned(ptr, ty); - eventfd_write(buf_place, dest, self, ecx) + eventfd_write(buf_place, self, ecx, finish) } fn as_unix(&self) -> &dyn UnixFileDescription { @@ -183,15 +183,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// else just add the user-supplied value to current counter. fn eventfd_write<'tcx>( buf_place: MPlaceTy<'tcx>, - dest: &MPlaceTy<'tcx>, eventfd: FileDescriptionRef<EventFd>, ecx: &mut MiriInterpCx<'tcx>, + finish: DynMachineCallback<'tcx, Result<usize, IoError>>, ) -> InterpResult<'tcx> { // Figure out which value we should add. let num = ecx.read_scalar(&buf_place)?.to_u64()?; // u64::MAX as input is invalid because the maximum value of counter is u64::MAX - 1. if num == u64::MAX { - return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest); + return finish.call(ecx, Err(ErrorKind::InvalidInput.into())); } match eventfd.counter.get().checked_add(num) { @@ -219,16 +219,14 @@ fn eventfd_write<'tcx>( ecx.check_and_update_readiness(eventfd)?; // Return how many bytes we consumed from the user-provided buffer. - return ecx.write_int(buf_place.layout.size.bytes(), dest); + return finish.call(ecx, Ok(buf_place.layout.size.bytes_usize())); } None | Some(u64::MAX) => { // We can't update the state, so we have to block. if eventfd.is_nonblock { - return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest); + return finish.call(ecx, Err(ErrorKind::WouldBlock.into())); } - let dest = dest.clone(); - eventfd.blocked_write_tid.borrow_mut().push(ecx.active_thread()); let weak_eventfd = FileDescriptionRef::downgrade(&eventfd); @@ -239,7 +237,7 @@ fn eventfd_write<'tcx>( @capture<'tcx> { num: u64, buf_place: MPlaceTy<'tcx>, - dest: MPlaceTy<'tcx>, + finish: DynMachineCallback<'tcx, Result<usize, IoError>>, weak_eventfd: WeakFileDescriptionRef<EventFd>, } |this, unblock: UnblockKind| { @@ -247,7 +245,7 @@ fn eventfd_write<'tcx>( // When we get unblocked, try again. We know the ref is still valid, // otherwise there couldn't be a `write` that unblocks us. let eventfd_ref = weak_eventfd.upgrade().unwrap(); - eventfd_write(buf_place, &dest, eventfd_ref, this) + eventfd_write(buf_place, eventfd_ref, this, finish) } ), ); @@ -260,9 +258,9 @@ fn eventfd_write<'tcx>( /// else just return the current counter value to the caller and set the counter to 0. fn eventfd_read<'tcx>( buf_place: MPlaceTy<'tcx>, - dest: &MPlaceTy<'tcx>, eventfd: FileDescriptionRef<EventFd>, ecx: &mut MiriInterpCx<'tcx>, + finish: DynMachineCallback<'tcx, Result<usize, IoError>>, ) -> InterpResult<'tcx> { // Set counter to 0, get old value. let counter = eventfd.counter.replace(0); @@ -270,9 +268,8 @@ fn eventfd_read<'tcx>( // Block when counter == 0. if counter == 0 { if eventfd.is_nonblock { - return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest); + return finish.call(ecx, Err(ErrorKind::WouldBlock.into())); } - let dest = dest.clone(); eventfd.blocked_read_tid.borrow_mut().push(ecx.active_thread()); @@ -283,7 +280,7 @@ fn eventfd_read<'tcx>( callback!( @capture<'tcx> { buf_place: MPlaceTy<'tcx>, - dest: MPlaceTy<'tcx>, + finish: DynMachineCallback<'tcx, Result<usize, IoError>>, weak_eventfd: WeakFileDescriptionRef<EventFd>, } |this, unblock: UnblockKind| { @@ -291,7 +288,7 @@ fn eventfd_read<'tcx>( // When we get unblocked, try again. We know the ref is still valid, // otherwise there couldn't be a `write` that unblocks us. let eventfd_ref = weak_eventfd.upgrade().unwrap(); - eventfd_read(buf_place, &dest, eventfd_ref, this) + eventfd_read(buf_place, eventfd_ref, this, finish) } ), ); @@ -317,7 +314,7 @@ fn eventfd_read<'tcx>( ecx.check_and_update_readiness(eventfd)?; // Tell userspace how many bytes we put into the buffer. - return ecx.write_int(buf_place.layout.size.bytes(), dest); + return finish.call(ecx, Ok(buf_place.layout.size.bytes_usize())); } interp_ok(()) } diff --git a/src/tools/miri/src/shims/unix/linux_like/sync.rs b/src/tools/miri/src/shims/unix/linux_like/sync.rs index 51124fb2a00..280bee4800f 100644 --- a/src/tools/miri/src/shims/unix/linux_like/sync.rs +++ b/src/tools/miri/src/shims/unix/linux_like/sync.rs @@ -1,5 +1,5 @@ use crate::concurrency::sync::FutexRef; -use crate::helpers::check_min_arg_count; +use crate::helpers::check_min_vararg_count; use crate::*; struct LinuxFutex { @@ -10,7 +10,7 @@ struct LinuxFutex { /// `args` is the arguments *including* the syscall number. pub fn futex<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - args: &[OpTy<'tcx>], + varargs: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { // The amount of arguments used depends on the type of futex operation. @@ -21,7 +21,7 @@ pub fn futex<'tcx>( // may or may not be left out from the `syscall()` call. // Therefore we don't use `check_arg_count` here, but only check for the // number of arguments to fall within a range. - let [_, addr, op, val] = check_min_arg_count("`syscall(SYS_futex, ...)`", args)?; + let [addr, op, val] = check_min_vararg_count("`syscall(SYS_futex, ...)`", varargs)?; // The first three arguments (after the syscall number itself) are the same to all futex operations: // (int *addr, int op, int val). @@ -55,14 +55,16 @@ pub fn futex<'tcx>( let wait_bitset = op & !futex_realtime == futex_wait_bitset; let (timeout, bitset) = if wait_bitset { - let [_, _, _, _, timeout, uaddr2, bitset] = - check_min_arg_count("`syscall(SYS_futex, FUTEX_WAIT_BITSET, ...)`", args)?; + let [_, _, _, timeout, uaddr2, bitset] = check_min_vararg_count( + "`syscall(SYS_futex, FUTEX_WAIT_BITSET, ...)`", + varargs, + )?; let _timeout = ecx.read_pointer(timeout)?; let _uaddr2 = ecx.read_pointer(uaddr2)?; (timeout, ecx.read_scalar(bitset)?.to_u32()?) } else { - let [_, _, _, _, timeout] = - check_min_arg_count("`syscall(SYS_futex, FUTEX_WAIT, ...)`", args)?; + let [_, _, _, timeout] = + check_min_vararg_count("`syscall(SYS_futex, FUTEX_WAIT, ...)`", varargs)?; (timeout, u32::MAX) }; @@ -156,14 +158,24 @@ pub fn futex<'tcx>( .futex .clone(); + let dest = dest.clone(); ecx.futex_wait( futex_ref, bitset, timeout, - Scalar::from_target_isize(0, ecx), // retval_succ - Scalar::from_target_isize(-1, ecx), // retval_timeout - dest.clone(), - LibcError("ETIMEDOUT"), // errno_timeout + callback!( + @capture<'tcx> { + dest: MPlaceTy<'tcx>, + } + |ecx, unblock: UnblockKind| match unblock { + UnblockKind::Ready => { + ecx.write_int(0, &dest) + } + UnblockKind::TimedOut => { + ecx.set_last_error_and_return(LibcError("ETIMEDOUT"), &dest) + } + } + ), ); } else { // The futex value doesn't match the expected value, so we return failure @@ -190,8 +202,10 @@ pub fn futex<'tcx>( let futex_ref = futex_ref.futex.clone(); let bitset = if op == futex_wake_bitset { - let [_, _, _, _, timeout, uaddr2, bitset] = - check_min_arg_count("`syscall(SYS_futex, FUTEX_WAKE_BITSET, ...)`", args)?; + let [_, _, _, timeout, uaddr2, bitset] = check_min_vararg_count( + "`syscall(SYS_futex, FUTEX_WAKE_BITSET, ...)`", + varargs, + )?; let _timeout = ecx.read_pointer(timeout)?; let _uaddr2 = ecx.read_pointer(uaddr2)?; ecx.read_scalar(bitset)?.to_u32()? @@ -205,16 +219,8 @@ pub fn futex<'tcx>( // will see the latest value on addr which could be changed by our caller // before doing the syscall. ecx.atomic_fence(AtomicFenceOrd::SeqCst)?; - let mut n = 0; - #[expect(clippy::arithmetic_side_effects)] - for _ in 0..val { - if ecx.futex_wake(&futex_ref, bitset)? { - n += 1; - } else { - break; - } - } - ecx.write_scalar(Scalar::from_target_isize(n, ecx), dest)?; + let woken = ecx.futex_wake(&futex_ref, bitset, val.try_into().unwrap())?; + ecx.write_scalar(Scalar::from_target_isize(woken.try_into().unwrap(), ecx), dest)?; } op => throw_unsup_format!("Miri does not support `futex` syscall with op={}", op), } diff --git a/src/tools/miri/src/shims/unix/linux_like/syscall.rs b/src/tools/miri/src/shims/unix/linux_like/syscall.rs index 5fb262e176f..22c6dc97507 100644 --- a/src/tools/miri/src/shims/unix/linux_like/syscall.rs +++ b/src/tools/miri/src/shims/unix/linux_like/syscall.rs @@ -2,7 +2,7 @@ use rustc_middle::ty::Ty; use rustc_span::Symbol; use rustc_target::callconv::{Conv, FnAbi}; -use crate::helpers::check_min_arg_count; +use crate::helpers::check_min_vararg_count; use crate::shims::unix::linux_like::eventfd::EvalContextExt as _; use crate::shims::unix::linux_like::sync::futex; use crate::*; @@ -14,9 +14,7 @@ pub fn syscall<'tcx>( args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { - // We do not use `check_shim` here because `syscall` is variadic. The argument - // count is checked bellow. - ecx.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?; + let ([op], varargs) = ecx.check_shim_variadic(abi, Conv::C, link_name, args)?; // The syscall variadic function is legal to call with more arguments than needed, // extra arguments are simply ignored. The important check is that when we use an // argument, we have to also check all arguments *before* it to ensure that they @@ -26,14 +24,13 @@ pub fn syscall<'tcx>( let sys_futex = ecx.eval_libc("SYS_futex").to_target_usize(ecx)?; let sys_eventfd2 = ecx.eval_libc("SYS_eventfd2").to_target_usize(ecx)?; - let [op] = check_min_arg_count("syscall", args)?; match ecx.read_target_usize(op)? { // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way (e.g. HashMap<K, V>). num if num == sys_getrandom => { // Used by getrandom 0.1 // The first argument is the syscall id, so skip over it. - let [_, ptr, len, flags] = check_min_arg_count("syscall(SYS_getrandom, ...)", args)?; + let [ptr, len, flags] = check_min_vararg_count("syscall(SYS_getrandom, ...)", varargs)?; let ptr = ecx.read_pointer(ptr)?; let len = ecx.read_target_usize(len)?; @@ -47,10 +44,10 @@ pub fn syscall<'tcx>( } // `futex` is used by some synchronization primitives. num if num == sys_futex => { - futex(ecx, args, dest)?; + futex(ecx, varargs, dest)?; } num if num == sys_eventfd2 => { - let [_, initval, flags] = check_min_arg_count("syscall(SYS_evetfd2, ...)", args)?; + let [initval, flags] = check_min_vararg_count("syscall(SYS_evetfd2, ...)", varargs)?; let result = ecx.eventfd(initval, flags)?; ecx.write_int(result.to_i32()?, dest)?; diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index 85c963774a1..918fd8dd52d 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -2,13 +2,20 @@ use rustc_middle::ty::Ty; use rustc_span::Symbol; use rustc_target::callconv::{Conv, FnAbi}; -use super::sync::EvalContextExt as _; -use crate::helpers::check_min_arg_count; +use super::sync::{EvalContextExt as _, MacOsFutexTimeout}; use crate::shims::unix::*; use crate::*; -pub fn is_dyn_sym(_name: &str) -> bool { - false +pub fn is_dyn_sym(name: &str) -> bool { + match name { + // These only became available with macOS 11.0, so std looks them up dynamically. + "os_sync_wait_on_address" + | "os_sync_wait_on_address_with_deadline" + | "os_sync_wait_on_address_with_timeout" + | "os_sync_wake_by_address_any" + | "os_sync_wake_by_address_all" => true, + _ => false, + } } impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -40,17 +47,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "stat" | "stat64" | "stat$INODE64" => { let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?; - let result = this.macos_fbsd_solaris_stat(path, buf)?; + let result = this.macos_fbsd_solarish_stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" | "lstat64" | "lstat$INODE64" => { let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?; - let result = this.macos_fbsd_solaris_lstat(path, buf)?; + let result = this.macos_fbsd_solarish_lstat(path, buf)?; this.write_scalar(result, dest)?; } "fstat" | "fstat64" | "fstat$INODE64" => { let [fd, buf] = this.check_shim(abi, Conv::C, link_name, args)?; - let result = this.macos_fbsd_solaris_fstat(fd, buf)?; + let result = this.macos_fbsd_solarish_fstat(fd, buf)?; this.write_scalar(result, dest)?; } "opendir$INODE64" => { @@ -69,10 +76,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "ioctl" => { - // `ioctl` is variadic. The argument count is checked based on the first argument - // in `this.ioctl()`, so we do not use `check_shim` here. - this.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?; - let result = this.ioctl(args)?; + let ([fd_num, cmd], varargs) = + this.check_shim_variadic(abi, Conv::C, link_name, args)?; + let result = this.ioctl(fd_num, cmd, varargs)?; this.write_scalar(result, dest)?; } @@ -216,6 +222,58 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } + // Futex primitives + "os_sync_wait_on_address" => { + let [addr_op, value_op, size_op, flags_op] = + this.check_shim(abi, Conv::C, link_name, args)?; + this.os_sync_wait_on_address( + addr_op, + value_op, + size_op, + flags_op, + MacOsFutexTimeout::None, + dest, + )?; + } + "os_sync_wait_on_address_with_deadline" => { + let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] = + this.check_shim(abi, Conv::C, link_name, args)?; + this.os_sync_wait_on_address( + addr_op, + value_op, + size_op, + flags_op, + MacOsFutexTimeout::Absolute { clock_op, timeout_op }, + dest, + )?; + } + "os_sync_wait_on_address_with_timeout" => { + let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] = + this.check_shim(abi, Conv::C, link_name, args)?; + this.os_sync_wait_on_address( + addr_op, + value_op, + size_op, + flags_op, + MacOsFutexTimeout::Relative { clock_op, timeout_op }, + dest, + )?; + } + "os_sync_wake_by_address_any" => { + let [addr_op, size_op, flags_op] = + this.check_shim(abi, Conv::C, link_name, args)?; + this.os_sync_wake_by_address( + addr_op, size_op, flags_op, /* all */ false, dest, + )?; + } + "os_sync_wake_by_address_all" => { + let [addr_op, size_op, flags_op] = + this.check_shim(abi, Conv::C, link_name, args)?; + this.os_sync_wake_by_address( + addr_op, size_op, flags_op, /* all */ true, dest, + )?; + } + "os_unfair_lock_lock" => { let [lock_op] = this.check_shim(abi, Conv::C, link_name, args)?; this.os_unfair_lock_lock(lock_op)?; @@ -243,12 +301,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(EmulateItemResult::NeedsReturn) } - fn ioctl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> { + fn ioctl( + &mut self, + fd_num: &OpTy<'tcx>, + cmd: &OpTy<'tcx>, + _varargs: &[OpTy<'tcx>], + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let fioclex = this.eval_libc_u64("FIOCLEX"); - let [fd_num, cmd] = check_min_arg_count("ioctl", args)?; let fd_num = this.read_scalar(fd_num)?.to_i32()?; let cmd = this.read_scalar(cmd)?.to_u64()?; diff --git a/src/tools/miri/src/shims/unix/macos/sync.rs b/src/tools/miri/src/shims/unix/macos/sync.rs index 330c64f06a3..6ba52f2f57e 100644 --- a/src/tools/miri/src/shims/unix/macos/sync.rs +++ b/src/tools/miri/src/shims/unix/macos/sync.rs @@ -10,8 +10,12 @@ //! and we do not detect copying of the lock, but macOS doesn't guarantee anything //! in that case either. +use std::cell::Cell; +use std::time::Duration; + use rustc_abi::Size; +use crate::concurrency::sync::FutexRef; use crate::*; #[derive(Clone)] @@ -20,6 +24,26 @@ enum MacOsUnfairLock { Active { mutex_ref: MutexRef }, } +pub enum MacOsFutexTimeout<'a, 'tcx> { + None, + Relative { clock_op: &'a OpTy<'tcx>, timeout_op: &'a OpTy<'tcx> }, + Absolute { clock_op: &'a OpTy<'tcx>, timeout_op: &'a OpTy<'tcx> }, +} + +/// Metadata for a macOS futex. +/// +/// Since macOS 11.0, Apple has exposed the previously private futex API consisting +/// of `os_sync_wait_on_address` (and friends) and `os_sync_wake_by_address_{any, all}`. +/// These work with different value sizes and flags, which are validated to be consistent. +/// This structure keeps track of both the futex queue and these values. +struct MacOsFutex { + futex: FutexRef, + /// The size in bytes of the atomic primitive underlying this futex. + size: Cell<u64>, + /// Whether the futex is shared across process boundaries. + shared: Cell<bool>, +} + impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { fn os_unfair_lock_get_data<'a>( @@ -30,7 +54,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { 'tcx: 'a, { let this = self.eval_context_mut(); - let lock = this.deref_pointer(lock_ptr)?; + let lock = this.deref_pointer_as(lock_ptr, this.libc_ty_layout("os_unfair_lock_s"))?; this.lazy_sync_get_data( &lock, Size::ZERO, // offset for init tracking @@ -54,6 +78,198 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + /// Implements [`os_sync_wait_on_address`], [`os_sync_wait_on_address_with_deadline`] + /// and [`os_sync_wait_on_address_with_timeout`]. + /// + /// [`os_sync_wait_on_address`]: https://developer.apple.com/documentation/os/os_sync_wait_on_address?language=objc + /// [`os_sync_wait_on_address_with_deadline`]: https://developer.apple.com/documentation/os/os_sync_wait_on_address_with_deadline?language=objc + /// [`os_sync_wait_on_address_with_timeout`]: https://developer.apple.com/documentation/os/os_sync_wait_on_address_with_timeout?language=objc + fn os_sync_wait_on_address( + &mut self, + addr_op: &OpTy<'tcx>, + value_op: &OpTy<'tcx>, + size_op: &OpTy<'tcx>, + flags_op: &OpTy<'tcx>, + timeout: MacOsFutexTimeout<'_, 'tcx>, + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let none = this.eval_libc_u32("OS_SYNC_WAIT_ON_ADDRESS_NONE"); + let shared = this.eval_libc_u32("OS_SYNC_WAIT_ON_ADDRESS_SHARED"); + let absolute_clock = this.eval_libc_u32("OS_CLOCK_MACH_ABSOLUTE_TIME"); + + let ptr = this.read_pointer(addr_op)?; + let value = this.read_scalar(value_op)?.to_u64()?; + let size = this.read_target_usize(size_op)?; + let flags = this.read_scalar(flags_op)?.to_u32()?; + + let clock_timeout = match timeout { + MacOsFutexTimeout::None => None, + MacOsFutexTimeout::Relative { clock_op, timeout_op } => { + let clock = this.read_scalar(clock_op)?.to_u32()?; + let timeout = this.read_scalar(timeout_op)?.to_u64()?; + Some((clock, TimeoutAnchor::Relative, timeout)) + } + MacOsFutexTimeout::Absolute { clock_op, timeout_op } => { + let clock = this.read_scalar(clock_op)?.to_u32()?; + let timeout = this.read_scalar(timeout_op)?.to_u64()?; + Some((clock, TimeoutAnchor::Absolute, timeout)) + } + }; + + // Perform validation of the arguments. + let addr = ptr.addr().bytes(); + if addr == 0 + || !matches!(size, 4 | 8) + || !addr.is_multiple_of(size) + || (flags != none && flags != shared) + || clock_timeout + .is_some_and(|(clock, _, timeout)| clock != absolute_clock || timeout == 0) + { + this.set_last_error_and_return(LibcError("EINVAL"), dest)?; + return interp_ok(()); + } + + let is_shared = flags == shared; + let timeout = clock_timeout.map(|(_, anchor, timeout)| { + // The only clock that is currenlty supported is the monotonic clock. + // While the deadline argument of `os_sync_wait_on_address_with_deadline` + // is actually not in nanoseconds but in the units of `mach_current_time`, + // the two are equivalent in miri. + (TimeoutClock::Monotonic, anchor, Duration::from_nanos(timeout)) + }); + + // See the Linux futex implementation for why this fence exists. + this.atomic_fence(AtomicFenceOrd::SeqCst)?; + + let layout = this.machine.layouts.uint(Size::from_bytes(size)).unwrap(); + let futex_val = this + .read_scalar_atomic(&this.ptr_to_mplace(ptr, layout), AtomicReadOrd::Acquire)? + .to_bits(Size::from_bytes(size))?; + + let futex = this + .get_sync_or_init(ptr, |_| { + MacOsFutex { + futex: Default::default(), + size: Cell::new(size), + shared: Cell::new(is_shared), + } + }) + .unwrap(); + + // Detect mismatches between the flags and sizes used on this address + // by comparing it with the parameters used by the other waiters in + // the current list. If the list is currently empty, update those + // parameters. + if futex.futex.waiters() == 0 { + futex.size.set(size); + futex.shared.set(is_shared); + } else if futex.size.get() != size || futex.shared.get() != is_shared { + this.set_last_error_and_return(LibcError("EINVAL"), dest)?; + return interp_ok(()); + } + + if futex_val == value.into() { + // If the values are the same, we have to block. + let futex_ref = futex.futex.clone(); + let dest = dest.clone(); + this.futex_wait( + futex_ref.clone(), + u32::MAX, // bitset + timeout, + callback!( + @capture<'tcx> { + dest: MPlaceTy<'tcx>, + futex_ref: FutexRef, + } + |this, unblock: UnblockKind| { + match unblock { + UnblockKind::Ready => { + let remaining = futex_ref.waiters().try_into().unwrap(); + this.write_scalar(Scalar::from_i32(remaining), &dest) + } + UnblockKind::TimedOut => { + this.set_last_error_and_return(LibcError("ETIMEDOUT"), &dest) + } + } + } + ), + ); + } else { + // else retrieve the current number of waiters. + let waiters = futex.futex.waiters().try_into().unwrap(); + this.write_scalar(Scalar::from_i32(waiters), dest)?; + } + + interp_ok(()) + } + + /// Implements [`os_sync_wake_by_address_all`] and [`os_sync_wake_by_address_any`]. + /// + /// [`os_sync_wake_by_address_all`]: https://developer.apple.com/documentation/os/os_sync_wake_by_address_all?language=objc + /// [`os_sync_wake_by_address_any`]: https://developer.apple.com/documentation/os/os_sync_wake_by_address_any?language=objc + fn os_sync_wake_by_address( + &mut self, + addr_op: &OpTy<'tcx>, + size_op: &OpTy<'tcx>, + flags_op: &OpTy<'tcx>, + all: bool, + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let none = this.eval_libc_u32("OS_SYNC_WAKE_BY_ADDRESS_NONE"); + let shared = this.eval_libc_u32("OS_SYNC_WAKE_BY_ADDRESS_SHARED"); + + let ptr = this.read_pointer(addr_op)?; + let size = this.read_target_usize(size_op)?; + let flags = this.read_scalar(flags_op)?.to_u32()?; + + // Perform validation of the arguments. + let addr = ptr.addr().bytes(); + if addr == 0 || !matches!(size, 4 | 8) || (flags != none && flags != shared) { + this.set_last_error_and_return(LibcError("EINVAL"), dest)?; + return interp_ok(()); + } + + let is_shared = flags == shared; + + let Some(futex) = this.get_sync_or_init(ptr, |_| { + MacOsFutex { + futex: Default::default(), + size: Cell::new(size), + shared: Cell::new(is_shared), + } + }) else { + // No AllocId, or no live allocation at that AllocId. Return an + // error code. (That seems nicer than silently doing something + // non-intuitive.) This means that if an address gets reused by a + // new allocation, we'll use an independent futex queue for this... + // that seems acceptable. + this.set_last_error_and_return(LibcError("ENOENT"), dest)?; + return interp_ok(()); + }; + + if futex.futex.waiters() == 0 { + this.set_last_error_and_return(LibcError("ENOENT"), dest)?; + return interp_ok(()); + // If there are waiters in the queue, they have all used the parameters + // stored in `futex` (we check this in `os_sync_wait_on_address` above). + // Detect mismatches between "our" parameters and the parameters used by + // the waiters and return an error in that case. + } else if futex.size.get() != size || futex.shared.get() != is_shared { + this.set_last_error_and_return(LibcError("EINVAL"), dest)?; + return interp_ok(()); + } + + let futex_ref = futex.futex.clone(); + + // See the Linux futex implementation for why this fence exists. + this.atomic_fence(AtomicFenceOrd::SeqCst)?; + this.futex_wake(&futex_ref, u32::MAX, if all { usize::MAX } else { 1 })?; + this.write_scalar(Scalar::from_i32(0), dest)?; + interp_ok(()) + } + fn os_unfair_lock_lock(&mut self, lock_op: &OpTy<'tcx>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs index 2d5d3a6471a..aefeee6f7a3 100644 --- a/src/tools/miri/src/shims/unix/mem.rs +++ b/src/tools/miri/src/shims/unix/mem.rs @@ -116,7 +116,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { align, MiriMemoryKind::Mmap.into(), // mmap guarantees new mappings are zero-init. - AllocInit::Zero + AllocInit::Zero, )?; interp_ok(Scalar::from_pointer(ptr, this)) diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs index f94783a3907..21d4f41f485 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -87,17 +87,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // File related shims "stat" | "stat64" => { let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?; - let result = this.macos_fbsd_solaris_stat(path, buf)?; + let result = this.macos_fbsd_solarish_stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" | "lstat64" => { let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?; - let result = this.macos_fbsd_solaris_lstat(path, buf)?; + let result = this.macos_fbsd_solarish_lstat(path, buf)?; this.write_scalar(result, dest)?; } "fstat" | "fstat64" => { let [fd, buf] = this.check_shim(abi, Conv::C, link_name, args)?; - let result = this.macos_fbsd_solaris_fstat(fd, buf)?; + let result = this.macos_fbsd_solarish_fstat(fd, buf)?; this.write_scalar(result, dest)?; } "readdir" => { @@ -163,7 +163,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { throw_unsup_format!("pset_info is only supported with list==NULL"); } - let cpus = this.deref_pointer(cpus)?; + let cpus = this.deref_pointer_as(cpus, this.machine.layouts.u32)?; this.write_scalar(Scalar::from_u32(this.machine.num_cpus), &cpus)?; this.write_null(dest)?; } diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs index 5b0a9398b4b..9f1fabfbf64 100644 --- a/src/tools/miri/src/shims/unix/sync.rs +++ b/src/tools/miri/src/shims/unix/sync.rs @@ -170,7 +170,7 @@ fn mutex_create<'tcx>( mutex_ptr: &OpTy<'tcx>, kind: MutexKind, ) -> InterpResult<'tcx, PthreadMutex> { - let mutex = ecx.deref_pointer(mutex_ptr)?; + let mutex = ecx.deref_pointer_as(mutex_ptr, ecx.libc_ty_layout("pthread_mutex_t"))?; let id = ecx.machine.sync.mutex_create(); let data = PthreadMutex { mutex_ref: id, kind }; ecx.lazy_sync_init(&mutex, mutex_init_offset(ecx)?, data.clone())?; @@ -186,7 +186,7 @@ fn mutex_get_data<'tcx, 'a>( where 'tcx: 'a, { - let mutex = ecx.deref_pointer(mutex_ptr)?; + let mutex = ecx.deref_pointer_as(mutex_ptr, ecx.libc_ty_layout("pthread_mutex_t"))?; ecx.lazy_sync_get_data( &mutex, mutex_init_offset(ecx)?, @@ -265,7 +265,7 @@ fn rwlock_get_data<'tcx, 'a>( where 'tcx: 'a, { - let rwlock = ecx.deref_pointer(rwlock_ptr)?; + let rwlock = ecx.deref_pointer_as(rwlock_ptr, ecx.libc_ty_layout("pthread_rwlock_t"))?; ecx.lazy_sync_get_data( &rwlock, rwlock_init_offset(ecx)?, @@ -383,7 +383,7 @@ fn cond_create<'tcx>( cond_ptr: &OpTy<'tcx>, clock: ClockId, ) -> InterpResult<'tcx, PthreadCondvar> { - let cond = ecx.deref_pointer(cond_ptr)?; + let cond = ecx.deref_pointer_as(cond_ptr, ecx.libc_ty_layout("pthread_cond_t"))?; let id = ecx.machine.sync.condvar_create(); let data = PthreadCondvar { id, clock }; ecx.lazy_sync_init(&cond, cond_init_offset(ecx)?, data)?; @@ -397,7 +397,7 @@ fn cond_get_data<'tcx, 'a>( where 'tcx: 'a, { - let cond = ecx.deref_pointer(cond_ptr)?; + let cond = ecx.deref_pointer_as(cond_ptr, ecx.libc_ty_layout("pthread_cond_t"))?; ecx.lazy_sync_get_data( &cond, cond_init_offset(ecx)?, @@ -760,7 +760,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let clock_id = condattr_get_clock_id(this, attr_op)?; - this.write_scalar(Scalar::from_i32(clock_id), &this.deref_pointer(clk_id_op)?)?; + this.write_scalar( + Scalar::from_i32(clock_id), + &this.deref_pointer_as(clk_id_op, this.libc_ty_layout("clockid_t"))?, + )?; interp_ok(()) } diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs index 08515b815a9..e183bfdf0e1 100644 --- a/src/tools/miri/src/shims/unix/unnamed_socket.rs +++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs @@ -5,9 +5,7 @@ use std::cell::{Cell, OnceCell, RefCell}; use std::collections::VecDeque; use std::io; -use std::io::{ErrorKind, Read}; - -use rustc_abi::Size; +use std::io::ErrorKind; use crate::concurrency::VClock; use crate::shims::files::{ @@ -92,10 +90,10 @@ impl FileDescription for AnonSocket { _communicate_allowed: bool, ptr: Pointer, len: usize, - dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, + finish: DynMachineCallback<'tcx, Result<usize, IoError>>, ) -> InterpResult<'tcx> { - anonsocket_read(self, len, ptr, dest, ecx) + anonsocket_read(self, ptr, len, ecx, finish) } fn write<'tcx>( @@ -103,10 +101,10 @@ impl FileDescription for AnonSocket { _communicate_allowed: bool, ptr: Pointer, len: usize, - dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, + finish: DynMachineCallback<'tcx, Result<usize, IoError>>, ) -> InterpResult<'tcx> { - anonsocket_write(self, ptr, len, dest, ecx) + anonsocket_write(self, ptr, len, ecx, finish) } fn as_unix(&self) -> &dyn UnixFileDescription { @@ -119,25 +117,25 @@ fn anonsocket_write<'tcx>( self_ref: FileDescriptionRef<AnonSocket>, ptr: Pointer, len: usize, - dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, + finish: DynMachineCallback<'tcx, Result<usize, IoError>>, ) -> InterpResult<'tcx> { // Always succeed on write size 0. // ("If count is zero and fd refers to a file other than a regular file, the results are not specified.") if len == 0 { - return ecx.return_write_success(0, dest); + return finish.call(ecx, Ok(0)); } // We are writing to our peer's readbuf. let Some(peer_fd) = self_ref.peer_fd().upgrade() else { // If the upgrade from Weak to Rc fails, it indicates that all read ends have been // closed. It is an error to write even if there would be space. - return ecx.set_last_error_and_return(ErrorKind::BrokenPipe, dest); + return finish.call(ecx, Err(ErrorKind::BrokenPipe.into())); }; let Some(writebuf) = &peer_fd.readbuf else { // Writing to the read end of a pipe. - return ecx.set_last_error_and_return(IoError::LibcError("EBADF"), dest); + return finish.call(ecx, Err(IoError::LibcError("EBADF"))); }; // Let's see if we can write. @@ -145,13 +143,12 @@ fn anonsocket_write<'tcx>( if available_space == 0 { if self_ref.is_nonblock { // Non-blocking socketpair with a full buffer. - return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest); + return finish.call(ecx, Err(ErrorKind::WouldBlock.into())); } else { self_ref.blocked_write_tid.borrow_mut().push(ecx.active_thread()); // Blocking socketpair with a full buffer. // Block the current thread; only keep a weak ref for this. let weak_self_ref = FileDescriptionRef::downgrade(&self_ref); - let dest = dest.clone(); ecx.block_thread( BlockReason::UnnamedSocket, None, @@ -160,14 +157,14 @@ fn anonsocket_write<'tcx>( weak_self_ref: WeakFileDescriptionRef<AnonSocket>, ptr: Pointer, len: usize, - dest: MPlaceTy<'tcx>, + finish: DynMachineCallback<'tcx, Result<usize, IoError>>, } |this, unblock: UnblockKind| { assert_eq!(unblock, UnblockKind::Ready); // If we got unblocked, then our peer successfully upgraded its weak // ref to us. That means we can also upgrade our weak ref. let self_ref = weak_self_ref.upgrade().unwrap(); - anonsocket_write(self_ref, ptr, len, &dest, this) + anonsocket_write(self_ref, ptr, len, this, finish) } ), ); @@ -180,9 +177,9 @@ fn anonsocket_write<'tcx>( writebuf.clock.join(clock); }); // Do full write / partial write based on the space available. - let actual_write_size = len.min(available_space); - let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; - writebuf.buf.extend(&bytes[..actual_write_size]); + let write_size = len.min(available_space); + let actual_write_size = ecx.write_to_host(&mut writebuf.buf, write_size, ptr)?.unwrap(); + assert_eq!(actual_write_size, write_size); // Need to stop accessing peer_fd so that it can be notified. drop(writebuf); @@ -197,7 +194,7 @@ fn anonsocket_write<'tcx>( // The kernel does this even if the fd was already readable before, so we follow suit. ecx.check_and_update_readiness(peer_fd)?; - return ecx.return_write_success(actual_write_size, dest); + return finish.call(ecx, Ok(write_size)); } interp_ok(()) } @@ -205,14 +202,14 @@ fn anonsocket_write<'tcx>( /// Read from AnonSocket and return the number of bytes read. fn anonsocket_read<'tcx>( self_ref: FileDescriptionRef<AnonSocket>, - len: usize, ptr: Pointer, - dest: &MPlaceTy<'tcx>, + len: usize, ecx: &mut MiriInterpCx<'tcx>, + finish: DynMachineCallback<'tcx, Result<usize, IoError>>, ) -> InterpResult<'tcx> { // Always succeed on read size 0. if len == 0 { - return ecx.return_read_success(ptr, &[], 0, dest); + return finish.call(ecx, Ok(0)); } let Some(readbuf) = &self_ref.readbuf else { @@ -225,43 +222,41 @@ fn anonsocket_read<'tcx>( if self_ref.peer_fd().upgrade().is_none() { // Socketpair with no peer and empty buffer. // 0 bytes successfully read indicates end-of-file. - return ecx.return_read_success(ptr, &[], 0, dest); + return finish.call(ecx, Ok(0)); } else if self_ref.is_nonblock { // Non-blocking socketpair with writer and empty buffer. // https://linux.die.net/man/2/read // EAGAIN or EWOULDBLOCK can be returned for socket, // POSIX.1-2001 allows either error to be returned for this case. // Since there is no ErrorKind for EAGAIN, WouldBlock is used. - return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest); + return finish.call(ecx, Err(ErrorKind::WouldBlock.into())); } else { self_ref.blocked_read_tid.borrow_mut().push(ecx.active_thread()); // Blocking socketpair with writer and empty buffer. // Block the current thread; only keep a weak ref for this. let weak_self_ref = FileDescriptionRef::downgrade(&self_ref); - let dest = dest.clone(); ecx.block_thread( BlockReason::UnnamedSocket, None, callback!( @capture<'tcx> { weak_self_ref: WeakFileDescriptionRef<AnonSocket>, - len: usize, ptr: Pointer, - dest: MPlaceTy<'tcx>, + len: usize, + finish: DynMachineCallback<'tcx, Result<usize, IoError>>, } |this, unblock: UnblockKind| { assert_eq!(unblock, UnblockKind::Ready); // If we got unblocked, then our peer successfully upgraded its weak // ref to us. That means we can also upgrade our weak ref. let self_ref = weak_self_ref.upgrade().unwrap(); - anonsocket_read(self_ref, len, ptr, &dest, this) + anonsocket_read(self_ref, ptr, len, this, finish) } ), ); } } else { // There's data to be read! - let mut bytes = vec![0; len]; let mut readbuf = readbuf.borrow_mut(); // Synchronize with all previous writes to this buffer. // FIXME: this over-synchronizes; a more precise approach would be to @@ -270,7 +265,7 @@ fn anonsocket_read<'tcx>( // Do full read / partial read based on the space available. // Conveniently, `read` exists on `VecDeque` and has exactly the desired behavior. - let actual_read_size = readbuf.buf.read(&mut bytes[..]).unwrap(); + let read_size = ecx.read_from_host(&mut readbuf.buf, len, ptr)?.unwrap(); // Need to drop before others can access the readbuf again. drop(readbuf); @@ -293,7 +288,7 @@ fn anonsocket_read<'tcx>( ecx.check_and_update_readiness(peer_fd)?; }; - return ecx.return_read_success(ptr, &bytes, actual_read_size, dest); + return finish.call(ecx, Ok(read_size)); } interp_ok(()) } @@ -362,7 +357,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let domain = this.read_scalar(domain)?.to_i32()?; let mut flags = this.read_scalar(type_)?.to_i32()?; let protocol = this.read_scalar(protocol)?.to_i32()?; - let sv = this.deref_pointer(sv)?; + // This is really a pointer to `[i32; 2]` but we use a ptr-to-first-element representation. + let sv = this.deref_pointer_as(sv, this.machine.layouts.i32)?; let mut is_sock_nonblock = false; diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs index 72c1fb58023..1b2ccd99ef9 100644 --- a/src/tools/miri/src/shims/windows/env.rs +++ b/src/tools/miri/src/shims/windows/env.rs @@ -218,7 +218,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let token = this.read_target_isize(token)?; let buf = this.read_pointer(buf)?; - let size = this.deref_pointer(size)?; + let size = this.deref_pointer_as(size, this.machine.layouts.u32)?; if token != -4 { throw_unsup_format!( diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index 4462d025bea..fae6170a9e7 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -266,7 +266,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::WinHeap.into(), - init + init, )?; this.write_pointer(ptr, dest)?; } @@ -299,7 +299,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::WinHeap.into(), - AllocInit::Uninit + AllocInit::Uninit, )?; this.write_pointer(new_ptr, dest)?; } @@ -335,7 +335,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Initialize with `0`. this.write_bytes_ptr( system_info.ptr(), - iter::repeat(0u8).take(system_info.layout.size.bytes_usize()), + iter::repeat_n(0u8, system_info.layout.size.bytes_usize()), )?; // Set selected fields. this.write_int_fields_named( @@ -523,7 +523,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [handle, name_ptr] = this.check_shim(abi, sys_conv, link_name, args)?; let handle = this.read_scalar(handle)?; - let name_ptr = this.deref_pointer(name_ptr)?; // the pointer where we should store the ptr to the name + let name_ptr = this.deref_pointer_as(name_ptr, this.machine.layouts.mut_raw_ptr)?; // the pointer where we should store the ptr to the name let thread = match Handle::try_from_scalar(handle, this)? { Ok(Handle::Thread(thread)) => Ok(thread), @@ -725,7 +725,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "GetConsoleMode" if this.frame_in_std() => { let [console, mode] = this.check_shim(abi, sys_conv, link_name, args)?; this.read_target_isize(console)?; - this.deref_pointer(mode)?; + this.deref_pointer_as(mode, this.machine.layouts.u32)?; // Indicate an error. this.write_null(dest)?; } diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs index 4001201bf67..8d5ea7db9e4 100644 --- a/src/tools/miri/src/shims/windows/sync.rs +++ b/src/tools/miri/src/shims/windows/sync.rs @@ -29,7 +29,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { { let this = self.eval_context_mut(); - let init_once = this.deref_pointer(init_once_ptr)?; + let init_once = + this.deref_pointer_as(init_once_ptr, this.windows_ty_layout("INIT_ONCE"))?; let init_offset = Size::ZERO; this.lazy_sync_get_data( @@ -85,7 +86,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let id = this.init_once_get_data(init_once_op)?.id; let flags = this.read_scalar(flags_op)?.to_u32()?; - let pending_place = this.deref_pointer(pending_op)?; + // PBOOL is int* + let pending_place = this.deref_pointer_as(pending_op, this.machine.layouts.i32)?; let context = this.read_pointer(context_op)?; if flags != 0 { @@ -210,14 +212,27 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { .futex .clone(); + let dest = dest.clone(); this.futex_wait( futex_ref, u32::MAX, // bitset timeout, - Scalar::from_i32(1), // retval_succ - Scalar::from_i32(0), // retval_timeout - dest.clone(), - IoError::WindowsError("ERROR_TIMEOUT"), // errno_timeout + callback!( + @capture<'tcx> { + dest: MPlaceTy<'tcx> + } + |this, unblock: UnblockKind| { + match unblock { + UnblockKind::Ready => { + this.write_int(1, &dest) + } + UnblockKind::TimedOut => { + this.set_last_error(IoError::WindowsError("ERROR_TIMEOUT"))?; + this.write_int(0, &dest) + } + } + } + ), ); } @@ -242,7 +257,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; let futex_ref = futex_ref.futex.clone(); - this.futex_wake(&futex_ref, u32::MAX)?; + this.futex_wake(&futex_ref, u32::MAX, 1)?; interp_ok(()) } @@ -262,7 +277,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; let futex_ref = futex_ref.futex.clone(); - while this.futex_wake(&futex_ref, u32::MAX)? {} + this.futex_wake(&futex_ref, u32::MAX, usize::MAX)?; interp_ok(()) } diff --git a/src/tools/miri/src/shims/windows/thread.rs b/src/tools/miri/src/shims/windows/thread.rs index efc1c2286bc..5db55404422 100644 --- a/src/tools/miri/src/shims/windows/thread.rs +++ b/src/tools/miri/src/shims/windows/thread.rs @@ -29,7 +29,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let thread = if this.ptr_is_null(this.read_pointer(thread_op)?)? { None } else { - let thread_info_place = this.deref_pointer(thread_op)?; + let thread_info_place = this.deref_pointer_as(thread_op, this.machine.layouts.u32)?; Some(thread_info_place) }; diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock index 0a5e9f62dd9..af92f9d0dec 100644 --- a/src/tools/miri/test_dependencies/Cargo.lock +++ b/src/tools/miri/test_dependencies/Cargo.lock @@ -106,6 +106,18 @@ dependencies = [ ] [[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets", +] + +[[package]] name = "gimli" version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -178,6 +190,7 @@ dependencies = [ "cfg-if", "getrandom 0.1.16", "getrandom 0.2.15", + "getrandom 0.3.1", "libc", "num_cpus", "page_size", @@ -360,6 +373,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] name = "wasm-bindgen" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -507,3 +529,12 @@ name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags", +] diff --git a/src/tools/miri/test_dependencies/Cargo.toml b/src/tools/miri/test_dependencies/Cargo.toml index e7eff46afca..78dddaf11df 100644 --- a/src/tools/miri/test_dependencies/Cargo.toml +++ b/src/tools/miri/test_dependencies/Cargo.toml @@ -8,13 +8,14 @@ version = "0.1.0" edition = "2021" [dependencies] -# all dependencies (and their transitive ones) listed here can be used in `tests/`. +# all dependencies (and their transitive ones) listed here can be used in `tests/*-dep`. libc = "0.2" num_cpus = "1.10.1" cfg-if = "1" getrandom_01 = { package = "getrandom", version = "0.1" } getrandom_02 = { package = "getrandom", version = "0.2", features = ["js"] } +getrandom_03 = { package = "getrandom", version = "0.3" } [target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dependencies] tempfile = "3" diff --git a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs index 4b6f344a78e..457f32e5544 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs +++ b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs @@ -8,5 +8,5 @@ fn main() { fn test_file_open_missing_needed_mode() { let name = b"missing_arg.txt\0"; let name_ptr = name.as_ptr().cast::<libc::c_char>(); - let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; //~ ERROR: Undefined Behavior: incorrect number of arguments for `open(pathname, O_CREAT, ...)`: got 2, expected at least 3 + let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; //~ ERROR: Undefined Behavior: not enough variadic arguments } diff --git a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr index ca9e3c6c4be..f48b75460d4 100644 --- a/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr +++ b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: incorrect number of arguments for `open(pathname, O_CREAT, ...)`: got 2, expected at least 3 +error: Undefined Behavior: not enough variadic arguments for `open(pathname, O_CREAT, ...)`: got 0, expected at least 1 --> tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs:LL:CC | -LL | ... { libc::open(name_ptr, libc::O_CREAT) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of arguments for `open(pathname, O_CREAT, ...)`: got 2, expected at least 3 +LL | let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not enough variadic arguments for `open(pathname, O_CREAT, ...)`: got 0, expected at least 1 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.rs new file mode 100644 index 00000000000..5a997ad8ec4 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.rs @@ -0,0 +1,5 @@ +fn main() { + unsafe { + (&1_u8 as *const u8).offset_from(&2_u8); //~ERROR: not both derived from the same allocation + } +} diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.stderr new file mode 100644 index 00000000000..34d7c6a8021 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_allocs.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation + --> tests/fail/intrinsics/ptr_offset_from_different_allocs.rs:LL:CC + | +LL | (&1_u8 as *const u8).offset_from(&2_u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/intrinsics/ptr_offset_from_different_allocs.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs index 0acda559d3a..0d34e711ca7 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs @@ -15,6 +15,6 @@ fn main() { let _ = p1.byte_offset_from(p1); // UB because different pointers. - let _ = p1.byte_offset_from(p2); //~ERROR: no provenance + let _ = p1.byte_offset_from(p2); //~ERROR: not both derived from the same allocation } } diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr index 7ef66390fcd..897945d6d5d 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds `offset_from` origin: expected a pointer to the end of 1 byte of memory, but got 0xb[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation --> tests/fail/intrinsics/ptr_offset_from_different_ints.rs:LL:CC | LL | let _ = p1.byte_offset_from(p2); - | ^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from` origin: expected a pointer to the end of 1 byte of memory, but got 0xb[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.rs new file mode 100644 index 00000000000..06f6b7a0117 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.rs @@ -0,0 +1,7 @@ +fn main() { + let mem = [0u8; 1]; + let ptr = mem.as_ptr(); + unsafe { + ptr.wrapping_add(4).offset_from(ptr); //~ERROR: the memory range between them is not in-bounds of an allocation + } +} diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.stderr new file mode 100644 index 00000000000..67df633bef5 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation + --> tests/fail/intrinsics/ptr_offset_from_oob.rs:LL:CC + | +LL | ptr.wrapping_add(4).offset_from(ptr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/intrinsics/ptr_offset_from_oob.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs index a20539ee7c7..c557c35c9de 100644 --- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs +++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs @@ -1,10 +1,13 @@ extern "Rust" { - fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>; + fn miri_backtrace_size(flags: u64) -> usize; + fn miri_get_backtrace(flags: u64, buf: *mut *mut ()); fn miri_resolve_frame(ptr: *mut (), flags: u64); } fn main() { - let frames = unsafe { miri_get_backtrace(0) }; + let size = unsafe { miri_backtrace_size(0) }; + let mut frames = vec![std::ptr::null_mut(); size]; + unsafe { miri_get_backtrace(1, frames.as_mut_ptr()) }; for frame in frames.iter() { unsafe { miri_resolve_frame(*frame, 0); //~ ERROR: Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 5 fields diff --git a/src/tools/miri/tests/fail/shims/non_vararg_signature_mismatch.rs b/src/tools/miri/tests/fail/shims/non_vararg_signature_mismatch.rs new file mode 100644 index 00000000000..b920e6795f9 --- /dev/null +++ b/src/tools/miri/tests/fail/shims/non_vararg_signature_mismatch.rs @@ -0,0 +1,17 @@ +//@ignore-target: windows # File handling is not implemented yet +//@compile-flags: -Zmiri-disable-isolation +use std::ffi::{CString, OsStr, c_char, c_int}; +use std::os::unix::ffi::OsStrExt; + +// Declare a variadic function as non-variadic. +extern "C" { + fn open(path: *const c_char, oflag: c_int) -> c_int; +} + +fn main() { + let c_path = CString::new(OsStr::new("./text").as_bytes()).expect("CString::new failed"); + let _fd = unsafe { + open(c_path.as_ptr(), /* value does not matter */ 0) + //~^ ERROR: calling a variadic function with a non-variadic caller-side signature + }; +} diff --git a/src/tools/miri/tests/fail/shims/non_vararg_signature_mismatch.stderr b/src/tools/miri/tests/fail/shims/non_vararg_signature_mismatch.stderr new file mode 100644 index 00000000000..43813af9a3c --- /dev/null +++ b/src/tools/miri/tests/fail/shims/non_vararg_signature_mismatch.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a variadic function with a non-variadic caller-side signature + --> tests/fail/shims/non_vararg_signature_mismatch.rs:LL:CC + | +LL | open(c_path.as_ptr(), /* value does not matter */ 0) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a variadic function with a non-variadic caller-side signature + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/shims/non_vararg_signature_mismatch.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/shims/wrong_fixed_arg_count.rs b/src/tools/miri/tests/fail/shims/wrong_fixed_arg_count.rs new file mode 100644 index 00000000000..e9cb69418d2 --- /dev/null +++ b/src/tools/miri/tests/fail/shims/wrong_fixed_arg_count.rs @@ -0,0 +1,16 @@ +//@ignore-target: windows # File handling is not implemented yet +//@compile-flags: -Zmiri-disable-isolation +use std::ffi::{CString, OsStr, c_char, c_int}; +use std::os::unix::ffi::OsStrExt; + +extern "C" { + fn open(path: *const c_char, ...) -> c_int; +} + +fn main() { + let c_path = CString::new(OsStr::new("./text").as_bytes()).expect("CString::new failed"); + let _fd = unsafe { + open(c_path.as_ptr(), /* value does not matter */ 0) + //~^ ERROR: incorrect number of fixed arguments for variadic function + }; +} diff --git a/src/tools/miri/tests/fail/shims/wrong_fixed_arg_count.stderr b/src/tools/miri/tests/fail/shims/wrong_fixed_arg_count.stderr new file mode 100644 index 00000000000..12e464813cf --- /dev/null +++ b/src/tools/miri/tests/fail/shims/wrong_fixed_arg_count.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: incorrect number of fixed arguments for variadic function `open`: got 1, expected 2 + --> tests/fail/shims/wrong_fixed_arg_count.rs:LL:CC + | +LL | open(c_path.as_ptr(), /* value does not matter */ 0) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of fixed arguments for variadic function `open`: got 1, expected 2 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at tests/fail/shims/wrong_fixed_arg_count.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs new file mode 100644 index 00000000000..becb90eb923 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs @@ -0,0 +1,276 @@ +//@only-target: darwin +//@compile-flags: -Zmiri-preemption-rate=0 + +use std::time::{Duration, Instant}; +use std::{io, ptr, thread}; + +fn wake_nobody() { + let futex = 0; + + // Wake 1 waiter. Expect ENOENT as nobody is waiting. + unsafe { + assert_eq!( + libc::os_sync_wake_by_address_any( + ptr::from_ref(&futex).cast_mut().cast(), + size_of::<i32>(), + libc::OS_SYNC_WAKE_BY_ADDRESS_NONE + ), + -1 + ); + assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::ENOENT); + } +} + +fn wake_dangling() { + let futex = Box::new(0); + let ptr = ptr::from_ref(&futex).cast_mut().cast(); + drop(futex); + + // Expect error since this is now "unmapped" memory. + unsafe { + assert_eq!( + libc::os_sync_wake_by_address_any( + ptr, + size_of::<i32>(), + libc::OS_SYNC_WAKE_BY_ADDRESS_NONE + ), + -1 + ); + assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::ENOENT); + } +} + +fn wait_wrong_val() { + let futex: i32 = 123; + + // Only wait if the futex value is 456. + unsafe { + assert_eq!( + libc::os_sync_wait_on_address( + ptr::from_ref(&futex).cast_mut().cast(), + 456, + size_of::<i32>(), + libc::OS_SYNC_WAIT_ON_ADDRESS_NONE + ), + 0, + ); + } +} + +fn wait_timeout() { + let start = Instant::now(); + + let futex: i32 = 123; + + // Wait for 200ms, with nobody waking us up early. + unsafe { + assert_eq!( + libc::os_sync_wait_on_address_with_timeout( + ptr::from_ref(&futex).cast_mut().cast(), + 123, + size_of::<i32>(), + libc::OS_SYNC_WAIT_ON_ADDRESS_NONE, + libc::OS_CLOCK_MACH_ABSOLUTE_TIME, + 200_000_000, + ), + -1, + ); + assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::ETIMEDOUT); + } + + assert!((200..1000).contains(&start.elapsed().as_millis())); +} + +fn wait_absolute_timeout() { + let start = Instant::now(); + + // Get the current monotonic timestamp. + #[allow(deprecated)] + let mut deadline = unsafe { libc::mach_absolute_time() }; + + // Add 200ms. + // What we should be doing here is call `mach_timebase_info` to determine the + // unit used for `deadline`, but we know what Miri returns for that function: + // the unit is nanoseconds. + deadline += 200_000_000; + + let futex: i32 = 123; + + // Wait for 200ms from now, with nobody waking us up early. + unsafe { + assert_eq!( + libc::os_sync_wait_on_address_with_deadline( + ptr::from_ref(&futex).cast_mut().cast(), + 123, + size_of::<i32>(), + libc::OS_SYNC_WAIT_ON_ADDRESS_NONE, + libc::OS_CLOCK_MACH_ABSOLUTE_TIME, + deadline, + ), + -1, + ); + assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::ETIMEDOUT); + } + + assert!((200..1000).contains(&start.elapsed().as_millis())); +} + +fn wait_wake() { + let start = Instant::now(); + + static mut FUTEX: i32 = 0; + + let t = thread::spawn(move || { + thread::sleep(Duration::from_millis(200)); + unsafe { + assert_eq!( + libc::os_sync_wake_by_address_any( + (&raw const FUTEX).cast_mut().cast(), + size_of::<i32>(), + libc::OS_SYNC_WAKE_BY_ADDRESS_NONE, + ), + 0, + ); + } + }); + + unsafe { + assert_eq!( + libc::os_sync_wait_on_address( + (&raw const FUTEX).cast_mut().cast(), + 0, + size_of::<i32>(), + libc::OS_SYNC_WAIT_ON_ADDRESS_NONE, + ), + 0, + ); + } + + // When running this in stress-gc mode, things can take quite long. + // So the timeout is 3000 ms. + assert!((200..3000).contains(&start.elapsed().as_millis())); + t.join().unwrap(); +} + +fn wait_wake_multiple() { + let val = 0i32; + let futex = &val; + + thread::scope(|s| { + // Spawn some threads and make them wait on the futex. + for i in 0..4 { + s.spawn(move || unsafe { + assert_eq!( + libc::os_sync_wait_on_address( + ptr::from_ref(futex).cast_mut().cast(), + 0, + size_of::<i32>(), + libc::OS_SYNC_WAIT_ON_ADDRESS_NONE, + ), + // The last two threads will be woken at the same time, + // but for the first two threads the remaining number + // of waiters should be strictly decreasing. + if i < 2 { 3 - i } else { 0 }, + ); + }); + + thread::yield_now(); + } + + // Wake the threads up again. + unsafe { + assert_eq!( + libc::os_sync_wake_by_address_any( + ptr::from_ref(futex).cast_mut().cast(), + size_of::<i32>(), + libc::OS_SYNC_WAKE_BY_ADDRESS_NONE, + ), + 0 + ); + + assert_eq!( + libc::os_sync_wake_by_address_any( + ptr::from_ref(futex).cast_mut().cast(), + size_of::<i32>(), + libc::OS_SYNC_WAKE_BY_ADDRESS_NONE, + ), + 0 + ); + + // Wake both remaining threads at the same time. + assert_eq!( + libc::os_sync_wake_by_address_all( + ptr::from_ref(futex).cast_mut().cast(), + size_of::<i32>(), + libc::OS_SYNC_WAKE_BY_ADDRESS_NONE, + ), + 0 + ); + } + }) +} + +fn param_mismatch() { + let futex = 0; + thread::scope(|s| { + s.spawn(|| { + unsafe { + assert_eq!( + libc::os_sync_wait_on_address_with_timeout( + ptr::from_ref(&futex).cast_mut().cast(), + 0, + size_of::<i32>(), + libc::OS_SYNC_WAIT_ON_ADDRESS_NONE, + libc::OS_CLOCK_MACH_ABSOLUTE_TIME, + 400_000_000, + ), + -1, + ); + assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::ETIMEDOUT); + } + }); + + s.spawn(|| { + thread::yield_now(); + unsafe { + assert_eq!( + libc::os_sync_wait_on_address( + ptr::from_ref(&futex).cast_mut().cast(), + 0, + size_of::<i32>(), + libc::OS_SYNC_WAIT_ON_ADDRESS_SHARED, + ), + -1, + ); + // This call fails because it uses the shared flag whereas the first waiter didn't. + assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL); + } + }); + + thread::yield_now(); + + unsafe { + assert_eq!( + libc::os_sync_wake_by_address_any( + ptr::from_ref(&futex).cast_mut().cast(), + size_of::<i32>(), + libc::OS_SYNC_WAIT_ON_ADDRESS_SHARED, + ), + -1, + ); + // This call fails because it uses the shared flag whereas the waiter didn't. + assert_eq!(io::Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL); + } + }); +} + +fn main() { + wake_nobody(); + wake_dangling(); + wait_wrong_val(); + wait_timeout(); + wait_absolute_timeout(); + wait_wake(); + wait_wake_multiple(); + param_mismatch(); +} diff --git a/src/tools/miri/tests/pass-dep/getrandom.rs b/src/tools/miri/tests/pass-dep/getrandom.rs index a5bc5ec7079..d359730e7f9 100644 --- a/src/tools/miri/tests/pass-dep/getrandom.rs +++ b/src/tools/miri/tests/pass-dep/getrandom.rs @@ -3,7 +3,7 @@ //@revisions: isolation no_isolation //@[no_isolation]compile-flags: -Zmiri-disable-isolation -/// Test direct calls of getrandom 0.1 and 0.2. +/// Test direct calls of getrandom 0.1, 0.2 and 0.3. fn main() { let mut data = vec![0; 16]; @@ -13,4 +13,6 @@ fn main() { getrandom_01::getrandom(&mut data).unwrap(); getrandom_02::getrandom(&mut data).unwrap(); + + getrandom_03::fill(&mut data).unwrap(); } diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs index 23e2122ee50..dc3ab2828fa 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs @@ -230,10 +230,10 @@ fn test_two_same_fd_in_same_epoll_instance() { //Two notification should be received. let expected_event = u32::try_from(libc::EPOLLIN | libc::EPOLLOUT).unwrap(); let expected_value = 5 as u64; - check_epoll_wait::<8>(epfd, &[ - (expected_event, expected_value), - (expected_event, expected_value), - ]); + check_epoll_wait::<8>( + epfd, + &[(expected_event, expected_value), (expected_event, expected_value)], + ); } fn test_epoll_eventfd() { @@ -290,10 +290,10 @@ fn test_epoll_socketpair_both_sides() { let expected_value0 = fds[0] as u64; let expected_event1 = u32::try_from(libc::EPOLLOUT).unwrap(); let expected_value1 = fds[1] as u64; - check_epoll_wait::<8>(epfd, &[ - (expected_event0, expected_value0), - (expected_event1, expected_value1), - ]); + check_epoll_wait::<8>( + epfd, + &[(expected_event0, expected_value0), (expected_event1, expected_value1)], + ); // Read from fds[0]. let mut buf: [u8; 5] = [0; 5]; @@ -453,10 +453,10 @@ fn test_socketpair_read() { let expected_value0 = fds[0] as u64; let expected_event1 = u32::try_from(libc::EPOLLOUT).unwrap(); let expected_value1 = fds[1] as u64; - check_epoll_wait::<8>(epfd, &[ - (expected_event0, expected_value0), - (expected_event1, expected_value1), - ]); + check_epoll_wait::<8>( + epfd, + &[(expected_event0, expected_value0), (expected_event1, expected_value1)], + ); // Read 3 bytes from fds[0]. let mut buf: [u8; 3] = [0; 3]; diff --git a/src/tools/miri/tests/pass/dyn-upcast.rs b/src/tools/miri/tests/pass/dyn-upcast.rs index 61410f7c4e0..f100c4d6a86 100644 --- a/src/tools/miri/tests/pass/dyn-upcast.rs +++ b/src/tools/miri/tests/pass/dyn-upcast.rs @@ -10,6 +10,8 @@ fn main() { replace_vptr(); vtable_nop_cast(); drop_principal(); + modulo_binder(); + modulo_assoc(); } fn vtable_nop_cast() { @@ -482,3 +484,53 @@ fn drop_principal() { println!("before"); drop(y); } + +// Test for <https://github.com/rust-lang/rust/issues/135316>. +fn modulo_binder() { + trait Supertrait<T> { + fn _print_numbers(&self, mem: &[usize; 100]) { + println!("{mem:?}"); + } + } + impl<T> Supertrait<T> for () {} + + trait Trait<T, U>: Supertrait<T> + Supertrait<U> { + fn say_hello(&self, _: &usize) { + println!("Hello!"); + } + } + impl<T, U> Trait<T, U> for () {} + + (&() as &'static dyn for<'a> Trait<&'static (), &'a ()> + as &'static dyn Trait<&'static (), &'static ()>) + .say_hello(&0); +} + +// Test for <https://github.com/rust-lang/rust/issues/135315>. +fn modulo_assoc() { + trait Supertrait<T> { + fn _print_numbers(&self, mem: &[usize; 100]) { + println!("{mem:?}"); + } + } + impl<T> Supertrait<T> for () {} + + trait Identity { + type Selff; + } + impl<Selff> Identity for Selff { + type Selff = Selff; + } + + trait Middle<T>: Supertrait<()> + Supertrait<T> { + fn say_hello(&self, _: &usize) { + println!("Hello!"); + } + } + impl<T> Middle<T> for () {} + + trait Trait: Middle<<() as Identity>::Selff> {} + impl Trait for () {} + + (&() as &dyn Trait as &dyn Middle<()>).say_hello(&0); +} diff --git a/src/tools/miri/tests/pass/dyn-upcast.stdout b/src/tools/miri/tests/pass/dyn-upcast.stdout index edd99a114a1..379600db3d9 100644 --- a/src/tools/miri/tests/pass/dyn-upcast.stdout +++ b/src/tools/miri/tests/pass/dyn-upcast.stdout @@ -2,3 +2,5 @@ before goodbye before goodbye +Hello! +Hello! diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 4de315e3589..2f4f64b1aa8 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -31,6 +31,7 @@ fn main() { test_fast(); test_algebraic(); test_fmuladd(); + test_min_max_nondet(); } trait Float: Copy + PartialEq + Debug { @@ -1211,3 +1212,30 @@ fn test_fmuladd() { test_operations_f32(0.1, 0.2, 0.3); test_operations_f64(1.1, 1.2, 1.3); } + +/// `min` and `max` on equal arguments are non-deterministic. +fn test_min_max_nondet() { + /// Ensure that if we call the closure often enough, we see both `true` and `false.` + #[track_caller] + fn ensure_both(f: impl Fn() -> bool) { + let rounds = 16; + let first = f(); + for _ in 1..rounds { + if f() != first { + // We saw two different values! + return; + } + } + // We saw the same thing N times. + panic!("expected non-determinism, got {rounds} times the same result: {first:?}"); + } + + ensure_both(|| f16::min(0.0, -0.0).is_sign_positive()); + ensure_both(|| f16::max(0.0, -0.0).is_sign_positive()); + ensure_both(|| f32::min(0.0, -0.0).is_sign_positive()); + ensure_both(|| f32::max(0.0, -0.0).is_sign_positive()); + ensure_both(|| f64::min(0.0, -0.0).is_sign_positive()); + ensure_both(|| f64::max(0.0, -0.0).is_sign_positive()); + ensure_both(|| f128::min(0.0, -0.0).is_sign_positive()); + ensure_both(|| f128::max(0.0, -0.0).is_sign_positive()); +} diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs index 9b9542b88a9..3bc953c3a5f 100644 --- a/src/tools/miri/tests/ui.rs +++ b/src/tools/miri/tests/ui.rs @@ -13,7 +13,7 @@ use ui_test::custom_flags::edition::Edition; use ui_test::dependencies::DependencyBuilder; use ui_test::per_test_config::TestConfig; use ui_test::spanned::Spanned; -use ui_test::{CommandBuilder, Config, Format, Match, OutputConflictHandling, status_emitter}; +use ui_test::{CommandBuilder, Config, Format, Match, ignore_output_conflict, status_emitter}; #[derive(Copy, Clone, Debug)] enum Mode { @@ -82,9 +82,18 @@ fn build_native_lib() -> PathBuf { native_lib_path } +struct WithDependencies { + bless: bool, +} + /// Does *not* set any args or env vars, since it is shared between the test runner and /// run_dep_mode. -fn miri_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) -> Config { +fn miri_config( + target: &str, + path: &str, + mode: Mode, + with_dependencies: Option<WithDependencies>, +) -> Config { // Miri is rustc-like, so we create a default builder for rustc and modify it let mut program = CommandBuilder::rustc(); program.program = miri_path(); @@ -119,22 +128,26 @@ fn miri_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) -> // keep in sync with `./miri run` config.comment_defaults.base().add_custom("edition", Edition("2021".into())); - if with_dependencies { - config.comment_defaults.base().set_custom("dependencies", DependencyBuilder { - program: CommandBuilder { - // Set the `cargo-miri` binary, which we expect to be in the same folder as the `miri` binary. - // (It's a separate crate, so we don't get an env var from cargo.) - program: miri_path() - .with_file_name(format!("cargo-miri{}", env::consts::EXE_SUFFIX)), - // There is no `cargo miri build` so we just use `cargo miri run`. - args: ["miri", "run"].into_iter().map(Into::into).collect(), - // Reset `RUSTFLAGS` to work around <https://github.com/rust-lang/rust/pull/119574#issuecomment-1876878344>. - envs: vec![("RUSTFLAGS".into(), None)], - ..CommandBuilder::cargo() + if let Some(WithDependencies { bless }) = with_dependencies { + config.comment_defaults.base().set_custom( + "dependencies", + DependencyBuilder { + program: CommandBuilder { + // Set the `cargo-miri` binary, which we expect to be in the same folder as the `miri` binary. + // (It's a separate crate, so we don't get an env var from cargo.) + program: miri_path() + .with_file_name(format!("cargo-miri{}", env::consts::EXE_SUFFIX)), + // There is no `cargo miri build` so we just use `cargo miri run`. + args: ["miri", "run"].into_iter().map(Into::into).collect(), + // Reset `RUSTFLAGS` to work around <https://github.com/rust-lang/rust/pull/119574#issuecomment-1876878344>. + envs: vec![("RUSTFLAGS".into(), None)], + ..CommandBuilder::cargo() + }, + crate_manifest_path: Path::new("test_dependencies").join("Cargo.toml"), + build_std: None, + bless_lockfile: bless, }, - crate_manifest_path: Path::new("test_dependencies").join("Cargo.toml"), - build_std: None, - }); + ); } config } @@ -146,7 +159,20 @@ fn run_tests( with_dependencies: bool, tmpdir: &Path, ) -> Result<()> { + // Handle command-line arguments. + let mut args = ui_test::Args::test()?; + args.bless |= env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0"); + + let with_dependencies = with_dependencies.then_some(WithDependencies { bless: args.bless }); + let mut config = miri_config(target, path, mode, with_dependencies); + config.with_args(&args); + config.bless_command = Some("./miri test --bless".into()); + + if env::var_os("MIRI_SKIP_UI_CHECKS").is_some() { + assert!(!args.bless, "cannot use RUSTC_BLESS and MIRI_SKIP_UI_CHECKS at the same time"); + config.output_conflict_handling = ignore_output_conflict; + } // Add a test env var to do environment communication tests. config.program.envs.push(("MIRI_ENV_VAR_TEST".into(), Some("0".into()))); @@ -182,16 +208,6 @@ fn run_tests( config.program.args.push(flag); } - // Handle command-line arguments. - let mut args = ui_test::Args::test()?; - args.bless |= env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0"); - config.with_args(&args); - config.bless_command = Some("./miri test --bless".into()); - - if env::var_os("MIRI_SKIP_UI_CHECKS").is_some() { - assert!(!args.bless, "cannot use RUSTC_BLESS and MIRI_SKIP_UI_CHECKS at the same time"); - config.output_conflict_handling = OutputConflictHandling::Ignore; - } eprintln!(" Compiler: {}", config.program.display()); ui_test::run_tests_generic( // Only run one test suite. In the future we can add all test suites to one `Vec` and run @@ -327,7 +343,8 @@ fn main() -> Result<()> { } fn run_dep_mode(target: String, args: impl Iterator<Item = OsString>) -> Result<()> { - let mut config = miri_config(&target, "", Mode::RunDep, /* with dependencies */ true); + let mut config = + miri_config(&target, "", Mode::RunDep, Some(WithDependencies { bless: false })); config.comment_defaults.base().custom.remove("edition"); // `./miri` adds an `--edition` in `args`, so don't set it twice config.fill_host_and_target()?; config.program.args = args.collect(); diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index 04de3493ea2..565721a9093 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -148,16 +148,6 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)> let is_aarch64 = target_triple.starts_with("aarch64"); - let skip_tests = if is_aarch64 { - vec![ - // Those tests fail only inside of Docker on aarch64, as of December 2024 - "tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs".to_string(), - "tests/ui/consts/large_const_alloc.rs".to_string(), - ] - } else { - vec![] - }; - let checkout_dir = Utf8PathBuf::from("/checkout"); let env = EnvironmentBuilder::default() .host_tuple(target_triple) @@ -169,7 +159,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)> .shared_llvm(true) // FIXME: Enable bolt for aarch64 once it's fixed upstream. Broken as of December 2024. .use_bolt(!is_aarch64) - .skipped_tests(skip_tests) + .skipped_tests(vec![]) .build()?; (env, shared.build_args) diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index b70db7130f6..8d99924a2d1 100644 --- a/src/tools/run-make-support/src/external_deps/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -216,6 +216,18 @@ impl Rustc { self } + /// Specify option of `-C symbol-mangling-version`. + pub fn symbol_mangling_version(&mut self, option: &str) -> &mut Self { + self.cmd.arg(format!("-Csymbol-mangling-version={option}")); + self + } + + /// Specify `-C prefer-dynamic`. + pub fn prefer_dynamic(&mut self) -> &mut Self { + self.cmd.arg(format!("-Cprefer-dynamic")); + self + } + /// Specify error format to use pub fn error_format(&mut self, format: &str) -> &mut Self { self.cmd.arg(format!("--error-format={format}")); diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 7316244b384..a8c9bec57fd 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -47,7 +47,9 @@ pub use wasmparser; // tidy-alphabetical-end // Re-exports of external dependencies. -pub use external_deps::{c_build, c_cxx_compiler, clang, htmldocck, llvm, python, rustc, rustdoc}; +pub use external_deps::{ + cargo, c_build, c_cxx_compiler, clang, htmldocck, llvm, python, rustc, rustdoc +}; // These rely on external dependencies. pub use c_cxx_compiler::{Cc, Gcc, cc, cxx, extra_c_flags, extra_cxx_flags, gcc}; @@ -79,7 +81,10 @@ pub use env::{env_var, env_var_os, set_current_dir}; pub use run::{cmd, run, run_fail, run_with_args}; /// Helpers for checking target information. -pub use targets::{is_aix, is_darwin, is_msvc, is_windows, llvm_components_contain, target, uname, apple_os}; +pub use targets::{ + apple_os, is_aix, is_darwin, is_msvc, is_windows, is_windows_gnu, llvm_components_contain, + target, uname, +}; /// Helpers for building names of output artifacts that are potentially target-specific. pub use artifact_names::{ @@ -104,4 +109,3 @@ pub use assertion_helpers::{ pub use string::{ count_regex_matches_in_files_with_extension, invalid_utf8_contains, invalid_utf8_not_contains, }; -use crate::external_deps::cargo; diff --git a/src/tools/run-make-support/src/symbols.rs b/src/tools/run-make-support/src/symbols.rs index fd0c866bcc9..e4d244e14a4 100644 --- a/src/tools/run-make-support/src/symbols.rs +++ b/src/tools/run-make-support/src/symbols.rs @@ -2,28 +2,44 @@ use std::path::Path; use object::{self, Object, ObjectSymbol, SymbolIterator}; -/// Iterate through the symbols in an object file. -/// -/// Uses a callback because `SymbolIterator` does not own its data. +/// Given an [`object::File`], find the exported dynamic symbol names via +/// [`object::Object::exports`]. This does not distinguish between which section the symbols appear +/// in. +#[track_caller] +pub fn exported_dynamic_symbol_names<'file>(file: &'file object::File<'file>) -> Vec<&'file str> { + file.exports() + .unwrap() + .into_iter() + .filter_map(|sym| std::str::from_utf8(sym.name()).ok()) + .collect() +} + +/// Iterate through the symbols in an object file. See [`object::Object::symbols`]. /// -/// Panics if `path` is not a valid object file readable by the current user. +/// Panics if `path` is not a valid object file readable by the current user or if `path` cannot be +/// parsed as a recognized object file. +#[track_caller] pub fn with_symbol_iter<P, F, R>(path: P, func: F) -> R where P: AsRef<Path>, F: FnOnce(&mut SymbolIterator<'_, '_>) -> R, { - let raw_bytes = crate::fs::read(path); - let f = object::File::parse(raw_bytes.as_slice()).expect("unable to parse file"); + let path = path.as_ref(); + let blob = crate::fs::read(path); + let f = object::File::parse(&*blob) + .unwrap_or_else(|e| panic!("failed to parse `{}`: {e}", path.display())); let mut iter = f.symbols(); func(&mut iter) } /// Check an object file's symbols for substrings. /// -/// Returns `true` if any of the symbols found in the object file at -/// `path` contain a substring listed in `substrings`. +/// Returns `true` if any of the symbols found in the object file at `path` contain a substring +/// listed in `substrings`. /// -/// Panics if `path` is not a valid object file readable by the current user. +/// Panics if `path` is not a valid object file readable by the current user or if `path` cannot be +/// parsed as a recognized object file. +#[track_caller] pub fn any_symbol_contains(path: impl AsRef<Path>, substrings: &[&str]) -> bool { with_symbol_iter(path, |syms| { for sym in syms { diff --git a/src/tools/run-make-support/src/targets.rs b/src/tools/run-make-support/src/targets.rs index ae004fd0cbd..a16fca71d2e 100644 --- a/src/tools/run-make-support/src/targets.rs +++ b/src/tools/run-make-support/src/targets.rs @@ -22,6 +22,12 @@ pub fn is_msvc() -> bool { target().contains("msvc") } +/// Check if target is windows-gnu. +#[must_use] +pub fn is_windows_gnu() -> bool { + target().ends_with("windows-gnu") +} + /// Check if target uses macOS. #[must_use] pub fn is_darwin() -> bool { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index e83ce6dc42c..38733577d1c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -411,6 +411,7 @@ language_item_table! { PanicLocation, sym::panic_location, panic_location, Target::Struct, GenericRequirement::None; PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None; PanicCannotUnwind, sym::panic_cannot_unwind, panic_cannot_unwind, Target::Fn, GenericRequirement::Exact(0); + PanicNullPointerDereference, sym::panic_null_pointer_dereference, panic_null_pointer_dereference, Target::Fn, GenericRequirement::None; /// libstd panic entry point. Necessary for const eval to be able to catch it BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None; diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index 9bc78ff87b8..ae1c6efe0cb 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -363,6 +363,7 @@ define_symbols! { panic_location, panic_misaligned_pointer_dereference, panic_nounwind, + panic_null_pointer_dereference, panic, Param, parse, diff --git a/src/tools/rustfmt/src/bin/main.rs b/src/tools/rustfmt/src/bin/main.rs index 34984798ae6..28df49b9304 100644 --- a/src/tools/rustfmt/src/bin/main.rs +++ b/src/tools/rustfmt/src/bin/main.rs @@ -817,7 +817,6 @@ mod test { options.inline_config = HashMap::from([("version".to_owned(), "Two".to_owned())]); let config = get_config(None, Some(options)); assert_eq!(config.style_edition(), StyleEdition::Edition2024); - assert_eq!(config.overflow_delimited_expr(), true); } #[nightly_only_test] @@ -827,7 +826,6 @@ mod test { let config_file = Some(Path::new("tests/config/style-edition/just-version")); let config = get_config(config_file, Some(options)); assert_eq!(config.style_edition(), StyleEdition::Edition2024); - assert_eq!(config.overflow_delimited_expr(), true); } #[nightly_only_test] @@ -872,7 +870,6 @@ mod test { ]); let config = get_config(None, Some(options)); assert_eq!(config.style_edition(), StyleEdition::Edition2024); - assert_eq!(config.overflow_delimited_expr(), true); } #[nightly_only_test] @@ -938,7 +935,6 @@ mod test { options.style_edition = Some(StyleEdition::Edition2024); let config = get_config(None, Some(options)); assert_eq!(config.style_edition(), StyleEdition::Edition2024); - assert_eq!(config.overflow_delimited_expr(), true); } #[nightly_only_test] @@ -948,6 +944,8 @@ mod test { let config_file = Some(Path::new("tests/config/style-edition/overrides")); let config = get_config(config_file, Some(options)); assert_eq!(config.style_edition(), StyleEdition::Edition2024); + // FIXME: this test doesn't really exercise anything, since + // `overflow_delimited_expr` is disabled by default in edition 2024. assert_eq!(config.overflow_delimited_expr(), false); } @@ -959,7 +957,8 @@ mod test { options.inline_config = HashMap::from([("overflow_delimited_expr".to_owned(), "false".to_owned())]); let config = get_config(config_file, Some(options)); - assert_eq!(config.style_edition(), StyleEdition::Edition2024); + // FIXME: this test doesn't really exercise anything, since + // `overflow_delimited_expr` is disabled by default in edition 2024. assert_eq!(config.overflow_delimited_expr(), false); } } diff --git a/src/tools/rustfmt/src/config/mod.rs b/src/tools/rustfmt/src/config/mod.rs index 7355adc9f9d..6b63108c037 100644 --- a/src/tools/rustfmt/src/config/mod.rs +++ b/src/tools/rustfmt/src/config/mod.rs @@ -848,7 +848,7 @@ binop_separator = "Front" remove_nested_parens = true combine_control_expr = true short_array_element_width_threshold = 10 -overflow_delimited_expr = true +overflow_delimited_expr = false struct_field_align_threshold = 0 enum_discrim_align_threshold = 0 match_arm_blocks = true diff --git a/src/tools/rustfmt/src/config/options.rs b/src/tools/rustfmt/src/config/options.rs index bbc99a2dced..71865ec75ce 100644 --- a/src/tools/rustfmt/src/config/options.rs +++ b/src/tools/rustfmt/src/config/options.rs @@ -627,7 +627,7 @@ config_option_with_style_edition_default!( RemoveNestedParens, bool, _ => true; CombineControlExpr, bool, _ => true; ShortArrayElementWidthThreshold, usize, _ => 10; - OverflowDelimitedExpr, bool, Edition2024 => true, _ => false; + OverflowDelimitedExpr, bool, _ => false; StructFieldAlignThreshold, usize, _ => 0; EnumDiscrimAlignThreshold, usize, _ => 0; MatchArmBlocks, bool, _ => true; @@ -644,7 +644,7 @@ config_option_with_style_edition_default!( BlankLinesLowerBound, usize, _ => 0; EditionConfig, Edition, _ => Edition::Edition2015; StyleEditionConfig, StyleEdition, - Edition2024 => StyleEdition::Edition2024, _ => StyleEdition::Edition2015; + Edition2024 => StyleEdition::Edition2024, _ => StyleEdition::Edition2015; VersionConfig, Version, Edition2024 => Version::Two, _ => Version::One; InlineAttributeWidth, usize, _ => 0; FormatGeneratedFiles, bool, _ => true; diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs index 63cc8794cea..34077c5f866 100644 --- a/src/tools/rustfmt/src/parse/session.rs +++ b/src/tools/rustfmt/src/parse/session.rs @@ -114,14 +114,13 @@ fn default_dcx( false, ); let emitter = Box::new( - HumanEmitter::new(stderr_destination(emit_color), fallback_bundle.clone()) + HumanEmitter::new(stderr_destination(emit_color), fallback_bundle) .sm(Some(source_map.clone())), ); let emitter: Box<DynEmitter> = if !show_parse_errors { Box::new(SilentEmitter { - fallback_bundle, - fatal_dcx: DiagCtxt::new(emitter), + fatal_emitter: emitter, fatal_note: None, emit_fatal_diagnostic: false, }) @@ -205,16 +204,7 @@ impl ParseSess { } pub(crate) fn set_silent_emitter(&mut self) { - // Ideally this invocation wouldn't be necessary and the fallback bundle in - // `self.parse_sess.dcx` could be used, but the lock in `DiagCtxt` prevents this. - // See `<rustc_errors::SilentEmitter as Translate>::fallback_fluent_bundle`. - let fallback_bundle = rustc_errors::fallback_fluent_bundle( - rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), - false, - ); - self.raw_psess - .dcx() - .make_silent(fallback_bundle, None, false); + self.raw_psess.dcx().make_silent(None, false); } pub(crate) fn span_to_filename(&self, span: Span) -> FileName { diff --git a/src/tools/rustfmt/tests/target/configs/style_edition/overflow_delim_expr_2024.rs b/src/tools/rustfmt/tests/target/configs/style_edition/overflow_delim_expr_2024.rs index ecd2e8ca797..1b2d12ce320 100644 --- a/src/tools/rustfmt/tests/target/configs/style_edition/overflow_delim_expr_2024.rs +++ b/src/tools/rustfmt/tests/target/configs/style_edition/overflow_delim_expr_2024.rs @@ -25,10 +25,13 @@ fn combine_blocklike() { y: value2, }); - do_thing(x, Bar { - x: value, - y: value2, - }); + do_thing( + x, + Bar { + x: value, + y: value2, + }, + ); do_thing( x, @@ -46,12 +49,15 @@ fn combine_blocklike() { value4_with_longer_name, ]); - do_thing(x, &[ - value_with_longer_name, - value2_with_longer_name, - value3_with_longer_name, - value4_with_longer_name, - ]); + do_thing( + x, + &[ + value_with_longer_name, + value2_with_longer_name, + value3_with_longer_name, + value4_with_longer_name, + ], + ); do_thing( x, @@ -71,12 +77,15 @@ fn combine_blocklike() { value4_with_longer_name, ]); - do_thing(x, vec![ - value_with_longer_name, - value2_with_longer_name, - value3_with_longer_name, - value4_with_longer_name, - ]); + do_thing( + x, + vec![ + value_with_longer_name, + value2_with_longer_name, + value3_with_longer_name, + value4_with_longer_name, + ], + ); do_thing( x, @@ -99,22 +108,28 @@ fn combine_blocklike() { } fn combine_struct_sample() { - let identity = verify(&ctx, VerifyLogin { - type_: LoginType::Username, - username: args.username.clone(), - password: Some(args.password.clone()), - domain: None, - })?; + let identity = verify( + &ctx, + VerifyLogin { + type_: LoginType::Username, + username: args.username.clone(), + password: Some(args.password.clone()), + domain: None, + }, + )?; } fn combine_macro_sample() { rocket::ignite() - .mount("/", routes![ - http::auth::login, - http::auth::logout, - http::cors::options, - http::action::dance, - http::action::sleep, - ]) + .mount( + "/", + routes![ + http::auth::login, + http::auth::logout, + http::cors::options, + http::action::dance, + http::action::sleep, + ], + ) .launch(); } diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index e75d3dc2147..45b40b17ea3 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -1,2 +1 @@ run-make/split-debuginfo/Makefile -run-make/symbol-mangling-hashed/Makefile diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs index d158a8e6324..9b78ba75a05 100644 --- a/src/tools/tidy/src/bins.rs +++ b/src/tools/tidy/src/bins.rs @@ -134,7 +134,7 @@ mod os_impl { &mut |entry| { let file = entry.path(); let extension = file.extension(); - let scripts = ["py", "sh", "ps1"]; + let scripts = ["py", "sh", "ps1", "woff2"]; if scripts.into_iter().any(|e| extension == Some(OsStr::new(e))) { return; } diff --git a/tests/assembly/small_data_threshold.rs b/tests/assembly/small_data_threshold.rs index d3ba144600e..bed515915b8 100644 --- a/tests/assembly/small_data_threshold.rs +++ b/tests/assembly/small_data_threshold.rs @@ -58,35 +58,35 @@ static mut Z: u64 = 0; // Currently, only MIPS and RISCV successfully put any objects in the small data // sections so the U/V/W/X tests are skipped on Hexagon and M68K -//@ RISCV: .section .sdata -//@ RISCV-NOT: .section -//@ RISCV: U: -//@ RISCV: .section .sbss -//@ RISCV-NOT: .section -//@ RISCV: V: -//@ RISCV: .section .sdata -//@ RISCV-NOT: .section -//@ RISCV: W: -//@ RISCV: .section .sbss -//@ RISCV-NOT: .section -//@ RISCV: X: +// RISCV: .section .sdata +// RISCV-NOT: .section +// RISCV: U: +// RISCV: .section .sbss +// RISCV-NOT: .section +// RISCV: V: +// RISCV: .section .sdata +// RISCV-NOT: .section +// RISCV: W: +// RISCV: .section .sbss +// RISCV-NOT: .section +// RISCV: X: -//@ MIPS: .section .sdata -//@ MIPS-NOT: .section -//@ MIPS: U: -//@ MIPS: .section .sbss -//@ MIPS-NOT: .section -//@ MIPS: V: -//@ MIPS: .section .sdata -//@ MIPS-NOT: .section -//@ MIPS: W: -//@ MIPS: .section .sbss -//@ MIPS-NOT: .section -//@ MIPS: X: +// MIPS: .section .sdata +// MIPS-NOT: .section +// MIPS: U: +// MIPS: .section .sbss +// MIPS-NOT: .section +// MIPS: V: +// MIPS: .section .sdata +// MIPS-NOT: .section +// MIPS: W: +// MIPS: .section .sbss +// MIPS-NOT: .section +// MIPS: X: -//@ CHECK: .section .data.Y, -//@ CHECK-NOT: .section -//@ CHECK: Y: -//@ CHECK: .section .bss.Z, -//@ CHECK-NOT: .section -//@ CHECK: Z: +// CHECK: .section .data.Y, +// CHECK-NOT: .section +// CHECK: Y: +// CHECK: .section .bss.Z, +// CHECK-NOT: .section +// CHECK: Z: diff --git a/tests/codegen/addr-of-mutate.rs b/tests/codegen/addr-of-mutate.rs index f10f01274b1..14bc4b8ab28 100644 --- a/tests/codegen/addr-of-mutate.rs +++ b/tests/codegen/addr-of-mutate.rs @@ -5,7 +5,7 @@ // Test for the absence of `readonly` on the argument when it is mutated via `&raw const`. // See <https://github.com/rust-lang/rust/issues/111502>. -// CHECK: i8 @foo(ptr noalias nocapture noundef align 1 dereferenceable(128) %x) +// CHECK: i8 @foo(ptr noalias{{( nocapture)?}} noundef align 1{{( captures\(none\))?}} dereferenceable(128) %x) #[no_mangle] pub fn foo(x: [u8; 128]) -> u8 { let ptr = core::ptr::addr_of!(x).cast_mut(); @@ -15,7 +15,7 @@ pub fn foo(x: [u8; 128]) -> u8 { x[0] } -// CHECK: i1 @second(ptr noalias nocapture noundef align {{[0-9]+}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) +// CHECK: i1 @second(ptr noalias{{( nocapture)?}} noundef align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) #[no_mangle] pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { let b_bool_ptr = core::ptr::addr_of!(a_ptr_and_b.1.1).cast_mut(); @@ -24,7 +24,7 @@ pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { } // If going through a deref (and there are no other mutating accesses), then `readonly` is fine. -// CHECK: i1 @third(ptr noalias nocapture noundef readonly align {{[0-9]+}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) +// CHECK: i1 @third(ptr noalias{{( nocapture)?}} noundef readonly align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b) #[no_mangle] pub unsafe fn third(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { let b_bool_ptr = core::ptr::addr_of!((*a_ptr_and_b.0).1).cast_mut(); diff --git a/tests/codegen/asm/bpf-clobbers.rs b/tests/codegen/asm/bpf-clobbers.rs new file mode 100644 index 00000000000..1117549b1ec --- /dev/null +++ b/tests/codegen/asm/bpf-clobbers.rs @@ -0,0 +1,31 @@ +//@ add-core-stubs +//@ compile-flags: --target bpfel-unknown-none +//@ needs-llvm-components: bpf + +#![crate_type = "rlib"] +#![feature(no_core, asm_experimental_arch)] +#![no_core] + +extern crate minicore; +use minicore::*; + +// CHECK-LABEL: @flags_clobber +// CHECK: call void asm sideeffect "", ""() +#[no_mangle] +pub unsafe fn flags_clobber() { + asm!("", options(nostack, nomem)); +} + +// CHECK-LABEL: @no_clobber +// CHECK: call void asm sideeffect "", ""() +#[no_mangle] +pub unsafe fn no_clobber() { + asm!("", options(nostack, nomem, preserves_flags)); +} + +// CHECK-LABEL: @clobber_abi +// CHECK: asm sideeffect "", "={r0},={r1},={r2},={r3},={r4},={r5}"() +#[no_mangle] +pub unsafe fn clobber_abi() { + asm!("", clobber_abi("C"), options(nostack, nomem, preserves_flags)); +} diff --git a/tests/codegen/cast-target-abi.rs b/tests/codegen/cast-target-abi.rs index db76aae3dd0..b3a35cbf3b1 100644 --- a/tests/codegen/cast-target-abi.rs +++ b/tests/codegen/cast-target-abi.rs @@ -392,7 +392,7 @@ pub fn call_fiveu16s() { } // CHECK-LABEL: @return_fiveu16s -// CHECK-SAME: (ptr {{.+}} sret([10 x i8]) align [[RUST_ALIGN:2]] dereferenceable(10) [[RET_PTR:%.+]]) +// CHECK-SAME: (ptr {{.+}} sret([10 x i8]) align [[RUST_ALIGN:2]] {{.*}}dereferenceable(10) [[RET_PTR:%.+]]) #[no_mangle] pub fn return_fiveu16s() -> FiveU16s { // powerpc returns this struct via sret pointer, it doesn't use the cast ABI. diff --git a/tests/codegen/float/f128.rs b/tests/codegen/float/f128.rs index 514d35433e1..562a8e6c9e9 100644 --- a/tests/codegen/float/f128.rs +++ b/tests/codegen/float/f128.rs @@ -1,11 +1,15 @@ // 32-bit x86 returns float types differently to avoid the x87 stack. // 32-bit systems will return 128bit values using a return area pointer. -//@ revisions: x86 bit32 bit64 +// Emscripten aligns f128 to 8 bytes, not 16. +//@ revisions: x86 bit32 bit64 emscripten //@[x86] only-x86 //@[bit32] ignore-x86 +//@[bit32] ignore-emscripten //@[bit32] only-32bit //@[bit64] ignore-x86 +//@[bit64] ignore-emscripten //@[bit64] only-64bit +//@[emscripten] only-emscripten // Verify that our intrinsics generate the correct LLVM calls for f128 @@ -59,6 +63,7 @@ pub fn f128_le(a: f128, b: f128) -> bool { // x86-LABEL: void @f128_neg({{.*}}sret([16 x i8]) // bit32-LABEL: void @f128_neg({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f128_neg( +// emscripten-LABEL: void @f128_neg({{.*}}sret([16 x i8]) #[no_mangle] pub fn f128_neg(a: f128) -> f128 { // CHECK: fneg fp128 @@ -68,6 +73,7 @@ pub fn f128_neg(a: f128) -> f128 { // x86-LABEL: void @f128_add({{.*}}sret([16 x i8]) // bit32-LABEL: void @f128_add({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f128_add( +// emscripten-LABEL: void @f128_add({{.*}}sret([16 x i8]) #[no_mangle] pub fn f128_add(a: f128, b: f128) -> f128 { // CHECK: fadd fp128 %{{.+}}, %{{.+}} @@ -77,6 +83,7 @@ pub fn f128_add(a: f128, b: f128) -> f128 { // x86-LABEL: void @f128_sub({{.*}}sret([16 x i8]) // bit32-LABEL: void @f128_sub({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f128_sub( +// emscripten-LABEL: void @f128_sub({{.*}}sret([16 x i8]) #[no_mangle] pub fn f128_sub(a: f128, b: f128) -> f128 { // CHECK: fsub fp128 %{{.+}}, %{{.+}} @@ -86,6 +93,7 @@ pub fn f128_sub(a: f128, b: f128) -> f128 { // x86-LABEL: void @f128_mul({{.*}}sret([16 x i8]) // bit32-LABEL: void @f128_mul({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f128_mul( +// emscripten-LABEL: void @f128_mul({{.*}}sret([16 x i8]) #[no_mangle] pub fn f128_mul(a: f128, b: f128) -> f128 { // CHECK: fmul fp128 %{{.+}}, %{{.+}} @@ -95,6 +103,7 @@ pub fn f128_mul(a: f128, b: f128) -> f128 { // x86-LABEL: void @f128_div({{.*}}sret([16 x i8]) // bit32-LABEL: void @f128_div({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f128_div( +// emscripten-LABEL: void @f128_div({{.*}}sret([16 x i8]) #[no_mangle] pub fn f128_div(a: f128, b: f128) -> f128 { // CHECK: fdiv fp128 %{{.+}}, %{{.+}} @@ -104,6 +113,7 @@ pub fn f128_div(a: f128, b: f128) -> f128 { // x86-LABEL: void @f128_rem({{.*}}sret([16 x i8]) // bit32-LABEL: void @f128_rem({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f128_rem( +// emscripten-LABEL: void @f128_rem({{.*}}sret([16 x i8]) #[no_mangle] pub fn f128_rem(a: f128, b: f128) -> f128 { // CHECK: frem fp128 %{{.+}}, %{{.+}} @@ -164,6 +174,7 @@ pub fn f128_as_f16(a: f128) -> f16 { // x86-LABEL: i32 @f128_as_f32( // bit32-LABEL: float @f128_as_f32( // bit64-LABEL: float @f128_as_f32( +// emscripten-LABEL: float @f128_as_f32( #[no_mangle] pub fn f128_as_f32(a: f128) -> f32 { // CHECK: fptrunc fp128 %{{.+}} to float @@ -173,6 +184,7 @@ pub fn f128_as_f32(a: f128) -> f32 { // x86-LABEL: void @f128_as_f64( // bit32-LABEL: double @f128_as_f64( // bit64-LABEL: double @f128_as_f64( +// emscripten-LABEL: double @f128_as_f64( #[no_mangle] pub fn f128_as_f64(a: f128) -> f64 { // CHECK: fptrunc fp128 %{{.+}} to double @@ -182,17 +194,20 @@ pub fn f128_as_f64(a: f128) -> f64 { // x86-LABEL: void @f128_as_self({{.*}}sret([16 x i8]) // bit32-LABEL: void @f128_as_self({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f128_as_self( +// emscripten-LABEL: void @f128_as_self({{.*}}sret([16 x i8]) #[no_mangle] pub fn f128_as_self(a: f128) -> f128 { // x86: store fp128 %a, ptr %_0, align 16 // bit32: store fp128 %a, ptr %_0, align 16 // bit64: ret fp128 %{{.+}} + // emscripten: store fp128 %a, ptr %_0, align 8 a as f128 } // x86-LABEL: void @f16_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @f16_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f16_as_f128( +// emscripten-LABEL: void @f16_as_f128({{.*}}sret([16 x i8]) #[no_mangle] pub fn f16_as_f128(a: f16) -> f128 { // CHECK: fpext half %{{.+}} to fp128 @@ -202,6 +217,7 @@ pub fn f16_as_f128(a: f16) -> f128 { // x86-LABEL: void @f32_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @f32_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f32_as_f128( +// emscripten-LABEL: void @f32_as_f128({{.*}}sret([16 x i8]) #[no_mangle] pub fn f32_as_f128(a: f32) -> f128 { // CHECK: fpext float %{{.+}} to fp128 @@ -211,6 +227,7 @@ pub fn f32_as_f128(a: f32) -> f128 { // x86-LABEL: void @f64_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @f64_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @f64_as_f128( +// emscripten-LABEL: void @f64_as_f128({{.*}}sret([16 x i8]) #[no_mangle] pub fn f64_as_f128(a: f64) -> f128 { // CHECK: fpext double %{{.+}} to fp128 @@ -249,6 +266,7 @@ pub fn f128_as_u64(a: f128) -> u64 { // x86-LABEL: void @f128_as_u128({{.*}}sret([16 x i8]) // bit32-LABEL: void @f128_as_u128({{.*}}sret([16 x i8]) // bit64-LABEL: i128 @f128_as_u128( +// emscripten-LABEL: void @f128_as_u128({{.*}}sret([16 x i8]) #[no_mangle] pub fn f128_as_u128(a: f128) -> u128 { // CHECK: call i128 @llvm.fptoui.sat.i128.f128(fp128 %{{.+}}) @@ -285,6 +303,7 @@ pub fn f128_as_i64(a: f128) -> i64 { // x86-LABEL: void @f128_as_i128({{.*}}sret([16 x i8]) // bit32-LABEL: void @f128_as_i128({{.*}}sret([16 x i8]) // bit64-LABEL: i128 @f128_as_i128( +// emscripten-LABEL: void @f128_as_i128({{.*}}sret([16 x i8]) #[no_mangle] pub fn f128_as_i128(a: f128) -> i128 { // CHECK: call i128 @llvm.fptosi.sat.i128.f128(fp128 %{{.+}}) @@ -296,6 +315,7 @@ pub fn f128_as_i128(a: f128) -> i128 { // x86-LABEL: void @u8_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @u8_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @u8_as_f128( +// emscripten-LABEL: void @u8_as_f128({{.*}}sret([16 x i8]) #[no_mangle] pub fn u8_as_f128(a: u8) -> f128 { // CHECK: uitofp i8 %{{.+}} to fp128 @@ -305,6 +325,7 @@ pub fn u8_as_f128(a: u8) -> f128 { // x86-LABEL: void @u16_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @u16_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @u16_as_f128( +// emscripten-LABEL: void @u16_as_f128({{.*}}sret([16 x i8]) #[no_mangle] pub fn u16_as_f128(a: u16) -> f128 { // CHECK: uitofp i16 %{{.+}} to fp128 @@ -314,6 +335,7 @@ pub fn u16_as_f128(a: u16) -> f128 { // x86-LABEL: void @u32_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @u32_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @u32_as_f128( +// emscripten-LABEL: void @u32_as_f128({{.*}}sret([16 x i8]) #[no_mangle] pub fn u32_as_f128(a: u32) -> f128 { // CHECK: uitofp i32 %{{.+}} to fp128 @@ -323,6 +345,7 @@ pub fn u32_as_f128(a: u32) -> f128 { // x86-LABEL: void @u64_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @u64_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @u64_as_f128( +// emscripten-LABEL: void @u64_as_f128({{.*}}sret([16 x i8]) #[no_mangle] pub fn u64_as_f128(a: u64) -> f128 { // CHECK: uitofp i64 %{{.+}} to fp128 @@ -332,6 +355,7 @@ pub fn u64_as_f128(a: u64) -> f128 { // x86-LABEL: void @u128_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @u128_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @u128_as_f128( +// emscripten-LABEL: void @u128_as_f128({{.*}}sret([16 x i8]) #[no_mangle] pub fn u128_as_f128(a: u128) -> f128 { // CHECK: uitofp i128 %{{.+}} to fp128 @@ -341,6 +365,7 @@ pub fn u128_as_f128(a: u128) -> f128 { // x86-LABEL: void @i8_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @i8_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @i8_as_f128( +// emscripten-LABEL: void @i8_as_f128({{.*}}sret([16 x i8]) #[no_mangle] pub fn i8_as_f128(a: i8) -> f128 { // CHECK: sitofp i8 %{{.+}} to fp128 @@ -350,6 +375,7 @@ pub fn i8_as_f128(a: i8) -> f128 { // x86-LABEL: void @i16_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @i16_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @i16_as_f128( +// emscripten-LABEL: void @i16_as_f128({{.*}}sret([16 x i8]) #[no_mangle] pub fn i16_as_f128(a: i16) -> f128 { // CHECK: sitofp i16 %{{.+}} to fp128 @@ -359,6 +385,7 @@ pub fn i16_as_f128(a: i16) -> f128 { // x86-LABEL: void @i32_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @i32_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @i32_as_f128( +// emscripten-LABEL: void @i32_as_f128({{.*}}sret([16 x i8]) #[no_mangle] pub fn i32_as_f128(a: i32) -> f128 { // CHECK: sitofp i32 %{{.+}} to fp128 @@ -368,6 +395,7 @@ pub fn i32_as_f128(a: i32) -> f128 { // x86-LABEL: void @i64_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @i64_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @i64_as_f128( +// emscripten-LABEL: void @i64_as_f128({{.*}}sret([16 x i8]) #[no_mangle] pub fn i64_as_f128(a: i64) -> f128 { // CHECK: sitofp i64 %{{.+}} to fp128 @@ -377,6 +405,7 @@ pub fn i64_as_f128(a: i64) -> f128 { // x86-LABEL: void @i128_as_f128({{.*}}sret([16 x i8]) // bit32-LABEL: void @i128_as_f128({{.*}}sret([16 x i8]) // bit64-LABEL: fp128 @i128_as_f128( +// emscripten-LABEL: void @i128_as_f128({{.*}}sret([16 x i8]) #[no_mangle] pub fn i128_as_f128(a: i128) -> f128 { // CHECK: sitofp i128 %{{.+}} to fp128 diff --git a/tests/codegen/function-arguments.rs b/tests/codegen/function-arguments.rs index 503799d3ed2..1a211dfe096 100644 --- a/tests/codegen/function-arguments.rs +++ b/tests/codegen/function-arguments.rs @@ -135,7 +135,7 @@ pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {} #[no_mangle] pub fn notunpin_borrow(_: &NotUnpin) {} -// CHECK: @indirect_struct(ptr noalias nocapture noundef readonly align 4 dereferenceable(32) %_1) +// CHECK: @indirect_struct(ptr noalias{{( nocapture)?}} noundef readonly align 4{{( captures\(none\))?}} dereferenceable(32) %_1) #[no_mangle] pub fn indirect_struct(_: S) {} @@ -198,7 +198,7 @@ pub fn notunpin_box(x: Box<NotUnpin>) -> Box<NotUnpin> { x } -// CHECK: @struct_return(ptr{{( dead_on_unwind)?}} noalias nocapture noundef{{( writable)?}} sret([32 x i8]) align 4 dereferenceable(32){{( %_0)?}}) +// CHECK: @struct_return(ptr{{( dead_on_unwind)?}} noalias{{( nocapture)?}} noundef{{( writable)?}} sret([32 x i8]) align 4{{( captures\(none\))?}} dereferenceable(32){{( %_0)?}}) #[no_mangle] pub fn struct_return() -> S { S { _field: [0, 0, 0, 0, 0, 0, 0, 0] } diff --git a/tests/codegen/i128-x86-align.rs b/tests/codegen/i128-x86-align.rs index 6b1da445c40..ac101b72513 100644 --- a/tests/codegen/i128-x86-align.rs +++ b/tests/codegen/i128-x86-align.rs @@ -19,8 +19,10 @@ pub struct ScalarPair { #[no_mangle] pub fn load(x: &ScalarPair) -> ScalarPair { // CHECK-LABEL: @load( - // CHECK-SAME: sret([32 x i8]) align 16 dereferenceable(32) %_0, - // CHECK-SAME: align 16 dereferenceable(32) %x + // CHECK-SAME: sret([32 x i8]) align 16 + // CHECK-SAME: dereferenceable(32) %_0, + // CHECK-SAME: align 16 + // CHECK-SAME: dereferenceable(32) %x // CHECK: [[A:%.*]] = load i32, ptr %x, align 16 // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %x, i64 16 // CHECK-NEXT: [[B:%.*]] = load i128, ptr [[GEP]], align 16 @@ -34,7 +36,8 @@ pub fn load(x: &ScalarPair) -> ScalarPair { #[no_mangle] pub fn store(x: &mut ScalarPair) { // CHECK-LABEL: @store( - // CHECK-SAME: align 16 dereferenceable(32) %x + // CHECK-SAME: align 16 + // CHECK-SAME: dereferenceable(32) %x // CHECK: store i32 1, ptr %x, align 16 // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %x, i64 16 // CHECK-NEXT: store i128 2, ptr [[GEP]], align 16 @@ -55,8 +58,10 @@ pub fn alloca() { #[no_mangle] pub fn load_volatile(x: &ScalarPair) -> ScalarPair { // CHECK-LABEL: @load_volatile( - // CHECK-SAME: sret([32 x i8]) align 16 dereferenceable(32) %_0, - // CHECK-SAME: align 16 dereferenceable(32) %x + // CHECK-SAME: sret([32 x i8]) align 16 + // CHECK-SAME: dereferenceable(32) %_0, + // CHECK-SAME: align 16 + // CHECK-SAME: dereferenceable(32) %x // CHECK: [[LOAD:%.*]] = load volatile %ScalarPair, ptr %x, align 16 // CHECK-NEXT: store %ScalarPair [[LOAD]], ptr %_0, align 16 // CHECK-NEXT: ret void @@ -66,7 +71,8 @@ pub fn load_volatile(x: &ScalarPair) -> ScalarPair { #[no_mangle] pub fn transmute(x: ScalarPair) -> (std::mem::MaybeUninit<i128>, i128) { // CHECK-LABEL: @transmute( - // CHECK-SAME: sret([32 x i8]) align 16 dereferenceable(32) %_0, + // CHECK-SAME: sret([32 x i8]) align 16 + // CHECK-SAME: dereferenceable(32) %_0, // CHECK-SAME: i32 noundef %x.0, i128 noundef %x.1 // CHECK: store i32 %x.0, ptr %_0, align 16 // CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr %_0, i64 16 @@ -86,7 +92,8 @@ pub struct Struct { #[no_mangle] pub fn store_struct(x: &mut Struct) { // CHECK-LABEL: @store_struct( - // CHECK-SAME: align 16 dereferenceable(32) %x + // CHECK-SAME: align 16 + // CHECK-SAME: dereferenceable(32) %x // CHECK: [[TMP:%.*]] = alloca [32 x i8], align 16 // CHECK: store i32 1, ptr [[TMP]], align 16 // CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i8, ptr [[TMP]], i64 4 diff --git a/tests/codegen/issues/issue-136329-optnone-noinline.rs b/tests/codegen/issues/issue-136329-optnone-noinline.rs new file mode 100644 index 00000000000..57c9e47a499 --- /dev/null +++ b/tests/codegen/issues/issue-136329-optnone-noinline.rs @@ -0,0 +1,21 @@ +//! Ensure that `#[optimize(none)]` functions are never inlined + +//@ compile-flags: -Copt-level=3 + +#![feature(optimize_attribute)] + +#[optimize(none)] +pub fn foo() { + let _x = 123; +} + +// CHECK-LABEL: define{{.*}}void @bar +// CHECK: start: +// CHECK: {{.*}}call {{.*}}void +// CHECK: ret void +#[no_mangle] +pub fn bar() { + foo(); +} + +fn main() {} diff --git a/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs b/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs index cba1a980caa..b147d01b38e 100644 --- a/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs +++ b/tests/codegen/loongarch-abi/loongarch64-lp64d-abi.rs @@ -259,11 +259,11 @@ pub struct IntDoubleInt { c: i32, } -// CHECK: define void @f_int_double_int_s_arg(ptr noalias nocapture noundef align 8 dereferenceable(24) %a) +// CHECK: define void @f_int_double_int_s_arg(ptr noalias{{( nocapture)?}} noundef align 8{{( captures\(none\))?}} dereferenceable(24) %a) #[no_mangle] pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {} -// CHECK: define void @f_ret_int_double_int_s(ptr{{( dead_on_unwind)?}} noalias nocapture noundef{{( writable)?}} sret([24 x i8]) align 8 dereferenceable(24) %_0) +// CHECK: define void @f_ret_int_double_int_s(ptr{{( dead_on_unwind)?}} noalias{{( nocapture)?}} noundef{{( writable)?}} sret([24 x i8]) align 8{{( captures\(none\))?}} dereferenceable(24) %_0) #[no_mangle] pub extern "C" fn f_ret_int_double_int_s() -> IntDoubleInt { IntDoubleInt { a: 1, b: 2., c: 3 } diff --git a/tests/codegen/packed.rs b/tests/codegen/packed.rs index 790d618b2ea..66df978d48c 100644 --- a/tests/codegen/packed.rs +++ b/tests/codegen/packed.rs @@ -52,7 +52,7 @@ pub struct BigPacked2 { #[no_mangle] pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 { // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca [32 x i8] - // CHECK: call void %{{.*}}(ptr noalias nocapture noundef sret{{.*}} dereferenceable(32) [[ALLOCA]]) + // CHECK: call void %{{.*}}(ptr{{( captures(none))?}} noalias{{( nocapture)?}} noundef sret{{.*}} dereferenceable(32) [[ALLOCA]]) // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 1 %{{.*}}, ptr align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false) // check that calls whose destination is a field of a packed struct // go through an alloca rather than calling the function with an @@ -64,7 +64,7 @@ pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 { #[no_mangle] pub fn call_pkd2(f: fn() -> Array) -> BigPacked2 { // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca [32 x i8] - // CHECK: call void %{{.*}}(ptr noalias nocapture noundef sret{{.*}} dereferenceable(32) [[ALLOCA]]) + // CHECK: call void %{{.*}}(ptr{{( captures(none))?}} noalias{{( nocapture)?}} noundef sret{{.*}} dereferenceable(32) [[ALLOCA]]) // CHECK: call void @llvm.memcpy.{{.*}}(ptr align 2 %{{.*}}, ptr align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false) // check that calls whose destination is a field of a packed struct // go through an alloca rather than calling the function with an diff --git a/tests/codegen/riscv-abi/riscv64-lp64d-abi.rs b/tests/codegen/riscv-abi/riscv64-lp64d-abi.rs index bcd9b0eae71..c14d5c01450 100644 --- a/tests/codegen/riscv-abi/riscv64-lp64d-abi.rs +++ b/tests/codegen/riscv-abi/riscv64-lp64d-abi.rs @@ -263,7 +263,7 @@ pub struct IntDoubleInt { #[no_mangle] pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {} -// CHECK: define void @f_ret_int_double_int_s(ptr {{.*}} sret([24 x i8]) align 8 dereferenceable(24) %_0) +// CHECK: define void @f_ret_int_double_int_s(ptr {{.*}} sret([24 x i8]) align 8 {{.*}}dereferenceable(24) %_0) #[no_mangle] pub extern "C" fn f_ret_int_double_int_s() -> IntDoubleInt { IntDoubleInt { a: 1, b: 2., c: 3 } diff --git a/tests/codegen/wasm_exceptions.rs b/tests/codegen/wasm_exceptions.rs index 719499dd8ea..07b8ae6e9d7 100644 --- a/tests/codegen/wasm_exceptions.rs +++ b/tests/codegen/wasm_exceptions.rs @@ -1,5 +1,5 @@ //@ only-wasm32 -//@ compile-flags: -C panic=unwind +//@ compile-flags: -C panic=unwind -Z emscripten-wasm-eh #![crate_type = "lib"] #![feature(core_intrinsics)] diff --git a/tests/crashes/131102.rs b/tests/crashes/131102.rs deleted file mode 100644 index 12b35f8d1b2..00000000000 --- a/tests/crashes/131102.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ known-bug: #131102 -pub struct Blorb<const N: u16>([String; N]); -pub struct Wrap(Blorb<0>); -pub const fn i(_: Wrap) {} diff --git a/tests/crashes/135210.rs b/tests/crashes/135210.rs deleted file mode 100644 index acb61e21090..00000000000 --- a/tests/crashes/135210.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #135210 - -#![feature(const_trait_impl)] -const _: fn(&String) = |s| { - &*s as &str; -}; - -fn main() {} diff --git a/tests/mir-opt/null_check_references.rs b/tests/mir-opt/null_check_references.rs new file mode 100644 index 00000000000..85f98865646 --- /dev/null +++ b/tests/mir-opt/null_check_references.rs @@ -0,0 +1,16 @@ +//@ compile-flags: -C debug-assertions + +struct Null { + a: u32, +} + +fn main() { + // CHECK-LABEL: fn main( + // CHECK-NOT: {{assert.*}} + let val: u32 = 42; + let val_ref: &u32 = &val; + let _access1: &u32 = &*val_ref; + + let val = Null { a: 42 }; + let _access2: &u32 = &val.a; +} diff --git a/tests/run-make/symbol-mangling-hashed/Makefile b/tests/run-make/symbol-mangling-hashed/Makefile deleted file mode 100644 index c95036ead95..00000000000 --- a/tests/run-make/symbol-mangling-hashed/Makefile +++ /dev/null @@ -1,48 +0,0 @@ -include ../tools.mk - -# ignore-cross-compile -# only-linux -# only-x86_64 - -NM=nm -D -RLIB_NAME=liba_rlib.rlib -DYLIB_NAME=liba_dylib.so -SO_NAME=libb_dylib.so -BIN_NAME=b_bin - -ifeq ($(UNAME),Darwin) -NM=nm -gU -RLIB_NAME=liba_rlib.rlib -DYLIB_NAME=liba_dylib.dylib -SO_NAME=libb_dylib.dylib -BIN_NAME=b_bin -endif - -ifdef IS_WINDOWS -NM=nm -g -RLIB_NAME=liba_rlib.dll.a -DYLIB_NAME=liba_dylib.dll -SO_NAME=libb_dylib.dll -BIN_NAME=b_bin.exe -endif - -all: - $(RUSTC) -C prefer-dynamic -Z unstable-options -C symbol-mangling-version=hashed -C metadata=foo a_dylib.rs - $(RUSTC) -C prefer-dynamic -Z unstable-options -C symbol-mangling-version=hashed -C metadata=bar a_rlib.rs - $(RUSTC) -C prefer-dynamic -L $(TMPDIR) b_dylib.rs - $(RUSTC) -C prefer-dynamic -L $(TMPDIR) b_bin.rs - - # Check hashed symbol name - - [ "$$($(NM) $(TMPDIR)/$(DYLIB_NAME) | grep -c hello)" -eq "0" ] - [ "$$($(NM) $(TMPDIR)/$(DYLIB_NAME) | grep _RNxC7a_dylib | grep -c ' T ')" -eq "2" ] - - [ "$$($(NM) $(TMPDIR)/$(SO_NAME) | grep b_dylib | grep -c hello)" -eq "1" ] - [ "$$($(NM) $(TMPDIR)/$(SO_NAME) | grep _RNxC6a_rlib | grep -c ' T ')" -eq "2" ] - [ "$$($(NM) $(TMPDIR)/$(SO_NAME) | grep _RNxC7a_dylib | grep -c ' U ')" -eq "1" ] - - [ "$$($(NM) $(TMPDIR)/$(BIN_NAME) | grep _RNxC6a_rlib | grep -c ' U ')" -eq "1" ] - [ "$$($(NM) $(TMPDIR)/$(BIN_NAME) | grep _RNxC7a_dylib | grep -c ' U ')" -eq "1" ] - [ "$$($(NM) $(TMPDIR)/$(BIN_NAME) | grep b_dylib | grep hello | grep -c ' U ')" -eq "1" ] - - $(call RUN,$(BIN_NAME)) diff --git a/tests/run-make/symbol-mangling-hashed/b_bin.rs b/tests/run-make/symbol-mangling-hashed/b_bin.rs deleted file mode 100644 index 8ee7fecda62..00000000000 --- a/tests/run-make/symbol-mangling-hashed/b_bin.rs +++ /dev/null @@ -1,9 +0,0 @@ -extern crate a_dylib; -extern crate a_rlib; -extern crate b_dylib; - -fn main() { - a_rlib::hello(); - a_dylib::hello(); - b_dylib::hello(); -} diff --git a/tests/run-make/symbol-mangling-hashed/b_dylib.rs b/tests/run-make/symbol-mangling-hashed/b_dylib.rs deleted file mode 100644 index 3252c9c75c2..00000000000 --- a/tests/run-make/symbol-mangling-hashed/b_dylib.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![crate_type = "dylib"] - -extern crate a_dylib; -extern crate a_rlib; - -pub fn hello() { - a_rlib::hello(); - a_dylib::hello(); -} diff --git a/tests/run-make/symbol-mangling-hashed/default_bin.rs b/tests/run-make/symbol-mangling-hashed/default_bin.rs new file mode 100644 index 00000000000..387596705c3 --- /dev/null +++ b/tests/run-make/symbol-mangling-hashed/default_bin.rs @@ -0,0 +1,9 @@ +extern crate default_dylib; +extern crate hashed_dylib; +extern crate hashed_rlib; + +fn main() { + hashed_rlib::hrhello(); + hashed_dylib::hdhello(); + default_dylib::ddhello(); +} diff --git a/tests/run-make/symbol-mangling-hashed/default_dylib.rs b/tests/run-make/symbol-mangling-hashed/default_dylib.rs new file mode 100644 index 00000000000..986d1c7b74d --- /dev/null +++ b/tests/run-make/symbol-mangling-hashed/default_dylib.rs @@ -0,0 +1,9 @@ +#![crate_type = "dylib"] + +extern crate hashed_dylib; +extern crate hashed_rlib; + +pub fn ddhello() { + hashed_rlib::hrhello(); + hashed_dylib::hdhello(); +} diff --git a/tests/run-make/symbol-mangling-hashed/a_dylib.rs b/tests/run-make/symbol-mangling-hashed/hashed_dylib.rs index 49d65b72cac..fbb7cba43e0 100644 --- a/tests/run-make/symbol-mangling-hashed/a_dylib.rs +++ b/tests/run-make/symbol-mangling-hashed/hashed_dylib.rs @@ -1,4 +1,4 @@ #![crate_type = "dylib"] -pub fn hello() { +pub fn hdhello() { println!("hello dylib"); } diff --git a/tests/run-make/symbol-mangling-hashed/a_rlib.rs b/tests/run-make/symbol-mangling-hashed/hashed_rlib.rs index 71e44ccc200..048e67784d2 100644 --- a/tests/run-make/symbol-mangling-hashed/a_rlib.rs +++ b/tests/run-make/symbol-mangling-hashed/hashed_rlib.rs @@ -1,5 +1,5 @@ #![crate_type = "rlib"] -pub fn hello() { +pub fn hrhello() { println!("hello rlib"); } diff --git a/tests/run-make/symbol-mangling-hashed/rmake.rs b/tests/run-make/symbol-mangling-hashed/rmake.rs new file mode 100644 index 00000000000..136e6b9fa3a --- /dev/null +++ b/tests/run-make/symbol-mangling-hashed/rmake.rs @@ -0,0 +1,108 @@ +// ignore-tidy-linelength +//! Basic smoke test for the unstable option `-C symbol_mangling_version=hashed` which aims to +//! replace full symbol mangling names based on hash digests to shorten symbol name lengths in +//! dylibs for space savings. +//! +//! # References +//! +//! - MCP #705: Provide option to shorten symbol names by replacing them with a digest: +//! <https://github.com/rust-lang/compiler-team/issues/705>. +//! - Implementation PR: <https://github.com/rust-lang/rust/pull/118636>. +//! - PE format: <https://learn.microsoft.com/en-us/windows/win32/debug/pe-format>. + +//@ ignore-cross-compile + +#![deny(warnings)] + +use run_make_support::symbols::exported_dynamic_symbol_names; +use run_make_support::{bin_name, cwd, dynamic_lib_name, is_darwin, object, rfs, run, rustc}; + +macro_rules! adjust_symbol_prefix { + ($name:literal) => { + if is_darwin() { concat!("_", $name) } else { $name } + }; +} + +fn main() { + rustc() + .input("hashed_dylib.rs") + .prefer_dynamic() + .arg("-Zunstable-options") + .symbol_mangling_version("hashed") + .metadata("foo") + .run(); + + rustc() + .input("hashed_rlib.rs") + .prefer_dynamic() + .arg("-Zunstable-options") + .symbol_mangling_version("hashed") + .metadata("bar") + .run(); + + rustc().input("default_dylib.rs").library_search_path(cwd()).prefer_dynamic().run(); + rustc().input("default_bin.rs").library_search_path(cwd()).prefer_dynamic().run(); + + { + // Check hashed symbol name + + let dylib_filename = dynamic_lib_name("hashed_dylib"); + println!("checking dylib `{dylib_filename}`"); + + let dylib_blob = rfs::read(&dylib_filename); + let dylib_file = object::File::parse(&*dylib_blob) + .unwrap_or_else(|e| panic!("failed to parse `{dylib_filename}`: {e}")); + + let dynamic_symbols = exported_dynamic_symbol_names(&dylib_file); + + if dynamic_symbols.iter().filter(|sym| sym.contains("hdhello")).count() != 0 { + eprintln!("exported dynamic symbols: {:#?}", dynamic_symbols); + panic!("expected no occurrence of `hdhello`"); + } + + let expected_prefix = adjust_symbol_prefix!("_RNxC12hashed_dylib"); + if dynamic_symbols.iter().filter(|sym| sym.starts_with(expected_prefix)).count() != 2 { + eprintln!("exported dynamic symbols: {:#?}", dynamic_symbols); + panic!("expected two dynamic symbols starting with `{expected_prefix}`"); + } + } + + { + let dylib_filename = dynamic_lib_name("default_dylib"); + println!("checking so `{dylib_filename}`"); + + let dylib_blob = rfs::read(&dylib_filename); + let dylib_file = object::File::parse(&*dylib_blob) + .unwrap_or_else(|e| panic!("failed to parse `{dylib_filename}`: {e}")); + + let dynamic_symbols = exported_dynamic_symbol_names(&dylib_file); + + if dynamic_symbols + .iter() + .filter(|sym| sym.contains("default_dylib") && sym.contains("ddhello")) + .count() + != 1 + { + eprintln!("exported dynamic symbols: {:#?}", dynamic_symbols); + panic!("expected one occurrence of mangled `ddhello`"); + } + + let expected_rlib_prefix = adjust_symbol_prefix!("_RNxC11hashed_rlib"); + if dynamic_symbols.iter().filter(|sym| sym.starts_with(expected_rlib_prefix)).count() != 2 { + eprintln!("exported dynamic symbols: {:#?}", dynamic_symbols); + panic!("expected two exported symbols starting with `{expected_rlib_prefix}`"); + } + + let expected_dylib_prefix = adjust_symbol_prefix!("_RNxC12hashed_dylib"); + if dynamic_symbols.iter().any(|sym| sym.starts_with("_RNxC12hashed_dylib")) { + eprintln!("exported dynamic symbols: {:#?}", dynamic_symbols); + panic!("did not expect any symbols starting with `{expected_dylib_prefix}`"); + } + } + + // Check that the final binary can be run. + { + let bin_filename = bin_name("default_bin"); + run(&bin_filename); + } +} diff --git a/tests/run-make/target-specs/require-explicit-cpu.json b/tests/run-make/target-specs/require-explicit-cpu.json new file mode 100644 index 00000000000..5cbb9573b3f --- /dev/null +++ b/tests/run-make/target-specs/require-explicit-cpu.json @@ -0,0 +1,11 @@ +{ + "data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128", + "linker-flavor": "gcc", + "llvm-target": "i686-unknown-linux-gnu", + "target-endian": "little", + "target-pointer-width": "32", + "target-c-int-width": "32", + "arch": "x86", + "os": "linux", + "need-explicit-cpu": true +} diff --git a/tests/run-make/target-specs/rmake.rs b/tests/run-make/target-specs/rmake.rs index 79c888ab340..f36a5784c89 100644 --- a/tests/run-make/target-specs/rmake.rs +++ b/tests/run-make/target-specs/rmake.rs @@ -63,4 +63,17 @@ fn main() { .crate_type("lib") .run_fail() .assert_stderr_contains("data-layout for target"); + rustc() + .input("foo.rs") + .target("require-explicit-cpu") + .crate_type("lib") + .run_fail() + .assert_stderr_contains("target requires explicitly specifying a cpu"); + rustc() + .input("foo.rs") + .target("require-explicit-cpu") + .crate_type("lib") + .arg("-Ctarget-cpu=generic") + .run(); + rustc().target("require-explicit-cpu").arg("--print=target-cpus").run(); } diff --git a/tests/rustdoc-gui/font-serif-change.goml b/tests/rustdoc-gui/font-serif-change.goml new file mode 100644 index 00000000000..b14d5ae96f9 --- /dev/null +++ b/tests/rustdoc-gui/font-serif-change.goml @@ -0,0 +1,31 @@ +// Ensures that the font serif change is working as expected. +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" + +// By default, it should be the serif fonts. +store-value: (serif_font, '"Source Serif 4", NanumBarunGothic, serif') +store-value: (serif_code_font, '"Source Code Pro", monospace') +assert-css: ("body", {"font-family": |serif_font|}) +assert-css: ("p code", {"font-family": |serif_code_font|}) + +// We now switch to the sans serif font +click: "#settings-menu" +wait-for: "#sans-serif-fonts" +click: "#sans-serif-fonts" + +store-value: (font, '"Fira Sans", sans-serif') +store-value: (code_font, '"Fira Mono", monospace') +assert-css: ("body", {"font-family": |font|}) +assert-css: ("p code", {"font-family": |code_font|}) + +// Reloading the page to ensure it is loaded correctly. +reload: +assert-css: ("body", {"font-family": |font|}) +assert-css: ("p code", {"font-family": |code_font|}) + +// We switch back to the serif font +click: "#settings-menu" +wait-for: "#sans-serif-fonts" +click: "#sans-serif-fonts" + +assert-css: ("body", {"font-family": |serif_font|}) +assert-css: ("p code", {"font-family": |serif_code_font|}) diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml index 1d93c07f9ec..4ab5b83d7c4 100644 --- a/tests/rustdoc-gui/settings.goml +++ b/tests/rustdoc-gui/settings.goml @@ -257,15 +257,15 @@ assert-text: ("#preferred-light-theme .setting-radio-name", "Preferred light the // We now check that clicking on the toggles' text is like clicking on the checkbox. // To test it, we use the "Disable keyboard shortcuts". set-local-storage: {"rustdoc-disable-shortcuts": "false"} -click: ".setting-line:last-child .setting-check span" +click: "#disable-shortcuts" assert-local-storage: {"rustdoc-disable-shortcuts": "true"} // We now check that focusing a toggle and pressing Space is like clicking on it. assert-local-storage: {"rustdoc-disable-shortcuts": "true"} -focus: ".setting-line:last-child .setting-check input" +focus: "#disable-shortcuts" press-key: "Space" assert-local-storage: {"rustdoc-disable-shortcuts": "false"} -focus: ".setting-line:last-child .setting-check input" +focus: "#disable-shortcuts" press-key: "Space" assert-local-storage: {"rustdoc-disable-shortcuts": "true"} @@ -276,7 +276,7 @@ assert-false: "#help-button .popover" wait-for-css: ("#settings-menu .popover", {"display": "block"}) // Now turn keyboard shortcuts back on, and see if they work. -click: ".setting-line:last-child .setting-check span" +click: "#disable-shortcuts" assert-local-storage: {"rustdoc-disable-shortcuts": "false"} press-key: "Escape" press-key: "?" diff --git a/tests/rustdoc-ui/coverage/html.stderr b/tests/rustdoc-ui/coverage/html.stderr index adca375d4bc..764179820c5 100644 --- a/tests/rustdoc-ui/coverage/html.stderr +++ b/tests/rustdoc-ui/coverage/html.stderr @@ -1,2 +1,2 @@ -error: html output format isn't supported for the --show-coverage option +error: `--output-format=html` is not supported for the `--show-coverage` option diff --git a/tests/rustdoc-ui/doctest-output.rs b/tests/rustdoc-ui/doctest-output.rs new file mode 100644 index 00000000000..720f2952980 --- /dev/null +++ b/tests/rustdoc-ui/doctest-output.rs @@ -0,0 +1 @@ +//@ compile-flags:-Z unstable-options --show-coverage --output-format=doctest diff --git a/tests/rustdoc-ui/doctest-output.stderr b/tests/rustdoc-ui/doctest-output.stderr new file mode 100644 index 00000000000..20c618dc61b --- /dev/null +++ b/tests/rustdoc-ui/doctest-output.stderr @@ -0,0 +1,2 @@ +error: `--output-format=doctest` is not supported for the `--show-coverage` option + diff --git a/tests/rustdoc-ui/extract-doctests.rs b/tests/rustdoc-ui/extract-doctests.rs new file mode 100644 index 00000000000..06bd35969d0 --- /dev/null +++ b/tests/rustdoc-ui/extract-doctests.rs @@ -0,0 +1,15 @@ +// Test to ensure that it generates expected output for `--output-format=doctest` command-line +// flag. + +//@ compile-flags:-Z unstable-options --output-format=doctest +//@ normalize-stdout: "tests/rustdoc-ui" -> "$$DIR" +//@ check-pass + +//! ```ignore (checking attributes) +//! let x = 12; +//! let y = 14; +//! ``` +//! +//! ```edition2018,compile_fail +//! let +//! ``` diff --git a/tests/rustdoc-ui/extract-doctests.stdout b/tests/rustdoc-ui/extract-doctests.stdout new file mode 100644 index 00000000000..fa8604cae94 --- /dev/null +++ b/tests/rustdoc-ui/extract-doctests.stdout @@ -0,0 +1 @@ +{"format_version":1,"doctests":[{"file":"$DIR/extract-doctests.rs","line":8,"doctest_attributes":{"original":"ignore (checking attributes)","should_panic":false,"no_run":false,"ignore":"All","rust":true,"test_harness":false,"compile_fail":false,"standalone_crate":false,"error_codes":[],"edition":null,"added_css_classes":[],"unknown":[]},"original_code":"let x = 12;\nlet y = 14;","doctest_code":"#![allow(unused)]\nfn main() {\nlet x = 12;\nlet y = 14;\n}","name":"$DIR/extract-doctests.rs - (line 8)"},{"file":"$DIR/extract-doctests.rs","line":13,"doctest_attributes":{"original":"edition2018,compile_fail","should_panic":false,"no_run":true,"ignore":"None","rust":true,"test_harness":false,"compile_fail":true,"standalone_crate":false,"error_codes":[],"edition":"2018","added_css_classes":[],"unknown":[]},"original_code":"let","doctest_code":"#![allow(unused)]\nfn main() {\nlet\n}","name":"$DIR/extract-doctests.rs - (line 13)"}]} \ No newline at end of file diff --git a/tests/rustdoc/intra-doc/auxiliary/issue-103463-aux.rs b/tests/rustdoc-ui/intra-doc/auxiliary/issue-103463-aux.rs index 2b8fdec1f12..2b8fdec1f12 100644 --- a/tests/rustdoc/intra-doc/auxiliary/issue-103463-aux.rs +++ b/tests/rustdoc-ui/intra-doc/auxiliary/issue-103463-aux.rs diff --git a/tests/rustdoc/intra-doc/issue-104145.rs b/tests/rustdoc-ui/intra-doc/ice-extern-trait-local-impl-104145.rs index 5690803af5a..0e403b21c8a 100644 --- a/tests/rustdoc/intra-doc/issue-104145.rs +++ b/tests/rustdoc-ui/intra-doc/ice-extern-trait-local-impl-104145.rs @@ -1,3 +1,6 @@ +// https://github.com/rust-lang/rust/issues/104145 +//@ check-pass + // Doc links in `Trait`'s methods are resolved because it has a local impl. //@ aux-build:issue-103463-aux.rs diff --git a/tests/rustdoc/intra-doc/issue-103463.rs b/tests/rustdoc-ui/intra-doc/ice-priv-use-103463.rs index 9b5cb67fd32..10894282e55 100644 --- a/tests/rustdoc/intra-doc/issue-103463.rs +++ b/tests/rustdoc-ui/intra-doc/ice-priv-use-103463.rs @@ -1,3 +1,6 @@ +// https://github.com/rust-lang/rust/issues/103463 +//@ check-pass + // The `Trait` is not pulled into the crate resulting in doc links in its methods being resolved. //@ aux-build:issue-103463-aux.rs diff --git a/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr b/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr index 180ba63927b..2c25589a553 100644 --- a/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr +++ b/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr @@ -99,7 +99,7 @@ LL | fn f<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {} | ^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/invalid_const_in_lifetime_position.rs:2:10 | LL | trait X { diff --git a/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr index 72d1a52f710..1e52b699820 100644 --- a/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr +++ b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr @@ -301,7 +301,7 @@ LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `SVec` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/ice-generic-type-alias-105742.rs:15:17 | LL | pub trait SVec: Index< diff --git a/tests/rustdoc/inline_cross/issue-28480.rs b/tests/rustdoc/inline_cross/doc-hidden-broken-link-28480.rs index 004510fd922..e1ca7403c03 100644 --- a/tests/rustdoc/inline_cross/issue-28480.rs +++ b/tests/rustdoc/inline_cross/doc-hidden-broken-link-28480.rs @@ -1,3 +1,6 @@ +// https://github.com/rust-lang/rust/issues/28480 +#![crate_name="foobar"] + //@ aux-build:rustdoc-hidden-sig.rs //@ build-aux-docs //@ ignore-cross-compile @@ -7,7 +10,7 @@ //@ has - '//a' 'u8' extern crate rustdoc_hidden_sig; -//@ has issue_28480/struct.Bar.html +//@ has foobar/struct.Bar.html //@ !has - '//a/@title' 'Hidden' //@ has - '//a' 'u8' pub use rustdoc_hidden_sig::Bar; diff --git a/tests/rustdoc/inline_cross/issue-31948-1.rs b/tests/rustdoc/inline_cross/doc-reachability-impl-31948-1.rs index e59da87c29d..baab1da9547 100644 --- a/tests/rustdoc/inline_cross/issue-31948-1.rs +++ b/tests/rustdoc/inline_cross/doc-reachability-impl-31948-1.rs @@ -1,27 +1,30 @@ +// https://github.com/rust-lang/rust/issues/31948 +#![crate_name="foobar"] + //@ aux-build:rustdoc-nonreachable-impls.rs //@ build-aux-docs //@ ignore-cross-compile extern crate rustdoc_nonreachable_impls; -//@ has issue_31948_1/struct.Wobble.html +//@ has foobar/struct.Wobble.html //@ has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for' //@ has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for' //@ !has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for' //@ !has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for' pub use rustdoc_nonreachable_impls::hidden::Wobble; -//@ has issue_31948_1/trait.Bark.html +//@ has foobar/trait.Bark.html //@ has - '//h3[@class="code-header"]' 'for Foo' //@ has - '//h3[@class="code-header"]' 'for Wobble' //@ !has - '//h3[@class="code-header"]' 'for Wibble' pub use rustdoc_nonreachable_impls::Bark; -//@ has issue_31948_1/trait.Woof.html +//@ has foobar/trait.Woof.html //@ has - '//h3[@class="code-header"]' 'for Foo' //@ has - '//h3[@class="code-header"]' 'for Wobble' //@ !has - '//h3[@class="code-header"]' 'for Wibble' pub use rustdoc_nonreachable_impls::Woof; -//@ !has issue_31948_1/trait.Bar.html -//@ !has issue_31948_1/trait.Qux.html +//@ !has foobar/trait.Bar.html +//@ !has foobar/trait.Qux.html diff --git a/tests/rustdoc/inline_cross/issue-31948-2.rs b/tests/rustdoc/inline_cross/doc-reachability-impl-31948-2.rs index 34b57052883..40e9108ec62 100644 --- a/tests/rustdoc/inline_cross/issue-31948-2.rs +++ b/tests/rustdoc/inline_cross/doc-reachability-impl-31948-2.rs @@ -1,21 +1,24 @@ +// https://github.com/rust-lang/rust/issues/31948 +#![crate_name="foobar"] + //@ aux-build:rustdoc-nonreachable-impls.rs //@ build-aux-docs //@ ignore-cross-compile extern crate rustdoc_nonreachable_impls; -//@ has issue_31948_2/struct.Wobble.html +//@ has foobar/struct.Wobble.html //@ has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for' //@ has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for' //@ has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for' //@ !has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for' pub use rustdoc_nonreachable_impls::hidden::Wobble; -//@ has issue_31948_2/trait.Qux.html +//@ has foobar/trait.Qux.html //@ has - '//h3[@class="code-header"]' 'for Foo' //@ has - '//h3[@class="code-header"]' 'for Wobble' pub use rustdoc_nonreachable_impls::hidden::Qux; -//@ !has issue_31948_2/trait.Bar.html -//@ !has issue_31948_2/trait.Woof.html -//@ !has issue_31948_2/trait.Bark.html +//@ !has foobar/trait.Bar.html +//@ !has foobar/trait.Woof.html +//@ !has foobar/trait.Bark.html diff --git a/tests/rustdoc/inline_cross/issue-31948.rs b/tests/rustdoc/inline_cross/doc-reachability-impl-31948.rs index 7a43fc7b279..ab0048513c7 100644 --- a/tests/rustdoc/inline_cross/issue-31948.rs +++ b/tests/rustdoc/inline_cross/doc-reachability-impl-31948.rs @@ -1,29 +1,32 @@ +// https://github.com/rust-lang/rust/issues/31948 +#![crate_name="foobar"] + //@ aux-build:rustdoc-nonreachable-impls.rs //@ build-aux-docs //@ ignore-cross-compile extern crate rustdoc_nonreachable_impls; -//@ has issue_31948/struct.Foo.html +//@ has foobar/struct.Foo.html //@ has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bark for' //@ has - '//*[@class="impl"]//h3[@class="code-header"]' 'Woof for' //@ !has - '//*[@class="impl"]//h3[@class="code-header"]' 'Bar for' //@ !has - '//*[@class="impl"]//h3[@class="code-header"]' 'Qux for' pub use rustdoc_nonreachable_impls::Foo; -//@ has issue_31948/trait.Bark.html +//@ has foobar/trait.Bark.html //@ has - '//h3[@class="code-header"]' 'for Foo' //@ !has - '//h3[@class="code-header"]' 'for Wibble' //@ !has - '//h3[@class="code-header"]' 'for Wobble' pub use rustdoc_nonreachable_impls::Bark; -//@ has issue_31948/trait.Woof.html +//@ has foobar/trait.Woof.html //@ has - '//h3[@class="code-header"]' 'for Foo' //@ !has - '//h3[@class="code-header"]' 'for Wibble' //@ !has - '//h3[@class="code-header"]' 'for Wobble' pub use rustdoc_nonreachable_impls::Woof; -//@ !has issue_31948/trait.Bar.html -//@ !has issue_31948/trait.Qux.html -//@ !has issue_31948/struct.Wibble.html -//@ !has issue_31948/struct.Wobble.html +//@ !has foobar/trait.Bar.html +//@ !has foobar/trait.Qux.html +//@ !has foobar/struct.Wibble.html +//@ !has foobar/struct.Wobble.html diff --git a/tests/rustdoc/inline_cross/issue-32881.rs b/tests/rustdoc/inline_cross/impl-dyn-trait-32881.rs index d4ebf10a1ca..f7dc7414455 100644 --- a/tests/rustdoc/inline_cross/issue-32881.rs +++ b/tests/rustdoc/inline_cross/impl-dyn-trait-32881.rs @@ -1,10 +1,13 @@ +// https://github.com/rust-lang/rust/issues/32881 +#![crate_name="foobar"] + //@ aux-build:rustdoc-trait-object-impl.rs //@ build-aux-docs //@ ignore-cross-compile extern crate rustdoc_trait_object_impl; -//@ has issue_32881/trait.Bar.html +//@ has foobar/trait.Bar.html //@ has - '//h3[@class="code-header"]' "impl<'a> dyn Bar" //@ has - '//h3[@class="code-header"]' "impl<'a> Debug for dyn Bar" diff --git a/tests/rustdoc/inline_cross/issue-33113.rs b/tests/rustdoc/inline_cross/impl-ref-33113.rs index 05e87d962cb..9ac4f02e00c 100644 --- a/tests/rustdoc/inline_cross/issue-33113.rs +++ b/tests/rustdoc/inline_cross/impl-ref-33113.rs @@ -1,10 +1,13 @@ +// https://github.com/rust-lang/rust/issues/33113 +#![crate_name="foobar"] + //@ aux-build:issue-33113.rs //@ build-aux-docs //@ ignore-cross-compile extern crate bar; -//@ has issue_33113/trait.Bar.html +//@ has foobar/trait.Bar.html //@ has - '//h3[@class="code-header"]' "for &'a char" //@ has - '//h3[@class="code-header"]' "for Foo" pub use bar::Bar; diff --git a/tests/rustdoc/inline_cross/issue-76736-1.rs b/tests/rustdoc/inline_cross/rustc-private-76736-1.rs index fe52702fd6f..3ffa5e6cc06 100644 --- a/tests/rustdoc/inline_cross/issue-76736-1.rs +++ b/tests/rustdoc/inline_cross/rustc-private-76736-1.rs @@ -1,3 +1,5 @@ +// https://github.com/rust-lang/rust/issues/76736 + //@ aux-build:issue-76736-1.rs //@ aux-build:issue-76736-2.rs diff --git a/tests/rustdoc/inline_cross/issue-76736-2.rs b/tests/rustdoc/inline_cross/rustc-private-76736-2.rs index df376ebe9a1..843b2941602 100644 --- a/tests/rustdoc/inline_cross/issue-76736-2.rs +++ b/tests/rustdoc/inline_cross/rustc-private-76736-2.rs @@ -1,3 +1,5 @@ +// https://github.com/rust-lang/rust/issues/76736 + //@ aux-build:issue-76736-1.rs //@ aux-build:issue-76736-2.rs diff --git a/tests/rustdoc/inline_cross/issue-76736-3.rs b/tests/rustdoc/inline_cross/rustc-private-76736-3.rs index 1bed4621c04..f9b46caa02f 100644 --- a/tests/rustdoc/inline_cross/issue-76736-3.rs +++ b/tests/rustdoc/inline_cross/rustc-private-76736-3.rs @@ -1,3 +1,5 @@ +// https://github.com/rust-lang/rust/issues/76736 + //@ compile-flags: -Zforce-unstable-if-unmarked //@ aux-build:issue-76736-1.rs //@ aux-build:issue-76736-2.rs diff --git a/tests/rustdoc/inline_cross/issue-76736-4.rs b/tests/rustdoc/inline_cross/rustc-private-76736-4.rs index 487e9030108..511464f2c49 100644 --- a/tests/rustdoc/inline_cross/issue-76736-4.rs +++ b/tests/rustdoc/inline_cross/rustc-private-76736-4.rs @@ -1,3 +1,5 @@ +// https://github.com/rust-lang/rust/issues/76736 + //@ aux-build:issue-76736-1.rs //@ aux-build:issue-76736-2.rs diff --git a/tests/rustdoc/inline_cross/issue-24183.method_no_where_self_sized.html b/tests/rustdoc/inline_cross/self-sized-bounds-24183.method_no_where_self_sized.html index f3c1c045202..f3c1c045202 100644 --- a/tests/rustdoc/inline_cross/issue-24183.method_no_where_self_sized.html +++ b/tests/rustdoc/inline_cross/self-sized-bounds-24183.method_no_where_self_sized.html diff --git a/tests/rustdoc/inline_cross/issue-24183.rs b/tests/rustdoc/inline_cross/self-sized-bounds-24183.rs index 8299eecc575..909005532f5 100644 --- a/tests/rustdoc/inline_cross/issue-24183.rs +++ b/tests/rustdoc/inline_cross/self-sized-bounds-24183.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/24183 #![crate_type = "lib"] #![crate_name = "usr"] diff --git a/tests/rustdoc/inline_local/issue-32343.rs b/tests/rustdoc/inline_local/doc-no-inline-32343.rs index 2ec123fdc5c..ed11614a500 100644 --- a/tests/rustdoc/inline_local/issue-32343.rs +++ b/tests/rustdoc/inline_local/doc-no-inline-32343.rs @@ -1,12 +1,15 @@ -//@ !has issue_32343/struct.Foo.html -//@ has issue_32343/index.html +// https://github.com/rust-lang/rust/issues/32343 +#![crate_name="foobar"] + +//@ !has foobar/struct.Foo.html +//@ has foobar/index.html //@ has - '//code' 'pub use foo::Foo' //@ !has - '//code/a' 'Foo' #[doc(no_inline)] pub use foo::Foo; -//@ !has issue_32343/struct.Bar.html -//@ has issue_32343/index.html +//@ !has foobar/struct.Bar.html +//@ has foobar/index.html //@ has - '//code' 'pub use foo::Bar' //@ has - '//code/a' 'Bar' #[doc(no_inline)] @@ -18,6 +21,6 @@ mod foo { } pub mod bar { - //@ has issue_32343/bar/struct.Bar.html + //@ has foobar/bar/struct.Bar.html pub use ::foo::Bar; } diff --git a/tests/rustdoc/inline_local/fully-stable-path-is-better.rs b/tests/rustdoc/inline_local/fully-stable-path-is-better.rs index 88b0b0d57b0..41bf42d2e7a 100644 --- a/tests/rustdoc/inline_local/fully-stable-path-is-better.rs +++ b/tests/rustdoc/inline_local/fully-stable-path-is-better.rs @@ -16,10 +16,10 @@ pub mod stb1 { #[unstable(feature = "uns", issue = "135003")] pub mod uns { #[stable(since = "1.0", feature = "stb1")] - #[rustc_allowed_through_unstable_modules] + #[rustc_allowed_through_unstable_modules = "use stable path instead"] pub struct Inside1; #[stable(since = "1.0", feature = "stb2")] - #[rustc_allowed_through_unstable_modules] + #[rustc_allowed_through_unstable_modules = "use stable path instead"] pub struct Inside2; } diff --git a/tests/rustdoc/inline_local/issue-28537.rs b/tests/rustdoc/inline_local/pub-re-export-28537.rs index d5ba94d2e6c..0e9836c7cee 100644 --- a/tests/rustdoc/inline_local/issue-28537.rs +++ b/tests/rustdoc/inline_local/pub-re-export-28537.rs @@ -1,3 +1,6 @@ +// https://github.com/rust-lang/rust/issues/28537 +#![crate_name="foo"] + #[doc(hidden)] pub mod foo { pub struct Foo; @@ -10,8 +13,8 @@ mod bar { } } -//@ has issue_28537/struct.Foo.html +//@ has foo/struct.Foo.html pub use foo::Foo; -//@ has issue_28537/struct.Bar.html +//@ has foo/struct.Bar.html pub use self::bar::Bar; diff --git a/tests/rustdoc/intra-doc/issue-82209.rs b/tests/rustdoc/intra-doc/enum-self-82209.rs index 46d028e535c..615115a5f8b 100644 --- a/tests/rustdoc/intra-doc/issue-82209.rs +++ b/tests/rustdoc/intra-doc/enum-self-82209.rs @@ -1,3 +1,5 @@ +// https://github.com/rust-lang/rust/issues/82209 + #![crate_name = "foo"] #![deny(rustdoc::broken_intra_doc_links)] pub enum Foo { diff --git a/tests/rustdoc/intra-doc/issue-108459.rs b/tests/rustdoc/intra-doc/link-same-name-different-disambiguator-108459.rs index 18424c069d3..0b339eaf6b2 100644 --- a/tests/rustdoc/intra-doc/issue-108459.rs +++ b/tests/rustdoc/intra-doc/link-same-name-different-disambiguator-108459.rs @@ -1,3 +1,6 @@ +// https://github.com/rust-lang/rust/pull/108459 +#![crate_name="foobar"] + #![deny(rustdoc::broken_intra_doc_links)] #![allow(rustdoc::redundant_explicit_links)] @@ -13,13 +16,13 @@ pub struct MyStruct1; // the same target but different text /// See also [crate::char] and [mod@char] and [prim@char] -//@ has issue_108459/struct.MyStruct2.html '//*[@href="char/index.html"]' 'crate::char' +//@ has foobar/struct.MyStruct2.html '//*[@href="char/index.html"]' 'crate::char' //@ has - '//*[@href="char/index.html"]' 'char' //@ has - '//*[@href="{{channel}}/std/primitive.char.html"]' 'char' pub struct MyStruct2; /// See also [mod@char] and [prim@char] and [crate::char] -//@ has issue_108459/struct.MyStruct3.html '//*[@href="char/index.html"]' 'crate::char' +//@ has foobar/struct.MyStruct3.html '//*[@href="char/index.html"]' 'crate::char' //@ has - '//*[@href="char/index.html"]' 'char' //@ has - '//*[@href="{{channel}}/std/primitive.char.html"]' 'char' pub struct MyStruct3; @@ -28,11 +31,11 @@ pub struct MyStruct3; // different targets /// See also [char][mod@char] and [char][prim@char] -//@ has issue_108459/struct.MyStruct4.html '//*[@href="char/index.html"]' 'char' +//@ has foobar/struct.MyStruct4.html '//*[@href="char/index.html"]' 'char' //@ has - '//*[@href="{{channel}}/std/primitive.char.html"]' 'char' pub struct MyStruct4; /// See also [char][prim@char] and [char][crate::char] -//@ has issue_108459/struct.MyStruct5.html '//*[@href="char/index.html"]' 'char' +//@ has foobar/struct.MyStruct5.html '//*[@href="char/index.html"]' 'char' //@ has - '//*[@href="{{channel}}/std/primitive.char.html"]' 'char' pub struct MyStruct5; diff --git a/tests/rustdoc/intra-doc/issue-66159.rs b/tests/rustdoc/intra-doc/same-name-different-crates-66159.rs index 5d50f63f299..7e3ace9355a 100644 --- a/tests/rustdoc/intra-doc/issue-66159.rs +++ b/tests/rustdoc/intra-doc/same-name-different-crates-66159.rs @@ -1,3 +1,6 @@ +// https://github.com/rust-lang/rust/issues/66159 +#![crate_name="foobar"] + //@ aux-crate:priv:pub_struct=pub-struct.rs //@ compile-flags:-Z unstable-options @@ -6,5 +9,5 @@ // Since we don't generate the docs for the auxiliary files, we can't actually // verify that the struct is linked correctly. -//@ has issue_66159/index.html +//@ has foobar/index.html //! [pub_struct::SomeStruct] diff --git a/tests/rustdoc/stability.rs b/tests/rustdoc/stability.rs index b74abb0e0ba..22cd4b9cd59 100644 --- a/tests/rustdoc/stability.rs +++ b/tests/rustdoc/stability.rs @@ -85,7 +85,7 @@ pub mod stable_later { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allowed_through_unstable_modules] +#[rustc_allowed_through_unstable_modules = "use stable path instead"] pub mod stable_earlier1 { //@ has stability/stable_earlier1/struct.StableInUnstable.html \ // '//div[@class="main-heading"]//span[@class="since"]' '1.0.0' diff --git a/tests/ui-fulldeps/obtain-borrowck.rs b/tests/ui-fulldeps/obtain-borrowck.rs index f8064c245a8..c6bec4f77a0 100644 --- a/tests/ui-fulldeps/obtain-borrowck.rs +++ b/tests/ui-fulldeps/obtain-borrowck.rs @@ -48,7 +48,6 @@ fn main() { let mut callbacks = CompilerCalls::default(); // Call the Rust compiler with our callbacks. rustc_driver::run_compiler(&rustc_args, &mut callbacks); - Ok(()) }); std::process::exit(exit_code); } diff --git a/tests/ui/abi/segfault-no-out-of-stack.rs b/tests/ui/abi/segfault-no-out-of-stack.rs index b5af13ebfb5..5e8b4e0dbf2 100644 --- a/tests/ui/abi/segfault-no-out-of-stack.rs +++ b/tests/ui/abi/segfault-no-out-of-stack.rs @@ -1,5 +1,6 @@ //@ run-pass //@ needs-subprocess +//@ compile-flags: -Zub-checks=no -Zmir-enable-passes=-CheckNull //@ ignore-fuchsia must translate zircon signal to SIGSEGV/SIGBUS, FIXME (#58590) #![feature(rustc_private)] diff --git a/tests/ui/array-slice-vec/driftsort-off-by-one-issue-136103.rs b/tests/ui/array-slice-vec/driftsort-off-by-one-issue-136103.rs new file mode 100644 index 00000000000..42197ff102d --- /dev/null +++ b/tests/ui/array-slice-vec/driftsort-off-by-one-issue-136103.rs @@ -0,0 +1,10 @@ +//@ run-pass +// Ensures that driftsort doesn't crash under specific slice +// length and memory size. +// Based on the example given in https://github.com/rust-lang/rust/issues/136103. +fn main() { + let n = 127; + let mut objs: Vec<_> = + (0..n).map(|i| [(i % 2) as u8; 125001]).collect(); + objs.sort(); +} diff --git a/tests/ui/associated-consts/associated-const-in-trait.stderr b/tests/ui/associated-consts/associated-const-in-trait.stderr index 107ceeaf113..5aaa6f6be05 100644 --- a/tests/ui/associated-consts/associated-const-in-trait.stderr +++ b/tests/ui/associated-consts/associated-const-in-trait.stderr @@ -5,7 +5,7 @@ LL | impl dyn Trait { | ^^^^^^^^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/associated-const-in-trait.rs:4:11 | LL | trait Trait { @@ -21,7 +21,7 @@ LL | const fn n() -> usize { Self::N } | ^^^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/associated-const-in-trait.rs:4:11 | LL | trait Trait { diff --git a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr b/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr index bf53089675d..81ace4ebb6d 100644 --- a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr +++ b/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr @@ -5,6 +5,8 @@ LL | fn main() -> Foo::Bar::<Vec<[u32]>> {} | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u32]` +note: required by an implicit `Sized` bound in `Vec` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL error: aborting due to 1 previous error diff --git a/tests/ui/associated-item/issue-48027.stderr b/tests/ui/associated-item/issue-48027.stderr index 1baaefd7720..513961e2bd0 100644 --- a/tests/ui/associated-item/issue-48027.stderr +++ b/tests/ui/associated-item/issue-48027.stderr @@ -5,7 +5,7 @@ LL | impl dyn Bar {} | ^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-48027.rs:2:11 | LL | trait Bar { diff --git a/tests/ui/async-await/async-closures/is-not-fn.current.stderr b/tests/ui/async-await/async-closures/is-not-fn.current.stderr index e7be1d5b10e..0fab1c15f27 100644 --- a/tests/ui/async-await/async-closures/is-not-fn.current.stderr +++ b/tests/ui/async-await/async-closures/is-not-fn.current.stderr @@ -1,4 +1,4 @@ -error[E0271]: expected `{async closure@is-not-fn.rs:8:14}` to be a closure that returns `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}` +error[E0271]: expected `{async closure@is-not-fn.rs:8:14}` to return `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}` --> $DIR/is-not-fn.rs:8:14 | LL | needs_fn(async || {}); diff --git a/tests/ui/async-await/async-closures/is-not-fn.next.stderr b/tests/ui/async-await/async-closures/is-not-fn.next.stderr index e7be1d5b10e..0fab1c15f27 100644 --- a/tests/ui/async-await/async-closures/is-not-fn.next.stderr +++ b/tests/ui/async-await/async-closures/is-not-fn.next.stderr @@ -1,4 +1,4 @@ -error[E0271]: expected `{async closure@is-not-fn.rs:8:14}` to be a closure that returns `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}` +error[E0271]: expected `{async closure@is-not-fn.rs:8:14}` to return `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}` --> $DIR/is-not-fn.rs:8:14 | LL | needs_fn(async || {}); diff --git a/tests/ui/async-await/async-closures/is-not-fn.rs b/tests/ui/async-await/async-closures/is-not-fn.rs index eacd07b7cdd..e5ab4742dab 100644 --- a/tests/ui/async-await/async-closures/is-not-fn.rs +++ b/tests/ui/async-await/async-closures/is-not-fn.rs @@ -6,5 +6,5 @@ fn main() { fn needs_fn(x: impl FnOnce()) {} needs_fn(async || {}); - //~^ ERROR expected `{async closure@is-not-fn.rs:8:14}` to be a closure that returns `()` + //~^ ERROR expected `{async closure@is-not-fn.rs:8:14}` to return `()` } diff --git a/tests/ui/async-await/async-fn/dyn-pos.stderr b/tests/ui/async-await/async-fn/dyn-pos.stderr index f9d2a669477..7d5b37bdbe7 100644 --- a/tests/ui/async-await/async-fn/dyn-pos.stderr +++ b/tests/ui/async-await/async-fn/dyn-pos.stderr @@ -5,7 +5,7 @@ LL | fn foo(x: &dyn AsyncFn()) {} | ^^^^^^^^^ `AsyncFnMut` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL | = note: the trait is not dyn compatible because it contains the generic associated type `CallRefFuture` diff --git a/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr index b60f6a08338..ce023397db9 100644 --- a/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr +++ b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr @@ -20,19 +20,15 @@ LL | true = note: expected enum `Option<()>` found type `bool` -error[E0271]: expected `{closure@dont-ice-for-type-mismatch-in-closure-in-async.rs:6:10}` to be a closure that returns `bool`, but it returns `Option<()>` - --> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:6:10 +error[E0271]: expected `{closure@dont-ice-for-type-mismatch-in-closure-in-async.rs:6:10}` to return `bool`, but it returns `Option<()>` + --> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:6:16 | -LL | call(|| -> Option<()> { - | _____----_^ - | | | - | | required by a bound introduced by this call -LL | | -LL | | if true { -LL | | false -... | -LL | | }) - | |_____^ expected `bool`, found `Option<()>` +LL | call(|| -> Option<()> { + | ---- ------^^^^^^^^^^ + | | | | + | | | expected `bool`, found `Option<()>` + | | this closure + | required by a bound introduced by this call | = note: expected type `bool` found enum `Option<()>` diff --git a/tests/ui/async-await/in-trait/dyn-compatibility.stderr b/tests/ui/async-await/in-trait/dyn-compatibility.stderr index c6c406902f6..553bcbf89d5 100644 --- a/tests/ui/async-await/in-trait/dyn-compatibility.stderr +++ b/tests/ui/async-await/in-trait/dyn-compatibility.stderr @@ -5,7 +5,7 @@ LL | let x: &dyn Foo = todo!(); | ^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/dyn-compatibility.rs:5:14 | LL | trait Foo { diff --git a/tests/ui/async-await/inference_var_self_argument.stderr b/tests/ui/async-await/inference_var_self_argument.stderr index a674fc0f3a5..1fccc32470f 100644 --- a/tests/ui/async-await/inference_var_self_argument.stderr +++ b/tests/ui/async-await/inference_var_self_argument.stderr @@ -14,7 +14,7 @@ LL | async fn foo(self: &dyn Foo) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/inference_var_self_argument.rs:5:14 | LL | trait Foo { diff --git a/tests/ui/async-await/issue-98634.rs b/tests/ui/async-await/issue-98634.rs index 02e869f4325..3bfc2bf8a7c 100644 --- a/tests/ui/async-await/issue-98634.rs +++ b/tests/ui/async-await/issue-98634.rs @@ -43,8 +43,8 @@ impl Runtime { fn main() { Runtime.block_on(async { StructAsync { callback }.await; - //~^ ERROR expected `callback` to be a fn item that returns `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>` - //~| ERROR expected `callback` to be a fn item that returns `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>` - //~| ERROR expected `callback` to be a fn item that returns `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>` + //~^ ERROR expected `callback` to return `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>` + //~| ERROR expected `callback` to return `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>` + //~| ERROR expected `callback` to return `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>` }); } diff --git a/tests/ui/async-await/issue-98634.stderr b/tests/ui/async-await/issue-98634.stderr index 574904ceafa..e0739ae3a9b 100644 --- a/tests/ui/async-await/issue-98634.stderr +++ b/tests/ui/async-await/issue-98634.stderr @@ -1,4 +1,4 @@ -error[E0271]: expected `callback` to be a fn item that returns `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>` +error[E0271]: expected `callback` to return `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>` --> $DIR/issue-98634.rs:45:23 | LL | StructAsync { callback }.await; @@ -10,7 +10,7 @@ note: required by a bound in `StructAsync` LL | pub struct StructAsync<F: Fn() -> Pin<Box<dyn Future<Output = ()>>>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StructAsync` -error[E0271]: expected `callback` to be a fn item that returns `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>` +error[E0271]: expected `callback` to return `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>` --> $DIR/issue-98634.rs:45:9 | LL | StructAsync { callback }.await; @@ -22,7 +22,7 @@ note: required by a bound in `StructAsync` LL | pub struct StructAsync<F: Fn() -> Pin<Box<dyn Future<Output = ()>>>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StructAsync` -error[E0271]: expected `callback` to be a fn item that returns `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>` +error[E0271]: expected `callback` to return `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>` --> $DIR/issue-98634.rs:45:34 | LL | StructAsync { callback }.await; diff --git a/tests/ui/borrowck/already-borrowed-as-mutable-if-let-133941.rs b/tests/ui/borrowck/already-borrowed-as-mutable-if-let-133941.rs new file mode 100644 index 00000000000..934aac8383d --- /dev/null +++ b/tests/ui/borrowck/already-borrowed-as-mutable-if-let-133941.rs @@ -0,0 +1,46 @@ +// https://github.com/rust-lang/rust/issues/133941 +use std::marker::PhantomData; + +struct Bar<'a>(PhantomData<&'a mut i32>); + +impl<'a> Drop for Bar<'a> { + fn drop(&mut self) {} +} + +struct Foo(); + +impl Foo { + fn f(&mut self) -> Option<Bar<'_>> { + None + } + + fn g(&mut self) {} +} + +fn main() { + let mut foo = Foo(); + while let Some(_) = foo.f() { + //~^ HELP matches! + foo.g(); + //~^ ERROR [E0499] + } + if let Some(_) = foo.f() { + //~^ HELP matches! + foo.g(); + //~^ ERROR [E0499] + } + while let Some(_x) = foo.f() { + foo.g(); + //~^ ERROR [E0499] + } + if let Some(_x) = foo.f() { + foo.g(); + //~^ ERROR [E0499] + } + while let Some(_x) = {let _x = foo.f(); foo.g(); None::<()>} { + //~^ ERROR [E0499] + } + if let Some(_x) = {let _x = foo.f(); foo.g(); None::<()>} { + //~^ ERROR [E0499] + } +} diff --git a/tests/ui/borrowck/already-borrowed-as-mutable-if-let-133941.stderr b/tests/ui/borrowck/already-borrowed-as-mutable-if-let-133941.stderr new file mode 100644 index 00000000000..bb21caccbaf --- /dev/null +++ b/tests/ui/borrowck/already-borrowed-as-mutable-if-let-133941.stderr @@ -0,0 +1,89 @@ +error[E0499]: cannot borrow `foo` as mutable more than once at a time + --> $DIR/already-borrowed-as-mutable-if-let-133941.rs:24:9 + | +LL | while let Some(_) = foo.f() { + | ------- + | | + | first mutable borrow occurs here + | a temporary with access to the first borrow is created here ... +LL | +LL | foo.g(); + | ^^^ second mutable borrow occurs here +LL | +LL | } + | - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option<Bar<'_>>` + | +help: consider using the `matches!` macro + | +LL | while matches!(foo.f(), Some(_)) { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0499]: cannot borrow `foo` as mutable more than once at a time + --> $DIR/already-borrowed-as-mutable-if-let-133941.rs:29:9 + | +LL | if let Some(_) = foo.f() { + | ------- + | | + | first mutable borrow occurs here + | a temporary with access to the first borrow is created here ... +LL | +LL | foo.g(); + | ^^^ second mutable borrow occurs here +LL | +LL | } + | - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option<Bar<'_>>` + | +help: consider using the `matches!` macro + | +LL | if matches!(foo.f(), Some(_)) { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0499]: cannot borrow `foo` as mutable more than once at a time + --> $DIR/already-borrowed-as-mutable-if-let-133941.rs:33:9 + | +LL | while let Some(_x) = foo.f() { + | ------- + | | + | first mutable borrow occurs here + | a temporary with access to the first borrow is created here ... +LL | foo.g(); + | ^^^ second mutable borrow occurs here +LL | +LL | } + | - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option<Bar<'_>>` + +error[E0499]: cannot borrow `foo` as mutable more than once at a time + --> $DIR/already-borrowed-as-mutable-if-let-133941.rs:37:9 + | +LL | if let Some(_x) = foo.f() { + | ------- + | | + | first mutable borrow occurs here + | a temporary with access to the first borrow is created here ... +LL | foo.g(); + | ^^^ second mutable borrow occurs here +LL | +LL | } + | - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option<Bar<'_>>` + +error[E0499]: cannot borrow `foo` as mutable more than once at a time + --> $DIR/already-borrowed-as-mutable-if-let-133941.rs:40:45 + | +LL | while let Some(_x) = {let _x = foo.f(); foo.g(); None::<()>} { + | --- ^^^ - first borrow might be used here, when `_x` is dropped and runs the destructor for type `Option<Bar<'_>>` + | | | + | | second mutable borrow occurs here + | first mutable borrow occurs here + +error[E0499]: cannot borrow `foo` as mutable more than once at a time + --> $DIR/already-borrowed-as-mutable-if-let-133941.rs:43:42 + | +LL | if let Some(_x) = {let _x = foo.f(); foo.g(); None::<()>} { + | --- ^^^ - first borrow might be used here, when `_x` is dropped and runs the destructor for type `Option<Bar<'_>>` + | | | + | | second mutable borrow occurs here + | first mutable borrow occurs here + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/closures/return-type-doesnt-match-bound.rs b/tests/ui/closures/return-type-doesnt-match-bound.rs new file mode 100644 index 00000000000..af15385d4b0 --- /dev/null +++ b/tests/ui/closures/return-type-doesnt-match-bound.rs @@ -0,0 +1,25 @@ +use std::error::Error; +use std::process::exit; + +fn foo<F>(f: F) -> () +where + F: FnOnce() -> Result<(), Box<dyn Error>>, +{ + f().or_else(|e| -> ! { //~ ERROR to return + eprintln!("{:?}", e); + exit(1) + }); +} + +fn bar<F>(f: F) -> () +where + F: FnOnce() -> Result<(), Box<dyn Error>>, +{ + let c = |e| -> ! { //~ ERROR to return + eprintln!("{:?}", e); + exit(1) + }; + f().or_else(c); +} + +fn main() {} diff --git a/tests/ui/closures/return-type-doesnt-match-bound.stderr b/tests/ui/closures/return-type-doesnt-match-bound.stderr new file mode 100644 index 00000000000..c0bc2f6084c --- /dev/null +++ b/tests/ui/closures/return-type-doesnt-match-bound.stderr @@ -0,0 +1,37 @@ +error[E0271]: expected `{closure@return-type-doesnt-match-bound.rs:8:17}` to return `Result<(), _>`, but it returns `!` + --> $DIR/return-type-doesnt-match-bound.rs:8:24 + | +LL | f().or_else(|e| -> ! { + | ------- -------^ + | | | | + | | | expected `Result<(), _>`, found `!` + | | this closure + | required by a bound introduced by this call + | + = note: expected enum `Result<(), _>` + found type `!` +note: required by a bound in `Result::<T, E>::or_else` + --> $SRC_DIR/core/src/result.rs:LL:COL + +error[E0271]: expected `{closure@return-type-doesnt-match-bound.rs:18:13}` to return `Result<(), _>`, but it returns `!` + --> $DIR/return-type-doesnt-match-bound.rs:18:20 + | +LL | let c = |e| -> ! { + | -------^ + | | | + | | expected `Result<(), _>`, found `!` + | this closure +... +LL | f().or_else(c); + | ------- - closure used here + | | + | required by a bound introduced by this call + | + = note: expected enum `Result<(), _>` + found type `!` +note: required by a bound in `Result::<T, E>::or_else` + --> $SRC_DIR/core/src/result.rs:LL:COL + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/coercion/coerce-expect-unsized-ascribed.stderr b/tests/ui/coercion/coerce-expect-unsized-ascribed.stderr index 0c220a13876..b682bdac034 100644 --- a/tests/ui/coercion/coerce-expect-unsized-ascribed.stderr +++ b/tests/ui/coercion/coerce-expect-unsized-ascribed.stderr @@ -29,7 +29,7 @@ error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:14:27 | LL | let _ = type_ascribe!(Box::new( { |x| (x as u8) }), Box<dyn Fn(i32) -> _>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Box<dyn Fn(i32) -> u8>`, found `Box<{closure@coerce-expect-unsized-ascribed.rs:14:39}>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Box<dyn Fn(i32) -> u8>`, found `Box<{closure@...}>` | = note: expected struct `Box<dyn Fn(i32) -> u8>` found struct `Box<{closure@$DIR/coerce-expect-unsized-ascribed.rs:14:39: 14:42}>` @@ -85,7 +85,7 @@ error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:22:27 | LL | let _ = type_ascribe!(&{ |x| (x as u8) }, &dyn Fn(i32) -> _); - | ^^^^^^^^^^^^^^^^^^ expected `&dyn Fn(i32) -> u8`, found `&{closure@coerce-expect-unsized-ascribed.rs:22:30}` + | ^^^^^^^^^^^^^^^^^^ expected `&dyn Fn(i32) -> u8`, found `&{closure@...}` | = note: expected reference `&dyn Fn(i32) -> u8` found reference `&{closure@$DIR/coerce-expect-unsized-ascribed.rs:22:30: 22:33}` @@ -123,7 +123,7 @@ error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:27:27 | LL | let _ = type_ascribe!(Box::new(|x| (x as u8)), Box<dyn Fn(i32) -> _>); - | ^^^^^^^^^^^^^^^^^^^^^^^ expected `Box<dyn Fn(i32) -> u8>`, found `Box<{closure@coerce-expect-unsized-ascribed.rs:27:36}>` + | ^^^^^^^^^^^^^^^^^^^^^^^ expected `Box<dyn Fn(i32) -> u8>`, found `Box<{closure@...}>` | = note: expected struct `Box<dyn Fn(i32) -> u8>` found struct `Box<{closure@$DIR/coerce-expect-unsized-ascribed.rs:27:36: 27:39}>` diff --git a/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr b/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr index 20257bbaf28..033bfee226f 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr +++ b/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr @@ -5,7 +5,7 @@ LL | impl DynIncompatible for dyn DynIncompatible { } | ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/coherence-impl-trait-for-trait-dyn-compatible.rs:6:45 | LL | trait DynIncompatible { fn eq(&self, other: Self); } diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr index cd7f3a3c21d..6fa9b591ad2 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr @@ -5,7 +5,7 @@ LL | fn foo(a: &dyn ConstParamTy_) {} | ^^^^^^^^^^^^^ `ConstParamTy_` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: the trait is not dyn compatible because it uses `Self` as a type parameter @@ -21,7 +21,7 @@ LL | fn bar(a: &dyn UnsizedConstParamTy) {} | ^^^^^^^^^^^^^^^^^^^ `UnsizedConstParamTy` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: the trait is not dyn compatible because it uses `Self` as a type parameter diff --git a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr index 763bc626c9d..8bc6ef093d0 100644 --- a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr +++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr @@ -5,7 +5,7 @@ LL | fn use_dyn(v: &dyn Foo) { | ^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/dyn-compatibility-err-ret.rs:8:8 | LL | trait Foo { @@ -24,7 +24,7 @@ LL | v.test(); | ^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/dyn-compatibility-err-ret.rs:8:8 | LL | trait Foo { diff --git a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr index 56678e4e9af..f5eaaa37916 100644 --- a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr +++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr @@ -5,7 +5,7 @@ LL | fn use_dyn(v: &dyn Foo) { | ^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/dyn-compatibility-err-where-bounds.rs:8:8 | LL | trait Foo { @@ -22,7 +22,7 @@ LL | v.test(); | ^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/dyn-compatibility-err-where-bounds.rs:8:8 | LL | trait Foo { diff --git a/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr b/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr index bd1811bd2cc..57b61006631 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr @@ -99,7 +99,7 @@ LL | fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {} | ^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-102768.rs:5:10 | LL | trait X { diff --git a/tests/ui/const-generics/issues/issue-88119.stderr b/tests/ui/const-generics/issues/issue-88119.stderr index f219c90849a..c497f1b6d0b 100644 --- a/tests/ui/const-generics/issues/issue-88119.stderr +++ b/tests/ui/const-generics/issues/issue-88119.stderr @@ -6,35 +6,29 @@ LL | #![feature(const_trait_impl, generic_const_exprs)] | = help: remove one of these features -error[E0284]: type annotations needed: cannot normalize `<&T as ConstName>::{constant#0}` - --> $DIR/issue-88119.rs:19:49 +error[E0284]: type annotations needed: cannot satisfy `the constant `name_len::<T>()` can be evaluated` + --> $DIR/issue-88119.rs:21:5 | -LL | impl<T: ?Sized + ConstName> const ConstName for &T - | ^^ cannot normalize `<&T as ConstName>::{constant#0}` +LL | [(); name_len::<T>()]:, + | ^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `name_len::<T>()` can be evaluated` | -note: required for `&T` to implement `~const ConstName` - --> $DIR/issue-88119.rs:19:35 +note: required by a bound in `<&T as ConstName>` + --> $DIR/issue-88119.rs:21:10 | -LL | impl<T: ?Sized + ConstName> const ConstName for &T - | ^^^^^^^^^ ^^ -LL | where LL | [(); name_len::<T>()]:, - | --------------------- unsatisfied trait bound introduced here + | ^^^^^^^^^^^^^^^ required by this bound in `<&T as ConstName>` -error[E0284]: type annotations needed: cannot normalize `<&mut T as ConstName>::{constant#0}` - --> $DIR/issue-88119.rs:26:49 +error[E0284]: type annotations needed: cannot satisfy `the constant `name_len::<T>()` can be evaluated` + --> $DIR/issue-88119.rs:28:5 | -LL | impl<T: ?Sized + ConstName> const ConstName for &mut T - | ^^^^^^ cannot normalize `<&mut T as ConstName>::{constant#0}` +LL | [(); name_len::<T>()]:, + | ^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `name_len::<T>()` can be evaluated` | -note: required for `&mut T` to implement `~const ConstName` - --> $DIR/issue-88119.rs:26:35 +note: required by a bound in `<&mut T as ConstName>` + --> $DIR/issue-88119.rs:28:10 | -LL | impl<T: ?Sized + ConstName> const ConstName for &mut T - | ^^^^^^^^^ ^^^^^^ -LL | where LL | [(); name_len::<T>()]:, - | --------------------- unsatisfied trait bound introduced here + | ^^^^^^^^^^^^^^^ required by this bound in `<&mut T as ConstName>` error: aborting due to 3 previous errors diff --git a/tests/ui/const-ptr/forbidden_slices.stderr b/tests/ui/const-ptr/forbidden_slices.stderr index fad078ad2b2..2e0c04dcf1e 100644 --- a/tests/ui/const-ptr/forbidden_slices.stderr +++ b/tests/ui/const-ptr/forbidden_slices.stderr @@ -190,7 +190,7 @@ LL | from_ptr_range(ptr..ptr.add(1)) error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: `ptr_offset_from_unsigned` called on pointers into different allocations + = note: `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation | note: inside `std::ptr::const_ptr::<impl *const u32>::sub_ptr` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -205,7 +205,7 @@ LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).ad error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: `ptr_offset_from_unsigned` called on pointers into different allocations + = note: `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation | note: inside `std::ptr::const_ptr::<impl *const u32>::sub_ptr` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL diff --git a/tests/ui/consts/bad-array-size-in-type-err.rs b/tests/ui/consts/bad-array-size-in-type-err.rs index cb02ad3205d..0490a9d3620 100644 --- a/tests/ui/consts/bad-array-size-in-type-err.rs +++ b/tests/ui/consts/bad-array-size-in-type-err.rs @@ -8,3 +8,14 @@ fn main() { //~^ ERROR mismatched types //~| ERROR the constant `2` is not of type `usize` } + +fn iter(val: BadArraySize::<2>) { + for _ in val.arr {} + //~^ ERROR the constant `2` is not of type `usize` + //~| ERROR `[i32; 2]` is not an iterator +} + +// issue #131102 +pub struct Blorb<const N: u16>([String; N]); //~ ERROR the constant `N` is not of type `usize` +pub struct Wrap(Blorb<0>); +pub const fn i(_: Wrap) {} //~ ERROR destructor of `Wrap` cannot be evaluated at compile-time diff --git a/tests/ui/consts/bad-array-size-in-type-err.stderr b/tests/ui/consts/bad-array-size-in-type-err.stderr index c3ff216432e..84e16f8d931 100644 --- a/tests/ui/consts/bad-array-size-in-type-err.stderr +++ b/tests/ui/consts/bad-array-size-in-type-err.stderr @@ -6,6 +6,14 @@ LL | arr: [i32; N], | = note: the length of array `[i32; N]` must be type `usize` +error: the constant `N` is not of type `usize` + --> $DIR/bad-array-size-in-type-err.rs:19:32 + | +LL | pub struct Blorb<const N: u16>([String; N]); + | ^^^^^^^^^^^ expected `usize`, found `u16` + | + = note: the length of array `[String; N]` must be type `usize` + error[E0308]: mismatched types --> $DIR/bad-array-size-in-type-err.rs:7:38 | @@ -20,6 +28,37 @@ LL | let _ = BadArraySize::<2> { arr: [0, 0, 0] }; | = note: the length of array `[i32; 2]` must be type `usize` -error: aborting due to 3 previous errors +error: the constant `2` is not of type `usize` + --> $DIR/bad-array-size-in-type-err.rs:13:14 + | +LL | for _ in val.arr {} + | ^^^^^^^ expected `usize`, found `u8` + | + = note: the length of array `[i32; 2]` must be type `usize` + +error[E0277]: `[i32; 2]` is not an iterator + --> $DIR/bad-array-size-in-type-err.rs:13:14 + | +LL | for _ in val.arr {} + | ^^^^^^^ `[i32; 2]` is not an iterator; try calling `.into_iter()` or `.iter()` + | + = help: the trait `IntoIterator` is not implemented for `[i32; 2]` + = help: the following other types implement trait `IntoIterator`: + &[T; N] + &[T] + &mut [T; N] + &mut [T] + [T; N] + +error[E0493]: destructor of `Wrap` cannot be evaluated at compile-time + --> $DIR/bad-array-size-in-type-err.rs:21:16 + | +LL | pub const fn i(_: Wrap) {} + | ^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions + +error: aborting due to 7 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0277, E0308, E0493. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/const-slice-array-deref.rs b/tests/ui/consts/const-slice-array-deref.rs new file mode 100644 index 00000000000..9d84ed4bdb0 --- /dev/null +++ b/tests/ui/consts/const-slice-array-deref.rs @@ -0,0 +1,9 @@ +const ONE: [u16] = [1]; +//~^ ERROR the size for values of type `[u16]` cannot be known at compilation time +//~| ERROR the size for values of type `[u16]` cannot be known at compilation time +//~| ERROR mismatched types + +const TWO: &'static u16 = &ONE[0]; +//~^ ERROR cannot move a value of type `[u16]` + +fn main() {} diff --git a/tests/ui/consts/const-slice-array-deref.stderr b/tests/ui/consts/const-slice-array-deref.stderr new file mode 100644 index 00000000000..6e69744144e --- /dev/null +++ b/tests/ui/consts/const-slice-array-deref.stderr @@ -0,0 +1,33 @@ +error[E0277]: the size for values of type `[u16]` cannot be known at compilation time + --> $DIR/const-slice-array-deref.rs:1:12 + | +LL | const ONE: [u16] = [1]; + | ^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u16]` + +error[E0308]: mismatched types + --> $DIR/const-slice-array-deref.rs:1:20 + | +LL | const ONE: [u16] = [1]; + | ^^^ expected `[u16]`, found `[u16; 1]` + +error[E0277]: the size for values of type `[u16]` cannot be known at compilation time + --> $DIR/const-slice-array-deref.rs:1:20 + | +LL | const ONE: [u16] = [1]; + | ^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u16]` + = note: constant expressions must have a statically known size + +error[E0161]: cannot move a value of type `[u16]` + --> $DIR/const-slice-array-deref.rs:6:28 + | +LL | const TWO: &'static u16 = &ONE[0]; + | ^^^ the size of `[u16]` cannot be statically determined + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0161, E0277, E0308. +For more information about an error, try `rustc --explain E0161`. diff --git a/tests/ui/consts/large_const_alloc.rs b/tests/ui/consts/large_const_alloc.rs index 61a22216ae5..14edc1bb696 100644 --- a/tests/ui/consts/large_const_alloc.rs +++ b/tests/ui/consts/large_const_alloc.rs @@ -1,5 +1,7 @@ //@ only-64bit // on 32bit and 16bit platforms it is plausible that the maximum allocation size will succeed +// FIXME (#135952) In some cases on AArch64 Linux the diagnostic does not trigger +//@ ignore-aarch64-unknown-linux-gnu const FOO: () = { // 128 TiB, unlikely anyone has that much RAM diff --git a/tests/ui/consts/large_const_alloc.stderr b/tests/ui/consts/large_const_alloc.stderr index 25d660f1217..fa7d5977a95 100644 --- a/tests/ui/consts/large_const_alloc.stderr +++ b/tests/ui/consts/large_const_alloc.stderr @@ -1,11 +1,11 @@ error[E0080]: evaluation of constant value failed - --> $DIR/large_const_alloc.rs:6:13 + --> $DIR/large_const_alloc.rs:8:13 | LL | let x = [0_u8; (1 << 47) - 1]; | ^^^^^^^^^^^^^^^^^^^^^ tried to allocate more memory than available to compiler error[E0080]: could not evaluate static initializer - --> $DIR/large_const_alloc.rs:11:13 + --> $DIR/large_const_alloc.rs:13:13 | LL | let x = [0_u8; (1 << 47) - 1]; | ^^^^^^^^^^^^^^^^^^^^^ tried to allocate more memory than available to compiler diff --git a/tests/ui/consts/offset_from_ub.rs b/tests/ui/consts/offset_from_ub.rs index 0232b03a813..88356900605 100644 --- a/tests/ui/consts/offset_from_ub.rs +++ b/tests/ui/consts/offset_from_ub.rs @@ -17,7 +17,7 @@ pub const DIFFERENT_ALLOC: usize = { let uninit2 = std::mem::MaybeUninit::<Struct>::uninit(); let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct; let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) }; //~ERROR evaluation of constant value failed - //~| pointers into different allocations + //~| not both derived from the same allocation offset as usize }; @@ -37,7 +37,7 @@ pub const DIFFERENT_INT: isize = { // offset_from with two different integers: l let ptr1 = 8 as *const u8; let ptr2 = 16 as *const u8; unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed - //~| dangling pointer + //~| not both derived from the same allocation }; const OUT_OF_BOUNDS_1: isize = { @@ -46,7 +46,7 @@ const OUT_OF_BOUNDS_1: isize = { let end_ptr = (start_ptr).wrapping_add(length); // First ptr is out of bounds unsafe { ptr_offset_from(end_ptr, start_ptr) } //~ERROR evaluation of constant value failed - //~| expected a pointer to 10 bytes of memory + //~| the memory range between them is not in-bounds of an allocation }; const OUT_OF_BOUNDS_2: isize = { @@ -55,7 +55,7 @@ const OUT_OF_BOUNDS_2: isize = { let end_ptr = (start_ptr).wrapping_add(length); // Second ptr is out of bounds unsafe { ptr_offset_from(start_ptr, end_ptr) } //~ERROR evaluation of constant value failed - //~| expected a pointer to the end of 10 bytes of memory + //~| the memory range between them is not in-bounds of an allocation }; pub const DIFFERENT_ALLOC_UNSIGNED: usize = { @@ -64,7 +64,7 @@ pub const DIFFERENT_ALLOC_UNSIGNED: usize = { let uninit2 = std::mem::MaybeUninit::<Struct>::uninit(); let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct; unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) } //~ERROR evaluation of constant value failed - //~| pointers into different allocations + //~| not both derived from the same allocation }; pub const TOO_FAR_APART1: isize = { diff --git a/tests/ui/consts/offset_from_ub.stderr b/tests/ui/consts/offset_from_ub.stderr index ac4597ff011..1379365cc25 100644 --- a/tests/ui/consts/offset_from_ub.stderr +++ b/tests/ui/consts/offset_from_ub.stderr @@ -2,12 +2,12 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:19:27 | LL | let offset = unsafe { ptr_offset_from(field_ptr, base_ptr) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on pointers into different allocations + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: `ptr_offset_from` called on pointers into different allocations + = note: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation | note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -27,25 +27,25 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:39:14 | LL | unsafe { ptr_offset_from(ptr2, ptr1) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from` origin: expected a pointer to $BYTES bytes of memory, but got 0x8[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers that are not both derived from the same allocation error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:48:14 | LL | unsafe { ptr_offset_from(end_ptr, start_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from` origin: expected a pointer to $BYTES bytes of memory, but got ALLOC0 which is only $BYTES bytes from the end of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:57:14 | LL | unsafe { ptr_offset_from(start_ptr, end_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from` origin: expected a pointer to the end of $BYTES bytes of memory, but got ALLOC1+0xa which does not have enough space to the beginning of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on two different pointers where the memory range between them is not in-bounds of an allocation error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:66:14 | LL | unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on pointers into different allocations + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called on two different pointers that are not both derived from the same allocation error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:73:14 @@ -80,7 +80,7 @@ LL | unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: out-of-bounds `offset_from` origin: expected a pointer to $BYTES bytes of memory, but got a null pointer + = note: `ptr_offset_from` called on two different pointers that are not both derived from the same allocation | note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL diff --git a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs index b923a768cbf..53618e2e86a 100644 --- a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs +++ b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.rs @@ -3,6 +3,8 @@ // Needs the max type size to be much bigger than the RAM people typically have. //@ only-64bit +// FIXME (#135952) In some cases on AArch64 Linux the diagnostic does not trigger +//@ ignore-aarch64-unknown-linux-gnu pub struct Data([u8; (1 << 47) - 1]); const _: &'static Data = &Data([0; (1 << 47) - 1]); diff --git a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr index f5d767efceb..aac805dbd8c 100644 --- a/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr +++ b/tests/ui/consts/promoted_running_out_of_memory_issue-130687.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation of constant value failed - --> $DIR/promoted_running_out_of_memory_issue-130687.rs:8:32 + --> $DIR/promoted_running_out_of_memory_issue-130687.rs:10:32 | LL | const _: &'static Data = &Data([0; (1 << 47) - 1]); | ^^^^^^^^^^^^^^^^^^ tried to allocate more memory than available to compiler diff --git a/tests/ui/derives/rustc-decodable-issue-123156.rs b/tests/ui/derives/rustc-decodable-issue-123156.rs deleted file mode 100644 index 1983837ed8d..00000000000 --- a/tests/ui/derives/rustc-decodable-issue-123156.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ check-pass -//@ edition:2021 -//@ aux-build:rustc-serialize.rs - -#![crate_type = "lib"] -#![allow(deprecated, soft_unstable)] - -extern crate rustc_serialize; - -#[derive(RustcDecodable)] -pub enum Foo {} diff --git a/tests/ui/derives/rustc-decodable-issue-123156.stderr b/tests/ui/derives/rustc-decodable-issue-123156.stderr deleted file mode 100644 index 93a993b90d8..00000000000 --- a/tests/ui/derives/rustc-decodable-issue-123156.stderr +++ /dev/null @@ -1,10 +0,0 @@ -Future incompatibility report: Future breakage diagnostic: -warning: use of unstable library feature `rustc_encodable_decodable`: derive macro for `rustc-serialize`; should not be used in new code - --> $DIR/rustc-decodable-issue-123156.rs:10:10 - | -LL | #[derive(RustcDecodable)] - | ^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #64266 <https://github.com/rust-lang/rust/issues/64266> - diff --git a/tests/ui/diagnostic-width/E0271.ascii.stderr b/tests/ui/diagnostic-width/E0271.ascii.stderr index 7446b1a543e..93555b336a6 100644 --- a/tests/ui/diagnostic-width/E0271.ascii.stderr +++ b/tests/ui/diagnostic-width/E0271.ascii.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<Result<Result<(), Result<Result<(), Result<Result<(), Option<{integer}>>, ...>>, ...>>, ...> as Future>::Error == Foo` +error[E0271]: type mismatch resolving `<Result<..., ()> as Future>::Error == Foo` --> $DIR/E0271.rs:20:5 | LL | / Box::new( @@ -7,14 +7,16 @@ LL | | Err::<(), _>( LL | | Ok::<_, ()>( ... | LL | | ) - | |_____^ type mismatch resolving `<Result<Result<(), Result<Result<(), ...>, ...>>, ...> as Future>::Error == Foo` + | |_____^ type mismatch resolving `<Result<..., ()> as Future>::Error == Foo` | note: expected this to be `Foo` --> $DIR/E0271.rs:10:18 | LL | type Error = E; | ^ - = note: required for the cast from `Box<Result<Result<(), Result<Result<(), Result<Result<(), Option<{integer}>>, ()>>, ()>>, ()>>` to `Box<(dyn Future<Error = Foo> + 'static)>` + = note: required for the cast from `Box<Result<..., ()>>` to `Box<...>` + = note: the full name for the type has been written to '$TEST_BUILD_DIR/diagnostic-width/E0271.ascii/E0271.long-type-hash.txt' + = note: consider using `--verbose` to print the full type name to the console error: aborting due to 1 previous error diff --git a/tests/ui/diagnostic-width/E0271.rs b/tests/ui/diagnostic-width/E0271.rs index 061ba45c219..2faf09d46c6 100644 --- a/tests/ui/diagnostic-width/E0271.rs +++ b/tests/ui/diagnostic-width/E0271.rs @@ -1,6 +1,6 @@ //@ revisions: ascii unicode -//@[ascii] compile-flags: --diagnostic-width=40 -//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode --diagnostic-width=40 +//@[ascii] compile-flags: --diagnostic-width=40 -Zwrite-long-types-to-disk=yes +//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode --diagnostic-width=40 -Zwrite-long-types-to-disk=yes //@ normalize-stderr: "long-type-\d+" -> "long-type-hash" trait Future { type Error; diff --git a/tests/ui/diagnostic-width/E0271.unicode.stderr b/tests/ui/diagnostic-width/E0271.unicode.stderr index 72df2a381a4..1e9acf603b2 100644 --- a/tests/ui/diagnostic-width/E0271.unicode.stderr +++ b/tests/ui/diagnostic-width/E0271.unicode.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<Result<Result<(), Result<Result<(), Result<Result<(), Option<{integer}>>, ...>>, ...>>, ...> as Future>::Error == Foo` +error[E0271]: type mismatch resolving `<Result<..., ()> as Future>::Error == Foo` ╭▸ $DIR/E0271.rs:20:5 │ LL │ ┏ Box::new( @@ -7,14 +7,16 @@ LL │ ┃ Err::<(), _>( LL │ ┃ Ok::<_, ()>( ‡ ┃ LL │ ┃ ) - │ ┗━━━━━┛ type mismatch resolving `<Result<Result<(), Result<Result<(), ...>, ...>>, ...> as Future>::Error == Foo` + │ ┗━━━━━┛ type mismatch resolving `<Result<..., ()> as Future>::Error == Foo` ╰╴ note: expected this to be `Foo` ╭▸ $DIR/E0271.rs:10:18 │ LL │ type Error = E; │ ━ - ╰ note: required for the cast from `Box<Result<Result<(), Result<Result<(), Result<Result<(), Option<{integer}>>, ()>>, ()>>, ()>>` to `Box<(dyn Future<Error = Foo> + 'static)>` + ├ note: required for the cast from `Box<Result<..., ()>>` to `Box<...>` + ├ note: the full name for the type has been written to '$TEST_BUILD_DIR/diagnostic-width/E0271.unicode/E0271.long-type-hash.txt' + ╰ note: consider using `--verbose` to print the full type name to the console error: aborting due to 1 previous error diff --git a/tests/ui/diagnostic-width/long-E0308.ascii.stderr b/tests/ui/diagnostic-width/long-E0308.ascii.stderr index d45d6bf329b..83da5586188 100644 --- a/tests/ui/diagnostic-width/long-E0308.ascii.stderr +++ b/tests/ui/diagnostic-width/long-E0308.ascii.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/long-E0308.rs:46:9 + --> $DIR/long-E0308.rs:48:9 | LL | let x: Atype< | _____________- @@ -16,15 +16,15 @@ LL | | Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok... LL | | Ok("") LL | | )))))))))))))))))))))))))))))) LL | | )))))))))))))))))))))))))))))); - | |__________________________________^ expected `Atype<Btype<..., ...>, ...>`, found `Result<Result<..., ...>, ...>` + | |__________________________________^ expected `Atype<Btype<Ctype<..., i32>, i32>, i32>`, found `Result<Result<Result<..., _>, _>, _>` | - = note: expected struct `Atype<Btype<..., ...>, ...>` - found enum `Result<Result<..., ...>, ...>` - = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.ascii/long-E0308.long-type-hash.txt' + = note: expected struct `Atype<Btype<..., i32>, i32>` + found enum `Result<Result<..., _>, _>` + = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types - --> $DIR/long-E0308.rs:59:26 + --> $DIR/long-E0308.rs:61:26 | LL | ))))))))))))))))) == Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(O... | __________________________^ @@ -32,15 +32,15 @@ LL | | Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(... LL | | Ok(Ok(Ok(Ok(Ok(Ok(Ok(""))))))) LL | | )))))))))))))))))))))))))))))) LL | | )))))))))))))))))))))))); - | |____________________________^ expected `Option<Result<..., ...>>`, found `Result<Result<..., ...>, ...>` + | |____________________________^ expected `Option<Result<Option<Option<...>>, _>>`, found `Result<Result<Result<..., _>, _>, _>` | - = note: expected enum `Option<Result<..., ...>>` - found enum `Result<Result<..., ...>, ...>` - = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.ascii/long-E0308.long-type-hash.txt' + = note: expected enum `Option<Result<Option<...>, _>>` + found enum `Result<Result<..., _>, _>` + = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types - --> $DIR/long-E0308.rs:90:9 + --> $DIR/long-E0308.rs:92:9 | LL | let x: Atype< | ____________- @@ -50,17 +50,17 @@ LL | | Atype< ... | LL | | i32 LL | | > = (); - | | - ^^ expected `Atype<Btype<..., ...>, ...>`, found `()` + | | - ^^ expected `Atype<Btype<Ctype<..., i32>, i32>, i32>`, found `()` | |_____| | expected due to this | - = note: expected struct `Atype<Btype<..., ...>, ...>` + = note: expected struct `Atype<Btype<..., i32>, i32>` found unit type `()` - = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.ascii/long-E0308.long-type-hash.txt' + = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types - --> $DIR/long-E0308.rs:93:17 + --> $DIR/long-E0308.rs:95:17 | LL | let _: () = Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(O... | ____________--___^ @@ -70,11 +70,11 @@ LL | | Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(... LL | | Ok(Ok(Ok(Ok(Ok(Ok(Ok(""))))))) LL | | )))))))))))))))))))))))))))))) LL | | )))))))))))))))))))))))); - | |____________________________^ expected `()`, found `Result<Result<..., ...>, ...>` + | |____________________________^ expected `()`, found `Result<Result<Result<..., _>, _>, _>` | = note: expected unit type `()` - found enum `Result<Result<..., ...>, ...>` - = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.ascii/long-E0308.long-type-hash.txt' + found enum `Result<Result<..., _>, _>` + = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console error: aborting due to 4 previous errors diff --git a/tests/ui/diagnostic-width/long-E0308.rs b/tests/ui/diagnostic-width/long-E0308.rs index 93987226020..26383d9418d 100644 --- a/tests/ui/diagnostic-width/long-E0308.rs +++ b/tests/ui/diagnostic-width/long-E0308.rs @@ -1,7 +1,9 @@ //@ revisions: ascii unicode //@[ascii] compile-flags: --diagnostic-width=60 -Zwrite-long-types-to-disk=yes //@[unicode] compile-flags: -Zunstable-options --json=diagnostic-unicode --diagnostic-width=60 -Zwrite-long-types-to-disk=yes -//@ normalize-stderr: "long-type-\d+" -> "long-type-hash" + +// The regex below normalizes the long type file name to make it suitable for compare-modes. +//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type-\d+.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type-hash.txt'" mod a { // Force the "short path for unique types" machinery to trip up diff --git a/tests/ui/diagnostic-width/long-E0308.unicode.stderr b/tests/ui/diagnostic-width/long-E0308.unicode.stderr index 3e8d881d7a6..54abf576dbd 100644 --- a/tests/ui/diagnostic-width/long-E0308.unicode.stderr +++ b/tests/ui/diagnostic-width/long-E0308.unicode.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - ╭▸ $DIR/long-E0308.rs:46:9 + ╭▸ $DIR/long-E0308.rs:48:9 │ LL │ let x: Atype< │ ┌─────────────┘ @@ -16,15 +16,15 @@ LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(O… LL │ ┃ Ok("") LL │ ┃ )))))))))))))))))))))))))))))) LL │ ┃ )))))))))))))))))))))))))))))); - │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Atype<Btype<..., ...>, ...>`, found `Result<Result<..., ...>, ...>` + │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Atype<Btype<Ctype<..., i32>, i32>, i32>`, found `Result<Result<Result<..., _>, _>, _>` │ - ├ note: expected struct `Atype<Btype<..., ...>, ...>` - │ found enum `Result<Result<..., ...>, ...>` - ├ note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.unicode/long-E0308.long-type-hash.txt' + ├ note: expected struct `Atype<Btype<..., i32>, i32>` + │ found enum `Result<Result<..., _>, _>` + ├ note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' ╰ note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types - ╭▸ $DIR/long-E0308.rs:59:26 + ╭▸ $DIR/long-E0308.rs:61:26 │ LL │ ))))))))))))))))) == Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(… │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━┛ @@ -32,15 +32,15 @@ LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok… LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(""))))))) LL │ ┃ )))))))))))))))))))))))))))))) LL │ ┃ )))))))))))))))))))))))); - │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Option<Result<..., ...>>`, found `Result<Result<..., ...>, ...>` + │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Option<Result<Option<Option<...>>, _>>`, found `Result<Result<Result<..., _>, _>, _>` │ - ├ note: expected enum `Option<Result<..., ...>>` - │ found enum `Result<Result<..., ...>, ...>` - ├ note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.unicode/long-E0308.long-type-hash.txt' + ├ note: expected enum `Option<Result<Option<...>, _>>` + │ found enum `Result<Result<..., _>, _>` + ├ note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' ╰ note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types - ╭▸ $DIR/long-E0308.rs:90:9 + ╭▸ $DIR/long-E0308.rs:92:9 │ LL │ let x: Atype< │ ┌────────────┘ @@ -50,17 +50,17 @@ LL │ │ Atype< ‡ │ LL │ │ i32 LL │ │ > = (); - │ │ │ ━━ expected `Atype<Btype<..., ...>, ...>`, found `()` + │ │ │ ━━ expected `Atype<Btype<Ctype<..., i32>, i32>, i32>`, found `()` │ └─────┤ │ expected due to this │ - ├ note: expected struct `Atype<Btype<..., ...>, ...>` + ├ note: expected struct `Atype<Btype<..., i32>, i32>` │ found unit type `()` - ├ note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.unicode/long-E0308.long-type-hash.txt' + ├ note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' ╰ note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types - ╭▸ $DIR/long-E0308.rs:93:17 + ╭▸ $DIR/long-E0308.rs:95:17 │ LL │ let _: () = Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(… │ ┏━━━━━━━━━━━━┬─━━━┛ @@ -70,11 +70,11 @@ LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok… LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(""))))))) LL │ ┃ )))))))))))))))))))))))))))))) LL │ ┃ )))))))))))))))))))))))); - │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `()`, found `Result<Result<..., ...>, ...>` + │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `()`, found `Result<Result<Result<..., _>, _>, _>` │ ├ note: expected unit type `()` - │ found enum `Result<Result<..., ...>, ...>` - ├ note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/long-E0308.unicode/long-E0308.long-type-hash.txt' + │ found enum `Result<Result<..., _>, _>` + ├ note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' ╰ note: consider using `--verbose` to print the full type name to the console error: aborting due to 4 previous errors diff --git a/tests/ui/diagnostic-width/long-e0277.rs b/tests/ui/diagnostic-width/long-e0277.rs new file mode 100644 index 00000000000..9b3bd8bb728 --- /dev/null +++ b/tests/ui/diagnostic-width/long-e0277.rs @@ -0,0 +1,15 @@ +//@ compile-flags: --diagnostic-width=60 -Zwrite-long-types-to-disk=yes +// The regex below normalizes the long type file name to make it suitable for compare-modes. +//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type-\d+.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type-hash.txt'" +type A = (i32, i32, i32, i32); +type B = (A, A, A, A); +type C = (B, B, B, B); +type D = (C, C, C, C); + +trait Trait {} + +fn require_trait<T: Trait>() {} + +fn main() { + require_trait::<D>(); //~ ERROR the trait bound `(... +} diff --git a/tests/ui/diagnostic-width/long-e0277.stderr b/tests/ui/diagnostic-width/long-e0277.stderr new file mode 100644 index 00000000000..a57270df7e2 --- /dev/null +++ b/tests/ui/diagnostic-width/long-e0277.stderr @@ -0,0 +1,23 @@ +error[E0277]: the trait bound `(..., ..., ..., ...): Trait` is not satisfied + --> $DIR/long-e0277.rs:14:21 + | +LL | require_trait::<D>(); + | ^ unsatisfied trait bound + | + = help: the trait `Trait` is not implemented for `(..., ..., ..., ...)` +help: this trait has no implementations, consider adding one + --> $DIR/long-e0277.rs:9:1 + | +LL | trait Trait {} + | ^^^^^^^^^^^ +note: required by a bound in `require_trait` + --> $DIR/long-e0277.rs:11:21 + | +LL | fn require_trait<T: Trait>() {} + | ^^^^^ required by this bound in `require_trait` + = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' + = note: consider using `--verbose` to print the full type name to the console + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic-width/non-copy-type-moved.rs b/tests/ui/diagnostic-width/non-copy-type-moved.rs index a5593ad7b2a..a220c62775e 100644 --- a/tests/ui/diagnostic-width/non-copy-type-moved.rs +++ b/tests/ui/diagnostic-width/non-copy-type-moved.rs @@ -1,5 +1,7 @@ //@ compile-flags: --diagnostic-width=60 -Zwrite-long-types-to-disk=yes -//@ normalize-stderr: "long-type-\d+" -> "long-type-hash" +// The regex below normalizes the long type file name to make it suitable for compare-modes. +//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type-\d+.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type-hash.txt'" + type A = (String, String, String, String); type B = (A, A, A, A); type C = (B, B, B, B); diff --git a/tests/ui/diagnostic-width/non-copy-type-moved.stderr b/tests/ui/diagnostic-width/non-copy-type-moved.stderr index da9385a5b4d..254542c7b39 100644 --- a/tests/ui/diagnostic-width/non-copy-type-moved.stderr +++ b/tests/ui/diagnostic-width/non-copy-type-moved.stderr @@ -1,14 +1,14 @@ error[E0382]: use of moved value: `x` - --> $DIR/non-copy-type-moved.rs:14:14 + --> $DIR/non-copy-type-moved.rs:16:14 | LL | fn foo(x: D) { - | - move occurs because `x` has type `((..., ..., ..., ...), ..., ..., ...)`, which does not implement the `Copy` trait + | - move occurs because `x` has type `(..., ..., ..., ...)`, which does not implement the `Copy` trait LL | let _a = x; | - value moved here LL | let _b = x; | ^ value used here after move | - = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/non-copy-type-moved/non-copy-type-moved.long-type-hash.txt' + = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console help: consider cloning the value if the performance cost is acceptable | diff --git a/tests/ui/diagnostic-width/secondary-label-with-long-type.rs b/tests/ui/diagnostic-width/secondary-label-with-long-type.rs index 6ed600c48ac..c8845af3183 100644 --- a/tests/ui/diagnostic-width/secondary-label-with-long-type.rs +++ b/tests/ui/diagnostic-width/secondary-label-with-long-type.rs @@ -1,5 +1,7 @@ //@ compile-flags: --diagnostic-width=100 -Zwrite-long-types-to-disk=yes -//@ normalize-stderr: "long-type-\d+" -> "long-type-hash" +// The regex below normalizes the long type file name to make it suitable for compare-modes. +//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type-\d+.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type-hash.txt'" + type A = (i32, i32, i32, i32); type B = (A, A, A, A); type C = (B, B, B, B); @@ -10,7 +12,7 @@ fn foo(x: D) { //~^ NOTE this expression has type `((..., //~| NOTE expected `((..., //~| NOTE expected tuple - //~| NOTE the full type name has been written to + //~| NOTE the full name for the type has been written to //~| NOTE consider using `--verbose` to print the full type name to the console } diff --git a/tests/ui/diagnostic-width/secondary-label-with-long-type.stderr b/tests/ui/diagnostic-width/secondary-label-with-long-type.stderr index 1e890455156..a95e1709148 100644 --- a/tests/ui/diagnostic-width/secondary-label-with-long-type.stderr +++ b/tests/ui/diagnostic-width/secondary-label-with-long-type.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/secondary-label-with-long-type.rs:9:9 + --> $DIR/secondary-label-with-long-type.rs:11:9 | LL | let () = x; | ^^ - this expression has type `((..., ..., ..., ...), ..., ..., ...)` @@ -8,7 +8,7 @@ LL | let () = x; | = note: expected tuple `((..., ..., ..., ...), ..., ..., ...)` found unit type `()` - = note: the full type name has been written to '$TEST_BUILD_DIR/diagnostic-width/secondary-label-with-long-type/secondary-label-with-long-type.long-type-hash.txt' + = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console error: aborting due to 1 previous error diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr index 1b76669ccb0..4f685c508c7 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr @@ -16,23 +16,13 @@ LL | where LL | T: AsExpression<Self::SqlType>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check` -error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied - --> $DIR/as_expression.rs:55:15 - | -LL | SelectInt.check("bar"); - | ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str` - | - = help: the trait `AsExpression<Integer>` is not implemented for `&str` - but trait `AsExpression<Text>` is implemented for it - = help: for that trait implementation, expected `Text`, found `Integer` - error[E0271]: type mismatch resolving `<SelectInt as Expression>::SqlType == Text` --> $DIR/as_expression.rs:55:5 | LL | SelectInt.check("bar"); | ^^^^^^^^^^^^^^^^^^^^^^ expected `Text`, found `Integer` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0271, E0277. For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs index 583b3c4675a..48c1ed2b02d 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs @@ -53,7 +53,7 @@ impl<T> Foo for T where T: Expression {} fn main() { SelectInt.check("bar"); - //~^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied - //[next]~| the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied + //[current]~^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied + //[next]~^^ the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied //[next]~| type mismatch } diff --git a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr index 7994ddf11c3..4fee6cc9a22 100644 --- a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr +++ b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr @@ -28,7 +28,7 @@ LL | let _: &Copy + 'static; | = note: the trait is not dyn compatible because it requires `Self: Sized` = note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> error: aborting due to 3 previous errors diff --git a/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr b/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr index f241333f2a7..a384697ee08 100644 --- a/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr +++ b/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr @@ -5,7 +5,7 @@ LL | impl<T, U> Dyn for dyn Foo<T, U> + '_ { | ^^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/almost-supertrait-associated-type.rs:33:34 | LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T> @@ -22,7 +22,7 @@ LL | (&PhantomData::<T> as &dyn Foo<T, U>).transmute(t) | ^^^^^^^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/almost-supertrait-associated-type.rs:33:34 | LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T> @@ -39,7 +39,7 @@ LL | (&PhantomData::<T> as &dyn Foo<T, U>).transmute(t) | ^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/almost-supertrait-associated-type.rs:33:34 | LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T> diff --git a/tests/ui/dyn-compatibility/associated-consts.curr.stderr b/tests/ui/dyn-compatibility/associated-consts.curr.stderr index 45d4f795542..de243938123 100644 --- a/tests/ui/dyn-compatibility/associated-consts.curr.stderr +++ b/tests/ui/dyn-compatibility/associated-consts.curr.stderr @@ -5,7 +5,7 @@ LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar { | ^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/associated-consts.rs:9:11 | LL | trait Bar { @@ -21,7 +21,7 @@ LL | t | ^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/associated-consts.rs:9:11 | LL | trait Bar { diff --git a/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr index 4c8c82196ed..704d833f00b 100644 --- a/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr +++ b/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr @@ -5,7 +5,7 @@ LL | t | ^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/associated-consts.rs:9:11 | LL | trait Bar { diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr index ff5e9fdb6b3..b811ef40c26 100644 --- a/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr +++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr @@ -34,7 +34,7 @@ LL | fn id<F>(f: Copy) -> usize { | = note: the trait is not dyn compatible because it requires `Self: Sized` = note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> error[E0618]: expected function, found `(dyn Copy + 'static)` --> $DIR/avoid-ice-on-warning-2.rs:12:5 diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr index 92a2d340115..d8935be5609 100644 --- a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr +++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr @@ -72,7 +72,7 @@ LL | trait B { fn f(a: A) -> A; } | ^ `A` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/avoid-ice-on-warning-3.rs:14:14 | LL | trait A { fn g(b: B) -> B; } @@ -109,7 +109,7 @@ LL | trait A { fn g(b: B) -> B; } | ^ `B` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/avoid-ice-on-warning-3.rs:4:14 | LL | trait B { fn f(a: A) -> A; } diff --git a/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr index e3ec5b9c3c8..7be6cb0d03b 100644 --- a/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr +++ b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr @@ -23,7 +23,7 @@ LL | fn ord_prefer_dot(s: String) -> Ord { | ^^^ `Ord` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: the trait is not dyn compatible because it uses `Self` as a type parameter diff --git a/tests/ui/dyn-compatibility/bounds.stderr b/tests/ui/dyn-compatibility/bounds.stderr index d45e66b1d5e..5473af388c0 100644 --- a/tests/ui/dyn-compatibility/bounds.stderr +++ b/tests/ui/dyn-compatibility/bounds.stderr @@ -5,7 +5,7 @@ LL | fn f() -> Box<dyn X<U = u32>> { | ^^^^^^^^^^^^^^ `X` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/bounds.rs:4:13 | LL | trait X { diff --git a/tests/ui/dyn-compatibility/gat-incompatible-supertrait.stderr b/tests/ui/dyn-compatibility/gat-incompatible-supertrait.stderr index 04dc0b1d6f4..cfebd5d6947 100644 --- a/tests/ui/dyn-compatibility/gat-incompatible-supertrait.stderr +++ b/tests/ui/dyn-compatibility/gat-incompatible-supertrait.stderr @@ -5,7 +5,7 @@ LL | fn take_dyn(_: &dyn Child) {} | ^^^^^ `Super` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/gat-incompatible-supertrait.rs:10:10 | LL | trait Super { diff --git a/tests/ui/dyn-compatibility/generics.curr.stderr b/tests/ui/dyn-compatibility/generics.curr.stderr index 1607954ab70..d29d02b2ff3 100644 --- a/tests/ui/dyn-compatibility/generics.curr.stderr +++ b/tests/ui/dyn-compatibility/generics.curr.stderr @@ -5,7 +5,7 @@ LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar { | ^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/generics.rs:10:8 | LL | trait Bar { @@ -21,7 +21,7 @@ LL | fn make_bar_explicit<T:Bar>(t: &T) -> &dyn Bar { | ^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/generics.rs:10:8 | LL | trait Bar { @@ -37,7 +37,7 @@ LL | t | ^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/generics.rs:10:8 | LL | trait Bar { @@ -54,7 +54,7 @@ LL | t as &dyn Bar | ^^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/generics.rs:10:8 | LL | trait Bar { @@ -70,7 +70,7 @@ LL | t as &dyn Bar | ^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/generics.rs:10:8 | LL | trait Bar { diff --git a/tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr index 7f31b29b39c..b3565a766fe 100644 --- a/tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr +++ b/tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr @@ -5,7 +5,7 @@ LL | t | ^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/generics.rs:10:8 | LL | trait Bar { @@ -22,7 +22,7 @@ LL | t as &dyn Bar | ^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/generics.rs:10:8 | LL | trait Bar { diff --git a/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr index 1ed78e1e659..bb3f7899bf1 100644 --- a/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr +++ b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr @@ -5,7 +5,7 @@ LL | let test: &mut dyn Bar = &mut thing; | ^^^^^^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/mention-correct-dyn-incompatible-trait.rs:4:8 | LL | fn foo<T>(&self, val: T); @@ -23,7 +23,7 @@ LL | let test: &mut dyn Bar = &mut thing; | ^^^^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/mention-correct-dyn-incompatible-trait.rs:4:8 | LL | fn foo<T>(&self, val: T); diff --git a/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr b/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr index eba2c15dd74..cf3a7b23084 100644 --- a/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr +++ b/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr @@ -5,7 +5,7 @@ LL | elements: Vec<Box<dyn Expr + 'x>>, | ^^^^ `Expr` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/mentions-Self-in-super-predicates.rs:5:21 | LL | trait Expr: Debug + PartialEq { @@ -20,7 +20,7 @@ LL | let a: Box<dyn Expr> = Box::new(SExpr::new()); | ^^^^ `Expr` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/mentions-Self-in-super-predicates.rs:5:21 | LL | trait Expr: Debug + PartialEq { @@ -35,7 +35,7 @@ LL | let b: Box<dyn Expr> = Box::new(SExpr::new()); | ^^^^ `Expr` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/mentions-Self-in-super-predicates.rs:5:21 | LL | trait Expr: Debug + PartialEq { diff --git a/tests/ui/dyn-compatibility/mentions-Self.curr.stderr b/tests/ui/dyn-compatibility/mentions-Self.curr.stderr index 90db86ffef9..2d3fe5ce636 100644 --- a/tests/ui/dyn-compatibility/mentions-Self.curr.stderr +++ b/tests/ui/dyn-compatibility/mentions-Self.curr.stderr @@ -5,7 +5,7 @@ LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar { | ^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/mentions-Self.rs:11:22 | LL | trait Bar { @@ -21,7 +21,7 @@ LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz { | ^^^^^^^ `Baz` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/mentions-Self.rs:15:22 | LL | trait Baz { @@ -37,7 +37,7 @@ LL | t | ^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/mentions-Self.rs:11:22 | LL | trait Bar { @@ -54,7 +54,7 @@ LL | t | ^ `Baz` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/mentions-Self.rs:15:22 | LL | trait Baz { diff --git a/tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr index 4a50d3f07e4..91c26a86025 100644 --- a/tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr +++ b/tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr @@ -5,7 +5,7 @@ LL | t | ^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/mentions-Self.rs:11:22 | LL | trait Bar { @@ -22,7 +22,7 @@ LL | t | ^ `Baz` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/mentions-Self.rs:15:22 | LL | trait Baz { diff --git a/tests/ui/dyn-compatibility/missing-assoc-type.stderr b/tests/ui/dyn-compatibility/missing-assoc-type.stderr index 3f550494b33..5a7560682f2 100644 --- a/tests/ui/dyn-compatibility/missing-assoc-type.stderr +++ b/tests/ui/dyn-compatibility/missing-assoc-type.stderr @@ -5,7 +5,7 @@ LL | fn bar(x: &dyn Foo) {} | ^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/missing-assoc-type.rs:2:10 | LL | trait Foo { diff --git a/tests/ui/dyn-compatibility/no-static.curr.stderr b/tests/ui/dyn-compatibility/no-static.curr.stderr index 867c485053d..bf9b48e7a43 100644 --- a/tests/ui/dyn-compatibility/no-static.curr.stderr +++ b/tests/ui/dyn-compatibility/no-static.curr.stderr @@ -5,7 +5,7 @@ LL | fn diverges() -> Box<dyn Foo> { | ^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/no-static.rs:9:8 | LL | trait Foo { @@ -29,7 +29,7 @@ LL | let b: Box<dyn Foo> = Box::new(Bar); | ^^^^^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/no-static.rs:9:8 | LL | trait Foo { @@ -53,7 +53,7 @@ LL | let b: Box<dyn Foo> = Box::new(Bar); | ^^^^^^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/no-static.rs:9:8 | LL | trait Foo { diff --git a/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr index 65608a9cca7..d5ad4510334 100644 --- a/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr +++ b/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr @@ -5,7 +5,7 @@ LL | let b: Box<dyn Foo> = Box::new(Bar); | ^^^^^^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/no-static.rs:9:8 | LL | trait Foo { diff --git a/tests/ui/dyn-compatibility/sized-2.curr.stderr b/tests/ui/dyn-compatibility/sized-2.curr.stderr index c8fd1056237..2d262072d5d 100644 --- a/tests/ui/dyn-compatibility/sized-2.curr.stderr +++ b/tests/ui/dyn-compatibility/sized-2.curr.stderr @@ -5,7 +5,7 @@ LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar { | ^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/sized-2.rs:9:18 | LL | trait Bar @@ -20,7 +20,7 @@ LL | t | ^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/sized-2.rs:9:18 | LL | trait Bar diff --git a/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr index 477dacdf5a1..1fbc10c0c3f 100644 --- a/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr +++ b/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr @@ -5,7 +5,7 @@ LL | t | ^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/sized-2.rs:9:18 | LL | trait Bar diff --git a/tests/ui/dyn-compatibility/sized.curr.stderr b/tests/ui/dyn-compatibility/sized.curr.stderr index d86ea9197b9..a197d967005 100644 --- a/tests/ui/dyn-compatibility/sized.curr.stderr +++ b/tests/ui/dyn-compatibility/sized.curr.stderr @@ -5,7 +5,7 @@ LL | fn make_bar<T: Bar>(t: &T) -> &dyn Bar { | ^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/sized.rs:8:12 | LL | trait Bar: Sized { @@ -20,7 +20,7 @@ LL | t | ^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/sized.rs:8:12 | LL | trait Bar: Sized { diff --git a/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr index b763173594b..350c8992c6f 100644 --- a/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr +++ b/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr @@ -5,7 +5,7 @@ LL | t | ^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/sized.rs:8:12 | LL | trait Bar: Sized { diff --git a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr index f5dea256469..8e139ee6b48 100644 --- a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr +++ b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr @@ -27,7 +27,7 @@ LL | fn c(&self) -> dyn SuperTrait<T>; | ^^^^^^^^^^^^^^^^^ `SuperTrait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/supertrait-mentions-GAT.rs:4:10 | LL | type Gat<'a> diff --git a/tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr b/tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr index f9ef0c9b2e0..a763649e9c6 100644 --- a/tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr +++ b/tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr @@ -25,7 +25,7 @@ LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz { | ^^^ `Baz` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/supertrait-mentions-Self.rs:8:13 | LL | trait Baz : Bar<Self> { diff --git a/tests/ui/dyn-compatibility/taint-const-eval.curr.stderr b/tests/ui/dyn-compatibility/taint-const-eval.curr.stderr index 8442314835e..7e80a1d2e42 100644 --- a/tests/ui/dyn-compatibility/taint-const-eval.curr.stderr +++ b/tests/ui/dyn-compatibility/taint-const-eval.curr.stderr @@ -5,7 +5,7 @@ LL | static FOO: &(dyn Qux + Sync) = "desc"; | ^^^^^^^^^^^^^^ `Qux` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/taint-const-eval.rs:8:8 | LL | trait Qux { @@ -28,7 +28,7 @@ LL | static FOO: &(dyn Qux + Sync) = "desc"; | ^^^^^^ `Qux` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/taint-const-eval.rs:8:8 | LL | trait Qux { @@ -52,7 +52,7 @@ LL | static FOO: &(dyn Qux + Sync) = "desc"; | ^^^^^^^^^^^^^^ `Qux` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/taint-const-eval.rs:8:8 | LL | trait Qux { diff --git a/tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr index 1c51df8501f..0bc7d0b14d3 100644 --- a/tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr +++ b/tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr @@ -5,7 +5,7 @@ LL | static FOO: &(dyn Qux + Sync) = "desc"; | ^^^^^^ `Qux` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/taint-const-eval.rs:8:8 | LL | trait Qux { diff --git a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr index 45a924008c7..1299167159e 100644 --- a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr +++ b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr @@ -8,7 +8,7 @@ LL | fn fetcher() -> Box<dyn Fetcher> { | ^^^^^^^^^^^ `Fetcher` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:22 | LL | pub trait Fetcher: Send + Sync { @@ -26,7 +26,7 @@ LL | let fetcher = fetcher(); | ^^^^^^^^^ `Fetcher` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:22 | LL | pub trait Fetcher: Send + Sync { @@ -44,7 +44,7 @@ LL | let _ = fetcher.get(); | ^^^^^^^^^^^^^ `Fetcher` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:22 | LL | pub trait Fetcher: Send + Sync { diff --git a/tests/ui/error-codes/E0038.stderr b/tests/ui/error-codes/E0038.stderr index 59e9f504d17..63a5249a386 100644 --- a/tests/ui/error-codes/E0038.stderr +++ b/tests/ui/error-codes/E0038.stderr @@ -5,7 +5,7 @@ LL | fn call_foo(x: Box<dyn Trait>) { | ^^^^^^^^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/E0038.rs:2:22 | LL | trait Trait { @@ -21,7 +21,7 @@ LL | let y = x.foo(); | ^^^^^^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/E0038.rs:2:22 | LL | trait Trait { diff --git a/tests/ui/error-codes/E0789.rs b/tests/ui/error-codes/E0789.rs index 3acc983edc4..08471e1b3f3 100644 --- a/tests/ui/error-codes/E0789.rs +++ b/tests/ui/error-codes/E0789.rs @@ -4,7 +4,7 @@ #![feature(staged_api)] #![unstable(feature = "foo_module", reason = "...", issue = "123")] -#[rustc_allowed_through_unstable_modules] +#[rustc_allowed_through_unstable_modules = "use stable path instead"] // #[stable(feature = "foo", since = "1.0")] struct Foo; //~^ ERROR `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute diff --git a/tests/ui/error-emitter/E0308-clarification.rs b/tests/ui/error-emitter/E0308-clarification.rs new file mode 100644 index 00000000000..4c15ede0041 --- /dev/null +++ b/tests/ui/error-emitter/E0308-clarification.rs @@ -0,0 +1,16 @@ +//@ compile-flags: -Zunstable-options --error-format=human-unicode --color=always +//@ only-linux +// Ensure that when we have a type error where both types have the same textual representation, the +// diagnostic machinery highlights the clarifying comment that comes after in parentheses. +trait Foo: Copy + ToString {} + +impl<T: Copy + ToString> Foo for T {} + +fn hide<T: Foo>(x: T) -> impl Foo { + x +} + +fn main() { + let mut x = (hide(0_u32), hide(0_i32)); + x = (x.1, x.0); +} diff --git a/tests/ui/error-emitter/E0308-clarification.svg b/tests/ui/error-emitter/E0308-clarification.svg new file mode 100644 index 00000000000..9432e3a4ee9 --- /dev/null +++ b/tests/ui/error-emitter/E0308-clarification.svg @@ -0,0 +1,97 @@ +<svg width="740px" height="668px" xmlns="http://www.w3.org/2000/svg"> + <style> + .fg { fill: #AAAAAA } + .bg { background: #000000 } + .fg-ansi256-009 { fill: #FF5555 } + .fg-ansi256-012 { fill: #5555FF } + .fg-magenta { fill: #AA00AA } + .container { + padding: 0 10px; + line-height: 18px; + } + .bold { font-weight: bold; } + tspan { + font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace; + white-space: pre; + line-height: 18px; + } + </style> + + <rect width="100%" height="100%" y="0" rx="4.5" class="bg" /> + + <text xml:space="preserve" class="container fg"> + <tspan x="10px" y="28px"><tspan class="fg-ansi256-009 bold">error[E0308]</tspan><tspan class="bold">: mismatched types</tspan> +</tspan> + <tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-ansi256-012 bold"> ╭▸ </tspan><tspan>$DIR/E0308-clarification.rs:15:10</tspan> +</tspan> + <tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan> +</tspan> + <tspan x="10px" y="82px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> fn hide<T: Foo>(x: T) -> impl Foo {</tspan> +</tspan> + <tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">┬───────</tspan> +</tspan> + <tspan x="10px" y="118px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan> +</tspan> + <tspan x="10px" y="136px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">the expected opaque type</tspan> +</tspan> + <tspan x="10px" y="154px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">the found opaque type</tspan> +</tspan> + <tspan x="10px" y="172px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">‡</tspan> +</tspan> + <tspan x="10px" y="190px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> x = (x.1, x.0);</tspan> +</tspan> + <tspan x="10px" y="208px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">━━━</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">expected `u32`, found `i32`</tspan> +</tspan> + <tspan x="10px" y="226px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan> +</tspan> + <tspan x="10px" y="244px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">├ </tspan><tspan class="bold">note</tspan><tspan>: expected opaque type `</tspan><tspan class="fg-magenta bold">impl Foo</tspan><tspan>` (</tspan><tspan class="fg-magenta bold">`u32`</tspan><tspan>)</tspan> +</tspan> + <tspan x="10px" y="262px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> found opaque type `</tspan><tspan class="fg-magenta bold">impl Foo</tspan><tspan>` (</tspan><tspan class="fg-magenta bold">`i32`</tspan><tspan>)</tspan> +</tspan> + <tspan x="10px" y="280px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">╰ </tspan><tspan class="bold">note</tspan><tspan>: distinct uses of `impl Trait` result in different opaque types</tspan> +</tspan> + <tspan x="10px" y="298px"> +</tspan> + <tspan x="10px" y="316px"><tspan class="fg-ansi256-009 bold">error[E0308]</tspan><tspan class="bold">: mismatched types</tspan> +</tspan> + <tspan x="10px" y="334px"><tspan> </tspan><tspan class="fg-ansi256-012 bold"> ╭▸ </tspan><tspan>$DIR/E0308-clarification.rs:15:15</tspan> +</tspan> + <tspan x="10px" y="352px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan> +</tspan> + <tspan x="10px" y="370px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> fn hide<T: Foo>(x: T) -> impl Foo {</tspan> +</tspan> + <tspan x="10px" y="388px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">┬───────</tspan> +</tspan> + <tspan x="10px" y="406px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan> +</tspan> + <tspan x="10px" y="424px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">the expected opaque type</tspan> +</tspan> + <tspan x="10px" y="442px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">the found opaque type</tspan> +</tspan> + <tspan x="10px" y="460px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">‡</tspan> +</tspan> + <tspan x="10px" y="478px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> x = (x.1, x.0);</tspan> +</tspan> + <tspan x="10px" y="496px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">━━━</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">expected `i32`, found `u32`</tspan> +</tspan> + <tspan x="10px" y="514px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan> +</tspan> + <tspan x="10px" y="532px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">├ </tspan><tspan class="bold">note</tspan><tspan>: expected opaque type `</tspan><tspan class="fg-magenta bold">impl Foo</tspan><tspan>` (</tspan><tspan class="fg-magenta bold">`i32`</tspan><tspan>)</tspan> +</tspan> + <tspan x="10px" y="550px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">│</tspan><tspan> found opaque type `</tspan><tspan class="fg-magenta bold">impl Foo</tspan><tspan>` (</tspan><tspan class="fg-magenta bold">`u32`</tspan><tspan>)</tspan> +</tspan> + <tspan x="10px" y="568px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">╰ </tspan><tspan class="bold">note</tspan><tspan>: distinct uses of `impl Trait` result in different opaque types</tspan> +</tspan> + <tspan x="10px" y="586px"> +</tspan> + <tspan x="10px" y="604px"><tspan class="fg-ansi256-009 bold">error</tspan><tspan class="bold">: aborting due to 2 previous errors</tspan> +</tspan> + <tspan x="10px" y="622px"> +</tspan> + <tspan x="10px" y="640px"><tspan class="bold">For more information about this error, try `rustc --explain E0308`.</tspan> +</tspan> + <tspan x="10px" y="658px"> +</tspan> + </text> + +</svg> diff --git a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr index b4de6b66469..ab8c092a826 100644 --- a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr +++ b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr @@ -5,7 +5,7 @@ LL | async fn takes_dyn_trait(x: &dyn Foo) { | ^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14 | LL | trait Foo { @@ -21,7 +21,7 @@ LL | x.bar().await; | ^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14 | LL | trait Foo { @@ -37,7 +37,7 @@ LL | x.bar().await; | ^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14 | LL | trait Foo { diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr index f8fc086c441..6634ce12118 100644 --- a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr +++ b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr @@ -8,7 +8,7 @@ LL | Ptr(Box::new(4)) as Ptr<dyn Trait>; | ^^^^^^^^^^^^^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18 | LL | trait Trait { @@ -27,7 +27,7 @@ LL | Ptr(Box::new(4)) as Ptr<dyn Trait>; | ^^^^^^^^^^^^^^^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18 | LL | trait Trait { diff --git a/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr b/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr index 10540f0219d..2c3edd6e6a5 100644 --- a/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr +++ b/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr @@ -5,7 +5,7 @@ LL | fn takes_dyn_incompatible_ref<T>(obj: &dyn DynIncompatible1) { | ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible1` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:4:25 | LL | trait DynIncompatible1: Sized {} @@ -20,7 +20,7 @@ LL | fn return_dyn_incompatible_ref() -> &'static dyn DynIncompatible2 { | ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible2` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:7:8 | LL | trait DynIncompatible2 { @@ -43,7 +43,7 @@ LL | fn takes_dyn_incompatible_box(obj: Box<dyn DynIncompatible3>) { | ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible3` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:11:8 | LL | trait DynIncompatible3 { @@ -59,7 +59,7 @@ LL | fn return_dyn_incompatible_rc() -> std::rc::Rc<dyn DynIncompatible4> { | ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible4` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:15:22 | LL | trait DynIncompatible4 { @@ -75,7 +75,7 @@ LL | impl Trait for dyn DynIncompatible1 {} | ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible1` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:4:25 | LL | trait DynIncompatible1: Sized {} diff --git a/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.rs b/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.rs deleted file mode 100644 index 71caf43806d..00000000000 --- a/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![crate_type = "lib"] - -// This isn't intended to compile, so it's easiest to just ignore this error. -extern crate rustc_serialize; //~ERROR can't find crate for `rustc_serialize` - -#[derive( - RustcEncodable, - //~^ ERROR use of unstable library feature `rustc_encodable_decodable` - //~^^ WARNING this was previously accepted by the compiler - //~^^^ WARNING use of deprecated macro `RustcEncodable` - RustcDecodable, - //~^ ERROR use of unstable library feature `rustc_encodable_decodable` - //~^^ WARNING this was previously accepted by the compiler - //~^^^ WARNING use of deprecated macro `RustcDecodable` -)] -struct S; diff --git a/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.stderr b/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.stderr deleted file mode 100644 index b949dbb9da2..00000000000 --- a/tests/ui/feature-gates/feature-gate-rustc_encodable_decodable.stderr +++ /dev/null @@ -1,66 +0,0 @@ -error[E0463]: can't find crate for `rustc_serialize` - --> $DIR/feature-gate-rustc_encodable_decodable.rs:4:1 - | -LL | extern crate rustc_serialize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate - | - = help: maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview` - -error: use of unstable library feature `rustc_encodable_decodable`: derive macro for `rustc-serialize`; should not be used in new code - --> $DIR/feature-gate-rustc_encodable_decodable.rs:7:5 - | -LL | RustcEncodable, - | ^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #64266 <https://github.com/rust-lang/rust/issues/64266> - = note: `#[deny(soft_unstable)]` on by default - -warning: use of deprecated macro `RustcEncodable`: rustc-serialize is deprecated and no longer supported - --> $DIR/feature-gate-rustc_encodable_decodable.rs:7:5 - | -LL | RustcEncodable, - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(deprecated)]` on by default - -error: use of unstable library feature `rustc_encodable_decodable`: derive macro for `rustc-serialize`; should not be used in new code - --> $DIR/feature-gate-rustc_encodable_decodable.rs:11:5 - | -LL | RustcDecodable, - | ^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #64266 <https://github.com/rust-lang/rust/issues/64266> - -warning: use of deprecated macro `RustcDecodable`: rustc-serialize is deprecated and no longer supported - --> $DIR/feature-gate-rustc_encodable_decodable.rs:11:5 - | -LL | RustcDecodable, - | ^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors; 2 warnings emitted - -For more information about this error, try `rustc --explain E0463`. -Future incompatibility report: Future breakage diagnostic: -error: use of unstable library feature `rustc_encodable_decodable`: derive macro for `rustc-serialize`; should not be used in new code - --> $DIR/feature-gate-rustc_encodable_decodable.rs:7:5 - | -LL | RustcEncodable, - | ^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #64266 <https://github.com/rust-lang/rust/issues/64266> - = note: `#[deny(soft_unstable)]` on by default - -Future breakage diagnostic: -error: use of unstable library feature `rustc_encodable_decodable`: derive macro for `rustc-serialize`; should not be used in new code - --> $DIR/feature-gate-rustc_encodable_decodable.rs:11:5 - | -LL | RustcDecodable, - | ^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #64266 <https://github.com/rust-lang/rust/issues/64266> - = note: `#[deny(soft_unstable)]` on by default - diff --git a/tests/ui/fn/fn-pointer-mismatch.stderr b/tests/ui/fn/fn-pointer-mismatch.stderr index 9cda11639d0..2aa840911f6 100644 --- a/tests/ui/fn/fn-pointer-mismatch.stderr +++ b/tests/ui/fn/fn-pointer-mismatch.stderr @@ -67,7 +67,7 @@ LL | let d: &fn(u32) -> u32 = foo; help: consider using a reference | LL | let d: &fn(u32) -> u32 = &foo; - | ~~~~ + | + error[E0308]: mismatched types --> $DIR/fn-pointer-mismatch.rs:48:30 diff --git a/tests/ui/force-inlining/cast.stderr b/tests/ui/force-inlining/cast.stderr index 116919e5fe7..53132959659 100644 --- a/tests/ui/force-inlining/cast.stderr +++ b/tests/ui/force-inlining/cast.stderr @@ -12,7 +12,7 @@ LL | let _: fn(isize) -> usize = callee; help: consider casting to a fn pointer | LL | let _: fn(isize) -> usize = callee as fn(isize) -> usize; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | +++++++++++++++++++++ error[E0605]: non-primitive cast: `fn(isize) -> usize {callee}` as `fn(isize) -> usize` --> $DIR/cast.rs:15:13 @@ -32,7 +32,7 @@ LL | callee, help: consider casting to a fn pointer | LL | callee as fn(isize) -> usize, - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | +++++++++++++++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr b/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr index 4c5a47e73c6..c9b46de5c33 100644 --- a/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr +++ b/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr @@ -43,7 +43,7 @@ LL | fn _f(arg : Box<dyn for<'a> X<Y<'x> = &'a [u32]>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:2:8 | LL | trait X { diff --git a/tests/ui/generic-associated-types/gat-in-trait-path.stderr b/tests/ui/generic-associated-types/gat-in-trait-path.stderr index df79556c825..e57f6b48401 100644 --- a/tests/ui/generic-associated-types/gat-in-trait-path.stderr +++ b/tests/ui/generic-associated-types/gat-in-trait-path.stderr @@ -5,7 +5,7 @@ LL | fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/gat-in-trait-path.rs:6:10 | LL | trait Foo { @@ -21,7 +21,7 @@ LL | f(Box::new(foo)); | ^^^^^^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/gat-in-trait-path.rs:6:10 | LL | trait Foo { @@ -37,7 +37,7 @@ LL | f(Box::new(foo)); | ^^^^^^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/gat-in-trait-path.rs:6:10 | LL | trait Foo { diff --git a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr index 499ce8e4a32..52fed354edf 100644 --- a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr +++ b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr @@ -130,7 +130,7 @@ LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {} | ^^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/gat-trait-path-parenthesised-args.rs:2:8 | LL | trait X { @@ -196,7 +196,7 @@ LL | fn bar<'a>(arg: Box<dyn X<Y() = ()>>) {} | ^^^^^^^^^^^^^^^ `X` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/gat-trait-path-parenthesised-args.rs:2:8 | LL | trait X { diff --git a/tests/ui/generic-associated-types/issue-67510-pass.stderr b/tests/ui/generic-associated-types/issue-67510-pass.stderr index f6846f833fe..4b56c4ef35f 100644 --- a/tests/ui/generic-associated-types/issue-67510-pass.stderr +++ b/tests/ui/generic-associated-types/issue-67510-pass.stderr @@ -5,7 +5,7 @@ LL | fn _func1<'a>(_x: Box<dyn X<Y<'a>=&'a ()>>) {} | ^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-67510-pass.rs:4:10 | LL | trait X { diff --git a/tests/ui/generic-associated-types/issue-67510.stderr b/tests/ui/generic-associated-types/issue-67510.stderr index e8555a7aa1f..f5c494788ea 100644 --- a/tests/ui/generic-associated-types/issue-67510.stderr +++ b/tests/ui/generic-associated-types/issue-67510.stderr @@ -36,7 +36,7 @@ LL | fn f(x: Box<dyn X<Y<'a> = &'a ()>>) {} | ^^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-67510.rs:2:10 | LL | trait X { diff --git a/tests/ui/generic-associated-types/issue-71176.stderr b/tests/ui/generic-associated-types/issue-71176.stderr index a78151384d4..56439f6dfea 100644 --- a/tests/ui/generic-associated-types/issue-71176.stderr +++ b/tests/ui/generic-associated-types/issue-71176.stderr @@ -55,7 +55,7 @@ LL | inner: Box<dyn Provider<A = B>>, | ^^^^^^^^^^^^^^^^^^^ `Provider` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-71176.rs:2:10 | LL | trait Provider { @@ -72,7 +72,7 @@ LL | inner: Box::new(()), | ^^^^^^^^^^^^ `Provider` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-71176.rs:2:10 | LL | trait Provider { @@ -89,7 +89,7 @@ LL | inner: Box::new(()), | ^^^^^^^^^^^^ `Provider` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-71176.rs:2:10 | LL | trait Provider { diff --git a/tests/ui/generic-associated-types/issue-76535.stderr b/tests/ui/generic-associated-types/issue-76535.stderr index 6b7c3bfe731..b828234afa1 100644 --- a/tests/ui/generic-associated-types/issue-76535.stderr +++ b/tests/ui/generic-associated-types/issue-76535.stderr @@ -21,7 +21,7 @@ LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruc | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-76535.rs:4:10 | LL | pub trait SuperTrait { @@ -39,7 +39,7 @@ LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruc | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-76535.rs:4:10 | LL | pub trait SuperTrait { diff --git a/tests/ui/generic-associated-types/issue-78671.stderr b/tests/ui/generic-associated-types/issue-78671.stderr index c85e97067cb..c6da137672d 100644 --- a/tests/ui/generic-associated-types/issue-78671.stderr +++ b/tests/ui/generic-associated-types/issue-78671.stderr @@ -21,7 +21,7 @@ LL | Box::new(Family) as &dyn CollectionFamily<Member=usize> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CollectionFamily` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-78671.rs:2:10 | LL | trait CollectionFamily { diff --git a/tests/ui/generic-associated-types/issue-79422.stderr b/tests/ui/generic-associated-types/issue-79422.stderr index a81217e96c3..6311e4de272 100644 --- a/tests/ui/generic-associated-types/issue-79422.stderr +++ b/tests/ui/generic-associated-types/issue-79422.stderr @@ -21,7 +21,7 @@ LL | as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-79422.rs:18:10 | LL | trait MapLike<K, V> { @@ -37,7 +37,7 @@ LL | let m = Box::new(std::collections::BTreeMap::<u8, u8>::new()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-79422.rs:18:10 | LL | trait MapLike<K, V> { diff --git a/tests/ui/generic-associated-types/issue-90014-tait2.rs b/tests/ui/generic-associated-types/issue-90014-tait2.rs index ef54a89aaae..3f7a9ff63c3 100644 --- a/tests/ui/generic-associated-types/issue-90014-tait2.rs +++ b/tests/ui/generic-associated-types/issue-90014-tait2.rs @@ -3,8 +3,6 @@ //! Unfortunately we don't even reach opaque type collection, as we ICE in typeck before that. //! See #109281 for the original report. //@ edition:2018 -//@ error-pattern: expected generic lifetime parameter, found `'a` - #![feature(type_alias_impl_trait)] use std::future::Future; @@ -24,6 +22,7 @@ impl<'x, T: 'x> Trait<'x> for (T,) { impl Foo<'_> { fn make_fut(&self) -> Box<dyn for<'a> Trait<'a, Thing = Fut<'a>>> { Box::new((async { () },)) + //~^ ERROR expected generic lifetime parameter, found `'a` } } diff --git a/tests/ui/generic-associated-types/issue-90014-tait2.stderr b/tests/ui/generic-associated-types/issue-90014-tait2.stderr index be6f4272ce1..aa427d42649 100644 --- a/tests/ui/generic-associated-types/issue-90014-tait2.stderr +++ b/tests/ui/generic-associated-types/issue-90014-tait2.stderr @@ -1,5 +1,5 @@ error[E0792]: expected generic lifetime parameter, found `'a` - --> $DIR/issue-90014-tait2.rs:26:9 + --> $DIR/issue-90014-tait2.rs:24:9 | LL | type Fut<'a> = impl Future<Output = ()>; | -- this generic parameter must be used with a generic lifetime parameter diff --git a/tests/ui/generic-associated-types/missing_lifetime_args.stderr b/tests/ui/generic-associated-types/missing_lifetime_args.stderr index 6b8df5cc12f..7b6888817f4 100644 --- a/tests/ui/generic-associated-types/missing_lifetime_args.stderr +++ b/tests/ui/generic-associated-types/missing_lifetime_args.stderr @@ -55,7 +55,7 @@ LL | fn foo<'c, 'd>(_arg: Box<dyn X<Y = (&'c u32, &'d u32)>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/missing_lifetime_args.rs:2:10 | LL | trait X { diff --git a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr index 5c9e9dbe3d7..45bca1a7628 100644 --- a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr +++ b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr @@ -99,7 +99,7 @@ LL | fn f2<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {} | ^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/trait-path-type-error-once-implemented.rs:2:10 | LL | trait X { diff --git a/tests/ui/generic-associated-types/trait-objects.stderr b/tests/ui/generic-associated-types/trait-objects.stderr index 56a1cb1906f..7d95718ec87 100644 --- a/tests/ui/generic-associated-types/trait-objects.stderr +++ b/tests/ui/generic-associated-types/trait-objects.stderr @@ -5,7 +5,7 @@ LL | fn min_size(x: &mut dyn for<'a> StreamingIterator<Item<'a> = &'a i32>) -> u | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/trait-objects.rs:2:10 | LL | trait StreamingIterator { @@ -21,7 +21,7 @@ LL | x.size_hint().0 | ^^^^^^^^^ `StreamingIterator` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/trait-objects.rs:2:10 | LL | trait StreamingIterator { @@ -37,7 +37,7 @@ LL | x.size_hint().0 | ^^^^^^^^^^^^^ `StreamingIterator` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/trait-objects.rs:2:10 | LL | trait StreamingIterator { diff --git a/tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.stderr b/tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.stderr index 67417a5e525..be2eca3e61a 100644 --- a/tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.stderr @@ -11,7 +11,7 @@ LL | | ), LL | | ) { | |_- expected `&dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn Fn(u32) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a))` because of return type LL | f - | ^ expected `&dyn Fn(&dyn Fn(&dyn Fn(&...)))`, found `&dyn Fn(u32)` + | ^ expected `&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&...))))`, found `&dyn Fn(u32)` | = note: expected reference `&dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn Fn(u32) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a))` found reference `&dyn Fn(u32)` diff --git a/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs b/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs index e70f6fc3430..c8963e078f0 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs @@ -36,12 +36,10 @@ trait Ty<'a> { fn main() { let v = Unit2.m( - L { - //~^ ERROR to be a closure that returns `Unit3`, but it returns `Unit4` - //~| ERROR type mismatch + L { //~ ERROR type mismatch f: |x| { drop(x); - Unit4 + Unit4 //~ ERROR to return `Unit3`, but it returns `Unit4` }, }, ); diff --git a/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr b/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr index 74610b55dc3..4302570cdbd 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr @@ -1,16 +1,15 @@ -error[E0271]: type mismatch resolving `<L<{closure@issue-62203-hrtb-ice.rs:42:16}> as T0<'r, (&u8,)>>::O == <_ as Ty<'r>>::V` +error[E0271]: type mismatch resolving `<L<{closure@issue-62203-hrtb-ice.rs:40:16}> as T0<'r, (&u8,)>>::O == <_ as Ty<'r>>::V` --> $DIR/issue-62203-hrtb-ice.rs:39:9 | LL | let v = Unit2.m( | - required by a bound introduced by this call LL | / L { -LL | | -LL | | LL | | f: |x| { -... | +LL | | drop(x); +LL | | Unit4 LL | | }, LL | | }, - | |_________^ type mismatch resolving `<L<{closure@issue-62203-hrtb-ice.rs:42:16}> as T0<'r, (&u8,)>>::O == <_ as Ty<'r>>::V` + | |_________^ type mismatch resolving `<L<{closure@issue-62203-hrtb-ice.rs:40:16}> as T0<'r, (&u8,)>>::O == <_ as Ty<'r>>::V` | note: expected this to be `<_ as Ty<'_>>::V` --> $DIR/issue-62203-hrtb-ice.rs:21:14 @@ -30,21 +29,19 @@ LL | where LL | F: for<'r> T0<'r, (<Self as Ty<'r>>::V,), O = <B as Ty<'r>>::V>, | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m` -error[E0271]: expected `{closure@issue-62203-hrtb-ice.rs:42:16}` to be a closure that returns `Unit3`, but it returns `Unit4` - --> $DIR/issue-62203-hrtb-ice.rs:39:9 - | -LL | let v = Unit2.m( - | - required by a bound introduced by this call -LL | / L { -LL | | -LL | | -LL | | f: |x| { -... | -LL | | }, -LL | | }, - | |_________^ expected `Unit3`, found `Unit4` - | -note: required for `L<{closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19}>` to implement `for<'r> T0<'r, (&'r u8,)>` +error[E0271]: expected `{closure@issue-62203-hrtb-ice.rs:40:16}` to return `Unit3`, but it returns `Unit4` + --> $DIR/issue-62203-hrtb-ice.rs:42:17 + | +LL | let v = Unit2.m( + | - required by a bound introduced by this call +LL | L { +LL | f: |x| { + | --- this closure +LL | drop(x); +LL | Unit4 + | ^^^^^ expected `Unit3`, found `Unit4` + | +note: required for `L<{closure@$DIR/issue-62203-hrtb-ice.rs:40:16: 40:19}>` to implement `for<'r> T0<'r, (&'r u8,)>` --> $DIR/issue-62203-hrtb-ice.rs:17:16 | LL | impl<'a, A, T> T0<'a, A> for L<T> diff --git a/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr index fc3d9c2171d..183ee678d7a 100644 --- a/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr +++ b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr @@ -5,7 +5,7 @@ LL | let x: &dyn Foo = &(); | ^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/span-bug-issue-121597.rs:4:12 | LL | trait Foo: for<T> Bar<T> {} @@ -21,7 +21,7 @@ LL | let x: &dyn Foo = &(); | ^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/span-bug-issue-121597.rs:4:12 | LL | trait Foo: for<T> Bar<T> {} diff --git a/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr index 4abd7bcf31c..2869702d7fc 100644 --- a/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr +++ b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr @@ -5,7 +5,7 @@ LL | fn car() -> dyn DynIncompatible { | ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8 | LL | trait DynIncompatible { @@ -33,7 +33,7 @@ LL | fn cat() -> Box<dyn DynIncompatible> { | ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8 | LL | trait DynIncompatible { @@ -78,7 +78,7 @@ LL | return Box::new(A); | ^^^^^^^^^^^ `DynIncompatible` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8 | LL | trait DynIncompatible { @@ -107,7 +107,7 @@ LL | Box::new(B) | ^^^^^^^^^^^ `DynIncompatible` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8 | LL | trait DynIncompatible { diff --git a/tests/ui/impl-trait/impl-trait-in-macro.stderr b/tests/ui/impl-trait/impl-trait-in-macro.stderr index 4380f47c5de..2f934694f83 100644 --- a/tests/ui/impl-trait/impl-trait-in-macro.stderr +++ b/tests/ui/impl-trait/impl-trait-in-macro.stderr @@ -12,8 +12,8 @@ LL | let mut a = x; LL | a = y; | ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug` | - = note: expected type parameter `impl Debug` (type parameter `impl Debug`) - found type parameter `impl Debug` (type parameter `impl Debug`) + = note: expected type parameter `impl Debug` + found type parameter `impl Debug` = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters diff --git a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr index 1cfc2a6d944..a95670ced86 100644 --- a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr +++ b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr @@ -18,6 +18,11 @@ help: this trait has no implementations, consider adding one | LL | trait Foo {} | ^^^^^^^^^ +note: required by a bound in `A` + --> $DIR/alias-bounds-when-not-wf.rs:8:11 + | +LL | type A<T: Foo> = T; + | ^^^ required by this bound in `A` error[E0277]: the trait bound `usize: Foo` is not satisfied --> $DIR/alias-bounds-when-not-wf.rs:16:10 diff --git a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr index 44ca09150fe..61fe9432a1e 100644 --- a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr +++ b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr @@ -15,7 +15,7 @@ LL | MyTrait::foo(&self) | ^^^^^^^^^^^^ `MyTrait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:5:22 | LL | trait MyTrait { @@ -40,7 +40,7 @@ LL | impl dyn MyTrait { | ^^^^^^^^^^^ `MyTrait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:5:22 | LL | trait MyTrait { @@ -57,7 +57,7 @@ LL | fn other(&self) -> impl Marker { | ^^^^ `MyTrait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:5:22 | LL | trait MyTrait { diff --git a/tests/ui/impl-trait/in-trait/dont-consider-unconstrained-rpitits.rs b/tests/ui/impl-trait/in-trait/dont-consider-unconstrained-rpitits.rs new file mode 100644 index 00000000000..fe73306966e --- /dev/null +++ b/tests/ui/impl-trait/in-trait/dont-consider-unconstrained-rpitits.rs @@ -0,0 +1,14 @@ +// There's a suggestion that turns `Iterator<u32>` into `Iterator<Item = u32>` +// if we have more generics than the trait wants. Let's not consider RPITITs +// for this, since that makes no sense right now. + +trait Foo { + fn bar(self) -> impl Sized; +} + +impl Foo<u8> for () { + //~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied + fn bar(self) -> impl Sized {} +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/dont-consider-unconstrained-rpitits.stderr b/tests/ui/impl-trait/in-trait/dont-consider-unconstrained-rpitits.stderr new file mode 100644 index 00000000000..fb497b89c5f --- /dev/null +++ b/tests/ui/impl-trait/in-trait/dont-consider-unconstrained-rpitits.stderr @@ -0,0 +1,17 @@ +error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/dont-consider-unconstrained-rpitits.rs:9:6 + | +LL | impl Foo<u8> for () { + | ^^^---- help: remove the unnecessary generics + | | + | expected 0 generic arguments + | +note: trait defined here, with 0 generic parameters + --> $DIR/dont-consider-unconstrained-rpitits.rs:5:7 + | +LL | trait Foo { + | ^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr b/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr index 87a5480b1e3..840c27e183f 100644 --- a/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr +++ b/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr @@ -5,7 +5,7 @@ LL | let i = Box::new(42_u32) as Box<dyn Foo>; | ^^^^^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/dyn-compatibility.rs:4:22 | LL | trait Foo { @@ -22,7 +22,7 @@ LL | let s = i.baz(); | ^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/dyn-compatibility.rs:4:22 | LL | trait Foo { @@ -39,7 +39,7 @@ LL | let s = i.baz(); | ^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/dyn-compatibility.rs:4:22 | LL | trait Foo { @@ -56,7 +56,7 @@ LL | let i = Box::new(42_u32) as Box<dyn Foo>; | ^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/dyn-compatibility.rs:4:22 | LL | trait Foo { diff --git a/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr b/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr index 07d09468b04..29235ca78a5 100644 --- a/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr +++ b/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr @@ -5,7 +5,7 @@ LL | let _: &dyn rpitit::Foo = todo!(); | ^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/auxiliary/rpitit.rs:4:21 | LL | fn bar(self) -> impl Deref<Target = impl Sized>; diff --git a/tests/ui/impl-trait/universal-two-impl-traits.stderr b/tests/ui/impl-trait/universal-two-impl-traits.stderr index 3b4844ab133..f2f5dd0a0c8 100644 --- a/tests/ui/impl-trait/universal-two-impl-traits.stderr +++ b/tests/ui/impl-trait/universal-two-impl-traits.stderr @@ -10,8 +10,8 @@ LL | let mut a = x; LL | a = y; | ^ expected type parameter `impl Debug`, found a different type parameter `impl Debug` | - = note: expected type parameter `impl Debug` (type parameter `impl Debug`) - found type parameter `impl Debug` (type parameter `impl Debug`) + = note: expected type parameter `impl Debug` + found type parameter `impl Debug` = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters diff --git a/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.rs b/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.rs index e28b8f373da..62fc079d9d9 100644 --- a/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.rs +++ b/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.rs @@ -3,6 +3,9 @@ //@ error-pattern: reached the recursion limit while instantiating //@ error-pattern: reached the recursion limit finding the struct tail +// The regex below normalizes the long type file name to make it suitable for compare-modes. +//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type.txt'" + // Regression test for #114484: This used to ICE during monomorphization, because we treated // `<VirtualWrapper<...> as Pointee>::Metadata` as a rigid projection after reaching the recursion // limit when finding the struct tail. diff --git a/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.stderr b/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.stderr index 7c961b79c0c..b67e000bf74 100644 --- a/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.stderr +++ b/tests/ui/infinite/infinite-instantiation-struct-tail-ice-114484.stderr @@ -18,7 +18,7 @@ error: reached the recursion limit finding the struct tail for `[u8; 256]` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` note: the above error was encountered while instantiating `fn virtualize_my_trait::<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<SomeData<256>, 0>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>>` - --> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:26:18 + --> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:29:18 | LL | unsafe { virtualize_my_trait(L, self) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -43,7 +43,7 @@ error: reached the recursion limit finding the struct tail for `SomeData<256>` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` note: the above error was encountered while instantiating `fn virtualize_my_trait::<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<SomeData<256>, 0>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>>` - --> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:26:18 + --> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:29:18 | LL | unsafe { virtualize_my_trait(L, self) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ error: reached the recursion limit finding the struct tail for `VirtualWrapper<S = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` note: the above error was encountered while instantiating `fn virtualize_my_trait::<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<SomeData<256>, 0>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>>` - --> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:26:18 + --> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:29:18 | LL | unsafe { virtualize_my_trait(L, self) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -76,11 +76,11 @@ LL | unsafe { virtualize_my_trait(L, self) } error: reached the recursion limit while instantiating `<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<VirtualWrapper<..., 1>, 1>, 1>, 1>, 1> as MyTrait>::virtualize` | note: `<VirtualWrapper<T, L> as MyTrait>::virtualize` defined here - --> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:25:5 + --> $DIR/infinite-instantiation-struct-tail-ice-114484.rs:28:5 | LL | fn virtualize(&self) -> &dyn MyTrait { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: the full type name has been written to '$TEST_BUILD_DIR/infinite/infinite-instantiation-struct-tail-ice-114484/infinite-instantiation-struct-tail-ice-114484.long-type.txt' + = note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type.txt' error: aborting due to 13 previous errors diff --git a/tests/ui/infinite/infinite-instantiation.rs b/tests/ui/infinite/infinite-instantiation.rs index 7e1bff6b124..d5cb8e79592 100644 --- a/tests/ui/infinite/infinite-instantiation.rs +++ b/tests/ui/infinite/infinite-instantiation.rs @@ -1,5 +1,6 @@ //@ build-fail -//@ normalize-stderr: ".nll/" -> "/" +// The regex below normalizes the long type file name to make it suitable for compare-modes. +//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type.txt'" trait ToOpt: Sized { fn to_option(&self) -> Option<Self>; diff --git a/tests/ui/infinite/infinite-instantiation.stderr b/tests/ui/infinite/infinite-instantiation.stderr index 43d267fa46b..71c745cf5eb 100644 --- a/tests/ui/infinite/infinite-instantiation.stderr +++ b/tests/ui/infinite/infinite-instantiation.stderr @@ -1,15 +1,15 @@ error: reached the recursion limit while instantiating `function::<Option<Option<Option<Option<Option<...>>>>>>` - --> $DIR/infinite-instantiation.rs:22:9 + --> $DIR/infinite-instantiation.rs:23:9 | LL | function(counter - 1, t.to_option()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `function` defined here - --> $DIR/infinite-instantiation.rs:20:1 + --> $DIR/infinite-instantiation.rs:21:1 | LL | fn function<T:ToOpt + Clone>(counter: usize, t: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: the full type name has been written to '$TEST_BUILD_DIR/infinite/infinite-instantiation/infinite-instantiation.long-type.txt' + = note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type.txt' error: aborting due to 1 previous error diff --git a/tests/ui/intrinsics/const-eval-select-bad.rs b/tests/ui/intrinsics/const-eval-select-bad.rs index 7e75de88d29..3365d57af7c 100644 --- a/tests/ui/intrinsics/const-eval-select-bad.rs +++ b/tests/ui/intrinsics/const-eval-select-bad.rs @@ -30,7 +30,7 @@ fn baz(n: bool) -> i32 { const fn return_ty_mismatch() { const_eval_select((1,), foo, bar); - //~^ ERROR expected `bar` to be a fn item that returns `i32`, but it returns `bool` + //~^ ERROR expected `bar` to return `i32`, but it returns `bool` } const fn args_ty_mismatch() { diff --git a/tests/ui/intrinsics/const-eval-select-bad.stderr b/tests/ui/intrinsics/const-eval-select-bad.stderr index e317ed23ab1..bb159bed282 100644 --- a/tests/ui/intrinsics/const-eval-select-bad.stderr +++ b/tests/ui/intrinsics/const-eval-select-bad.stderr @@ -60,7 +60,7 @@ LL | const_eval_select((), 42, 0xDEADBEEF); = note: expected a function item, found {integer} = help: consult the documentation on `const_eval_select` for more information -error[E0271]: expected `bar` to be a fn item that returns `i32`, but it returns `bool` +error[E0271]: expected `bar` to return `i32`, but it returns `bool` --> $DIR/const-eval-select-bad.rs:32:34 | LL | const_eval_select((1,), foo, bar); diff --git a/tests/ui/issues/issue-18959.stderr b/tests/ui/issues/issue-18959.stderr index 49d501c397f..c37c4177bfc 100644 --- a/tests/ui/issues/issue-18959.stderr +++ b/tests/ui/issues/issue-18959.stderr @@ -5,7 +5,7 @@ LL | fn foo(b: &dyn Bar) { | ^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-18959.rs:1:20 | LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); } @@ -21,7 +21,7 @@ LL | b.foo(&0) | ^^^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-18959.rs:1:20 | LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); } @@ -37,7 +37,7 @@ LL | let test: &dyn Bar = &mut thing; | ^^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-18959.rs:1:20 | LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); } @@ -53,7 +53,7 @@ LL | let test: &dyn Bar = &mut thing; | ^^^^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-18959.rs:1:20 | LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); } @@ -70,7 +70,7 @@ LL | foo(test); | ^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-18959.rs:1:20 | LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); } diff --git a/tests/ui/issues/issue-19380.stderr b/tests/ui/issues/issue-19380.stderr index 7d4812c3693..f8509891d3a 100644 --- a/tests/ui/issues/issue-19380.stderr +++ b/tests/ui/issues/issue-19380.stderr @@ -5,7 +5,7 @@ LL | foos: &'static [&'static (dyn Qiz + 'static)] | ^^^^^^^^^^^^^^^^^ `Qiz` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-19380.rs:2:6 | LL | trait Qiz { @@ -29,7 +29,7 @@ LL | const BAR : Bar = Bar { foos: &[&FOO]}; | ^^^^ `Qiz` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-19380.rs:2:6 | LL | trait Qiz { @@ -54,7 +54,7 @@ LL | const BAR : Bar = Bar { foos: &[&FOO]}; | ^^^^^^^ `Qiz` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-19380.rs:2:6 | LL | trait Qiz { diff --git a/tests/ui/issues/issue-26056.stderr b/tests/ui/issues/issue-26056.stderr index d1cdf43351e..c2168af9496 100644 --- a/tests/ui/issues/issue-26056.stderr +++ b/tests/ui/issues/issue-26056.stderr @@ -5,7 +5,7 @@ LL | as &dyn Map<Key=u32,MapValue=u32>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ `Map` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-26056.rs:9:12 | LL | trait Map: MapLookup<<Self as Map>::Key> { diff --git a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs index edf4f2fce26..ebaf244ac9c 100644 --- a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs +++ b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.rs @@ -1,5 +1,6 @@ //@ build-fail -//@ normalize-stderr: ".nll/" -> "/" +// The regex below normalizes the long type file name to make it suitable for compare-modes. +//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type.txt'" trait Mirror { type Image; diff --git a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr index 84ed97572b3..fbbf80021be 100644 --- a/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr +++ b/tests/ui/issues/issue-37311-type-length-limit/issue-37311.stderr @@ -1,15 +1,15 @@ error: reached the recursion limit while instantiating `<(&(&(..., ...), ...), ...) as Foo>::recurse` - --> $DIR/issue-37311.rs:17:9 + --> $DIR/issue-37311.rs:18:9 | LL | (self, self).recurse(); | ^^^^^^^^^^^^^^^^^^^^^^ | note: `<T as Foo>::recurse` defined here - --> $DIR/issue-37311.rs:16:5 + --> $DIR/issue-37311.rs:17:5 | LL | fn recurse(&self) { | ^^^^^^^^^^^^^^^^^ - = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-37311-type-length-limit/issue-37311/issue-37311.long-type.txt' + = note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type.txt' error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-50781.stderr b/tests/ui/issues/issue-50781.stderr index 293e9839944..88b83a83e0c 100644 --- a/tests/ui/issues/issue-50781.stderr +++ b/tests/ui/issues/issue-50781.stderr @@ -5,7 +5,7 @@ LL | impl Trait for dyn X {} | ^^^^^ `X` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-50781.rs:4:8 | LL | trait X { @@ -22,7 +22,7 @@ LL | <dyn X as X>::foo(&()); | ^^^ `X` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-50781.rs:4:8 | LL | trait X { @@ -40,7 +40,7 @@ LL | <dyn X as X>::foo(&()); | ^^^^^ `X` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-50781.rs:4:8 | LL | trait X { diff --git a/tests/ui/issues/issue-67552.rs b/tests/ui/issues/issue-67552.rs index 343ae4f262f..8c7e95bd2e3 100644 --- a/tests/ui/issues/issue-67552.rs +++ b/tests/ui/issues/issue-67552.rs @@ -1,6 +1,7 @@ //@ build-fail //@ compile-flags: -Copt-level=0 -//@ normalize-stderr: ".nll/" -> "/" +// The regex below normalizes the long type file name to make it suitable for compare-modes. +//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type.txt'" fn main() { rec(Empty); diff --git a/tests/ui/issues/issue-67552.stderr b/tests/ui/issues/issue-67552.stderr index 1a8d7248b45..f94cd78c870 100644 --- a/tests/ui/issues/issue-67552.stderr +++ b/tests/ui/issues/issue-67552.stderr @@ -1,17 +1,17 @@ error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut ...>` - --> $DIR/issue-67552.rs:29:9 + --> $DIR/issue-67552.rs:30:9 | LL | rec(identity(&mut it)) | ^^^^^^^^^^^^^^^^^^^^^^ | note: `rec` defined here - --> $DIR/issue-67552.rs:22:1 + --> $DIR/issue-67552.rs:23:1 | LL | / fn rec<T>(mut it: T) LL | | where LL | | T: Iterator, | |________________^ - = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-67552/issue-67552.long-type.txt' + = note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type.txt' error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-8727.rs b/tests/ui/issues/issue-8727.rs index b824be7c12f..7767729109e 100644 --- a/tests/ui/issues/issue-8727.rs +++ b/tests/ui/issues/issue-8727.rs @@ -2,7 +2,8 @@ // recursions. //@ build-fail -//@ normalize-stderr: ".nll/" -> "/" +// The regex below normalizes the long type file name to make it suitable for compare-modes. +//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type.txt'" fn generic<T>() { //~ WARN function cannot return without recursing generic::<Option<T>>(); diff --git a/tests/ui/issues/issue-8727.stderr b/tests/ui/issues/issue-8727.stderr index 9af598fe43f..22286eb8d7b 100644 --- a/tests/ui/issues/issue-8727.stderr +++ b/tests/ui/issues/issue-8727.stderr @@ -1,5 +1,5 @@ warning: function cannot return without recursing - --> $DIR/issue-8727.rs:7:1 + --> $DIR/issue-8727.rs:8:1 | LL | fn generic<T>() { | ^^^^^^^^^^^^^^^ cannot return without recursing @@ -10,17 +10,17 @@ LL | generic::<Option<T>>(); = note: `#[warn(unconditional_recursion)]` on by default error: reached the recursion limit while instantiating `generic::<Option<Option<Option<Option<Option<...>>>>>>` - --> $DIR/issue-8727.rs:8:5 + --> $DIR/issue-8727.rs:9:5 | LL | generic::<Option<T>>(); | ^^^^^^^^^^^^^^^^^^^^^^ | note: `generic` defined here - --> $DIR/issue-8727.rs:7:1 + --> $DIR/issue-8727.rs:8:1 | LL | fn generic<T>() { | ^^^^^^^^^^^^^^^ - = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-8727/issue-8727.long-type.txt' + = note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type.txt' error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr index 83446fc9ec0..95048c4454b 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr +++ b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr @@ -26,7 +26,7 @@ LL | let z = &x as &dyn Foo; | ^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/kindck-inherited-copy-bound.rs:10:13 | LL | trait Foo : Copy { @@ -41,7 +41,7 @@ LL | let z = &x as &dyn Foo; | ^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/kindck-inherited-copy-bound.rs:10:13 | LL | trait Foo : Copy { diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr index 271e5afb9e7..296f011193e 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr +++ b/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr @@ -26,7 +26,7 @@ LL | let z = &x as &dyn Foo; | ^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/kindck-inherited-copy-bound.rs:10:13 | LL | trait Foo : Copy { diff --git a/tests/ui/lazy-type-alias/def-site-param-defaults-wf.rs b/tests/ui/lazy-type-alias/def-site-param-defaults-wf.rs new file mode 100644 index 00000000000..90bb0a294f8 --- /dev/null +++ b/tests/ui/lazy-type-alias/def-site-param-defaults-wf.rs @@ -0,0 +1,9 @@ +//! Ensure that we check generic parameter defaults for well-formedness at the definition site. +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +type Alias<T = Vec<str>, const N: usize = {0 - 1}> = T; +//~^ ERROR evaluation of constant value failed +//~| ERROR the size for values of type `str` cannot be known at compilation time + +fn main() {} diff --git a/tests/ui/lazy-type-alias/def-site-param-defaults-wf.stderr b/tests/ui/lazy-type-alias/def-site-param-defaults-wf.stderr new file mode 100644 index 00000000000..da0021ccaf4 --- /dev/null +++ b/tests/ui/lazy-type-alias/def-site-param-defaults-wf.stderr @@ -0,0 +1,20 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/def-site-param-defaults-wf.rs:5:44 + | +LL | type Alias<T = Vec<str>, const N: usize = {0 - 1}> = T; + | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/def-site-param-defaults-wf.rs:5:16 + | +LL | type Alias<T = Vec<str>, const N: usize = {0 - 1}> = T; + | ^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` +note: required by an implicit `Sized` bound in `Vec` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0080, E0277. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/lazy-type-alias/def-site-predicates-wf.rs b/tests/ui/lazy-type-alias/def-site-predicates-wf.rs new file mode 100644 index 00000000000..5d9235347cb --- /dev/null +++ b/tests/ui/lazy-type-alias/def-site-predicates-wf.rs @@ -0,0 +1,13 @@ +//! Ensure that we check the predicates at the definition site for well-formedness. +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +type Alias0 = () +where + Vec<str>:; //~ ERROR the size for values of type `str` cannot be known at compilation time + +type Alias1 = () +where + Vec<str>: Sized; //~ ERROR the size for values of type `str` cannot be known at compilation time + +fn main() {} diff --git a/tests/ui/lazy-type-alias/def-site-predicates-wf.stderr b/tests/ui/lazy-type-alias/def-site-predicates-wf.stderr new file mode 100644 index 00000000000..b44e702c35c --- /dev/null +++ b/tests/ui/lazy-type-alias/def-site-predicates-wf.stderr @@ -0,0 +1,23 @@ +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/def-site-predicates-wf.rs:7:5 + | +LL | Vec<str>:; + | ^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` +note: required by an implicit `Sized` bound in `Vec` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/def-site-predicates-wf.rs:11:15 + | +LL | Vec<str>: Sized; + | ^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` +note: required by an implicit `Sized` bound in `Vec` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/lint/issue-106991.rs b/tests/ui/lint/issue-106991.rs index e4d7f765b4a..b70f751195a 100644 --- a/tests/ui/lint/issue-106991.rs +++ b/tests/ui/lint/issue-106991.rs @@ -3,7 +3,7 @@ fn foo(items: &mut Vec<u8>) { } fn bar() -> impl Iterator<Item = i32> { - //~^ ERROR expected `foo` to be a fn item that returns `i32`, but it returns `()` [E0271] + //~^ ERROR expected `foo` to return `i32`, but it returns `()` [E0271] let mut x: Vec<Vec<u8>> = vec![vec![0, 2, 1], vec![5, 4, 3]]; x.iter_mut().map(foo) } diff --git a/tests/ui/lint/issue-106991.stderr b/tests/ui/lint/issue-106991.stderr index 0441a6377d0..15e0ba5337f 100644 --- a/tests/ui/lint/issue-106991.stderr +++ b/tests/ui/lint/issue-106991.stderr @@ -1,4 +1,4 @@ -error[E0271]: expected `foo` to be a fn item that returns `i32`, but it returns `()` +error[E0271]: expected `foo` to return `i32`, but it returns `()` --> $DIR/issue-106991.rs:5:13 | LL | fn bar() -> impl Iterator<Item = i32> { diff --git a/tests/ui/liveness/liveness-unused.rs b/tests/ui/liveness/liveness-unused.rs index ba635e6638c..49e7044aeda 100644 --- a/tests/ui/liveness/liveness-unused.rs +++ b/tests/ui/liveness/liveness-unused.rs @@ -2,6 +2,7 @@ #![deny(unused_variables)] #![deny(unused_assignments)] #![allow(dead_code, non_camel_case_types, trivial_numeric_casts, dropping_copy_types)] +#![feature(intrinsics)] use std::ops::AddAssign; @@ -137,5 +138,10 @@ fn f7() { drop(a); } +// unused params warnings are not needed for intrinsic functions without bodies +#[rustc_intrinsic] +unsafe fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U; + + fn main() { } diff --git a/tests/ui/liveness/liveness-unused.stderr b/tests/ui/liveness/liveness-unused.stderr index f6c478ddbc7..a69fc10dff2 100644 --- a/tests/ui/liveness/liveness-unused.stderr +++ b/tests/ui/liveness/liveness-unused.stderr @@ -1,5 +1,5 @@ warning: unreachable statement - --> $DIR/liveness-unused.rs:92:9 + --> $DIR/liveness-unused.rs:93:9 | LL | continue; | -------- any code following this expression is unreachable @@ -14,7 +14,7 @@ LL | #![warn(unused)] = note: `#[warn(unreachable_code)]` implied by `#[warn(unused)]` error: unused variable: `x` - --> $DIR/liveness-unused.rs:8:7 + --> $DIR/liveness-unused.rs:9:7 | LL | fn f1(x: isize) { | ^ help: if this is intentional, prefix it with an underscore: `_x` @@ -26,25 +26,25 @@ LL | #![deny(unused_variables)] | ^^^^^^^^^^^^^^^^ error: unused variable: `x` - --> $DIR/liveness-unused.rs:12:8 + --> $DIR/liveness-unused.rs:13:8 | LL | fn f1b(x: &mut isize) { | ^ help: if this is intentional, prefix it with an underscore: `_x` error: unused variable: `x` - --> $DIR/liveness-unused.rs:20:9 + --> $DIR/liveness-unused.rs:21:9 | LL | let x: isize; | ^ help: if this is intentional, prefix it with an underscore: `_x` error: unused variable: `x` - --> $DIR/liveness-unused.rs:25:9 + --> $DIR/liveness-unused.rs:26:9 | LL | let x = 3; | ^ help: if this is intentional, prefix it with an underscore: `_x` error: variable `x` is assigned to, but never used - --> $DIR/liveness-unused.rs:30:13 + --> $DIR/liveness-unused.rs:31:13 | LL | let mut x = 3; | ^ @@ -52,7 +52,7 @@ LL | let mut x = 3; = note: consider using `_x` instead error: value assigned to `x` is never read - --> $DIR/liveness-unused.rs:32:5 + --> $DIR/liveness-unused.rs:33:5 | LL | x += 4; | ^ @@ -65,7 +65,7 @@ LL | #![deny(unused_assignments)] | ^^^^^^^^^^^^^^^^^^ error: variable `z` is assigned to, but never used - --> $DIR/liveness-unused.rs:37:13 + --> $DIR/liveness-unused.rs:38:13 | LL | let mut z = 3; | ^ @@ -73,31 +73,31 @@ LL | let mut z = 3; = note: consider using `_z` instead error: unused variable: `i` - --> $DIR/liveness-unused.rs:59:12 + --> $DIR/liveness-unused.rs:60:12 | LL | Some(i) => { | ^ help: if this is intentional, prefix it with an underscore: `_i` error: unused variable: `x` - --> $DIR/liveness-unused.rs:79:9 + --> $DIR/liveness-unused.rs:80:9 | LL | for x in 1..10 { } | ^ help: if this is intentional, prefix it with an underscore: `_x` error: unused variable: `x` - --> $DIR/liveness-unused.rs:84:10 + --> $DIR/liveness-unused.rs:85:10 | LL | for (x, _) in [1, 2, 3].iter().enumerate() { } | ^ help: if this is intentional, prefix it with an underscore: `_x` error: unused variable: `x` - --> $DIR/liveness-unused.rs:89:13 + --> $DIR/liveness-unused.rs:90:13 | LL | for (_, x) in [1, 2, 3].iter().enumerate() { | ^ help: if this is intentional, prefix it with an underscore: `_x` error: variable `x` is assigned to, but never used - --> $DIR/liveness-unused.rs:112:9 + --> $DIR/liveness-unused.rs:113:9 | LL | let x; | ^ @@ -105,7 +105,7 @@ LL | let x; = note: consider using `_x` instead error: value assigned to `x` is never read - --> $DIR/liveness-unused.rs:116:9 + --> $DIR/liveness-unused.rs:117:9 | LL | x = 0; | ^ diff --git a/tests/ui/mir/null/addrof_null.rs b/tests/ui/mir/null/addrof_null.rs new file mode 100644 index 00000000000..0d0b7edeef6 --- /dev/null +++ b/tests/ui/mir/null/addrof_null.rs @@ -0,0 +1,14 @@ +// Make sure that we don't insert a check for `addr_of!`. +//@ run-pass +//@ compile-flags: -C debug-assertions + +struct Field { + a: u32, +} + +fn main() { + unsafe { + let ptr: *const Field = std::ptr::null(); + let _ptr = core::ptr::addr_of!((*ptr).a); + } +} diff --git a/tests/ui/mir/null/borrowed_mut_null.rs b/tests/ui/mir/null/borrowed_mut_null.rs new file mode 100644 index 00000000000..437955c452b --- /dev/null +++ b/tests/ui/mir/null/borrowed_mut_null.rs @@ -0,0 +1,8 @@ +//@ run-fail +//@ compile-flags: -C debug-assertions +//@ error-pattern: null pointer dereference occured + +fn main() { + let ptr: *mut u32 = std::ptr::null_mut(); + let _ptr: &mut u32 = unsafe { &mut *ptr }; +} diff --git a/tests/ui/mir/null/borrowed_null.rs b/tests/ui/mir/null/borrowed_null.rs new file mode 100644 index 00000000000..eb0794efaa5 --- /dev/null +++ b/tests/ui/mir/null/borrowed_null.rs @@ -0,0 +1,8 @@ +//@ run-fail +//@ compile-flags: -C debug-assertions +//@ error-pattern: null pointer dereference occured + +fn main() { + let ptr: *const u32 = std::ptr::null(); + let _ptr: &u32 = unsafe { &*ptr }; +} diff --git a/tests/ui/mir/null/null_lhs.rs b/tests/ui/mir/null/null_lhs.rs new file mode 100644 index 00000000000..fd3bc3a78b8 --- /dev/null +++ b/tests/ui/mir/null/null_lhs.rs @@ -0,0 +1,10 @@ +//@ run-fail +//@ compile-flags: -C debug-assertions +//@ error-pattern: null pointer dereference occured + +fn main() { + let ptr: *mut u32 = std::ptr::null_mut(); + unsafe { + *(ptr) = 42; + } +} diff --git a/tests/ui/mir/null/null_rhs.rs b/tests/ui/mir/null/null_rhs.rs new file mode 100644 index 00000000000..45c8beb3fe8 --- /dev/null +++ b/tests/ui/mir/null/null_rhs.rs @@ -0,0 +1,10 @@ +//@ run-fail +//@ compile-flags: -C debug-assertions +//@ error-pattern: null pointer dereference occured + +fn main() { + let ptr: *mut u32 = std::ptr::null_mut(); + unsafe { + let _v = *ptr; + } +} diff --git a/tests/ui/mir/null/place_without_read.rs b/tests/ui/mir/null/place_without_read.rs new file mode 100644 index 00000000000..d6bfb089b01 --- /dev/null +++ b/tests/ui/mir/null/place_without_read.rs @@ -0,0 +1,10 @@ +// Make sure that we don't insert a check for places that do not read. +//@ run-pass +//@ compile-flags: -C debug-assertions + +fn main() { + let ptr: *const u16 = std::ptr::null(); + unsafe { + let _ = *ptr; + } +} diff --git a/tests/ui/mir/null/two_pointers.rs b/tests/ui/mir/null/two_pointers.rs new file mode 100644 index 00000000000..d9f0687fe0d --- /dev/null +++ b/tests/ui/mir/null/two_pointers.rs @@ -0,0 +1,12 @@ +//@ run-fail +//@ compile-flags: -C debug-assertions +//@ error-pattern: null pointer dereference occured + +fn main() { + let ptr = std::ptr::null(); + let mut dest = 0u32; + let dest_ptr = &mut dest as *mut u32; + unsafe { + *dest_ptr = *(ptr); + } +} diff --git a/tests/ui/mir/null/zero_sized_access.rs b/tests/ui/mir/null/zero_sized_access.rs new file mode 100644 index 00000000000..e8aaf820c49 --- /dev/null +++ b/tests/ui/mir/null/zero_sized_access.rs @@ -0,0 +1,15 @@ +// Make sure that we don't insert a check for zero-sized reads or writes to +// null, because they are allowed. +//@ run-pass +//@ compile-flags: -C debug-assertions + +fn main() { + let ptr: *mut () = std::ptr::null_mut(); + unsafe { + *(ptr) = (); + } + let ptr1: *const () = std::ptr::null_mut(); + unsafe { + let _ptr = *ptr1; + } +} diff --git a/tests/ui/never_type/fallback-closure-wrap.fallback.stderr b/tests/ui/never_type/fallback-closure-wrap.fallback.stderr index aa4a2760ffd..ac99a1fc24c 100644 --- a/tests/ui/never_type/fallback-closure-wrap.fallback.stderr +++ b/tests/ui/never_type/fallback-closure-wrap.fallback.stderr @@ -1,16 +1,15 @@ -error[E0271]: expected `{closure@fallback-closure-wrap.rs:18:40}` to be a closure that returns `()`, but it returns `!` - --> $DIR/fallback-closure-wrap.rs:18:31 +error[E0271]: expected `{closure@fallback-closure-wrap.rs:18:40}` to return `()`, but it returns `!` + --> $DIR/fallback-closure-wrap.rs:19:9 | -LL | let error = Closure::wrap(Box::new(move || { - | _______________________________^ -LL | | -LL | | panic!("Can't connect to server."); -LL | | }) as Box<dyn FnMut()>); - | |______^ expected `()`, found `!` +LL | let error = Closure::wrap(Box::new(move || { + | ------- this closure +LL | panic!("Can't connect to server."); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `!` | = note: expected unit type `()` found type `!` = note: required for the cast from `Box<{closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47}>` to `Box<dyn FnMut()>` + = note: this error originates in the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/never_type/fallback-closure-wrap.rs b/tests/ui/never_type/fallback-closure-wrap.rs index 27020289c68..e7f7d5aae3f 100644 --- a/tests/ui/never_type/fallback-closure-wrap.rs +++ b/tests/ui/never_type/fallback-closure-wrap.rs @@ -16,8 +16,8 @@ use std::marker::PhantomData; fn main() { let error = Closure::wrap(Box::new(move || { - //[fallback]~^ to be a closure that returns `()`, but it returns `!` panic!("Can't connect to server."); + //[fallback]~^ to return `()`, but it returns `!` }) as Box<dyn FnMut()>); } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2024.stderr new file mode 100644 index 00000000000..331b86736a0 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic2024.stderr @@ -0,0 +1,79 @@ +error[E0508]: cannot move out of type `[&mut u32; 1]`, a non-copy array + --> $DIR/borrowck-errors.rs:13:16 + | +LL | let [&x] = &[&mut 0]; + | - ^^^^^^^^^ cannot move out of here + | | + | data moved here + | move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait + | +help: consider borrowing the pattern binding + | +LL | let [&ref x] = &[&mut 0]; + | +++ + +error[E0508]: cannot move out of type `[&mut u32; 1]`, a non-copy array + --> $DIR/borrowck-errors.rs:19:16 + | +LL | let [&x] = &mut [&mut 0]; + | - ^^^^^^^^^^^^^ cannot move out of here + | | + | data moved here + | move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait + | +help: consider borrowing the pattern binding + | +LL | let [&ref x] = &mut [&mut 0]; + | +++ + +error[E0507]: cannot move out of a shared reference + --> $DIR/borrowck-errors.rs:27:29 + | +LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) { + | - ^^^^^^^^^^^^^^^^^^^ + | | + | data moved here + | move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait + | +help: consider removing the borrow + | +LL - if let Some(&Some(x)) = Some(&Some(&mut 0)) { +LL + if let Some(Some(x)) = Some(&Some(&mut 0)) { + | + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/borrowck-errors.rs:32:10 + | +LL | let &ref mut x = &0; + | ^^^^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/borrowck-errors.rs:35:23 + | +LL | if let &Some(Some(x)) = &Some(&mut Some(0)) { + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/borrowck-errors.rs:40:11 + | +LL | let &[x] = &&mut [0]; + | ^ cannot borrow as mutable + +error[E0508]: cannot move out of type `[&mut i32; 1]`, a non-copy array + --> $DIR/borrowck-errors.rs:44:20 + | +LL | let [&mut x] = &mut [&mut 0]; + | - ^^^^^^^^^^^^^ cannot move out of here + | | + | data moved here + | move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait + | +help: consider borrowing the pattern binding + | +LL | let [&mut ref x] = &mut [&mut 0]; + | +++ + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0507, E0508, E0596. +For more information about an error, try `rustc --explain E0507`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs index a01e9ca2657..3f5d9c8db5d 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs @@ -1,9 +1,27 @@ -//@ edition: 2024 -//@ revisions: classic structural +//@ revisions: stable2021 classic2024 structural2024 +//@[stable2021] edition: 2021 +//@[classic2024] edition: 2024 +//@[structural2024] edition: 2024 //! Tests for pattern errors not handled by the pattern typing rules, but by borrowck. #![allow(incomplete_features)] -#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))] -#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))] +#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))] + +/// These patterns additionally use `&` to match a `&mut` reference type, which causes compilation +/// to fail in HIR typeck on stable. As such, they need to be separate from the other tests. +fn errors_caught_in_hir_typeck_on_stable() { + let [&x] = &[&mut 0]; + //[stable2021]~^ mismatched types + //[stable2021]~| types differ in mutability + //[classic2024]~^^^ ERROR: cannot move out of type + let _: &u32 = x; + + let [&x] = &mut [&mut 0]; + //[stable2021]~^ mismatched types + //[stable2021]~| types differ in mutability + //[classic2024]~^^^ ERROR: cannot move out of type + let _: &u32 = x; +} pub fn main() { if let Some(&Some(x)) = Some(&Some(&mut 0)) { @@ -13,4 +31,18 @@ pub fn main() { let &ref mut x = &0; //~^ cannot borrow data in a `&` reference as mutable [E0596] + + if let &Some(Some(x)) = &Some(&mut Some(0)) { + //[stable2021,classic2024]~^ ERROR: cannot borrow data in a `&` reference as mutable + let _: &u32 = x; + } + + let &[x] = &&mut [0]; + //[stable2021,classic2024]~^ ERROR: cannot borrow data in a `&` reference as mutable + let _: &u32 = x; + + let [&mut x] = &mut [&mut 0]; + //[classic2024]~^ ERROR: cannot move out of type + #[cfg(stable2021)] let _: u32 = x; + #[cfg(structural2024)] let _: &mut u32 = x; } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.stable2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.stable2021.stderr new file mode 100644 index 00000000000..65c98e2da9c --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.stable2021.stderr @@ -0,0 +1,69 @@ +error[E0308]: mismatched types + --> $DIR/borrowck-errors.rs:13:10 + | +LL | let [&x] = &[&mut 0]; + | ^^ --------- this expression has type `&[&mut {integer}; 1]` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut {integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - let [&x] = &[&mut 0]; +LL + let [x] = &[&mut 0]; + | + +error[E0308]: mismatched types + --> $DIR/borrowck-errors.rs:19:10 + | +LL | let [&x] = &mut [&mut 0]; + | ^^ ------------- this expression has type `&mut [&mut {integer}; 1]` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut {integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - let [&x] = &mut [&mut 0]; +LL + let [x] = &mut [&mut 0]; + | + +error[E0507]: cannot move out of a shared reference + --> $DIR/borrowck-errors.rs:27:29 + | +LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) { + | - ^^^^^^^^^^^^^^^^^^^ + | | + | data moved here + | move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait + | +help: consider removing the borrow + | +LL - if let Some(&Some(x)) = Some(&Some(&mut 0)) { +LL + if let Some(Some(x)) = Some(&Some(&mut 0)) { + | + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/borrowck-errors.rs:32:10 + | +LL | let &ref mut x = &0; + | ^^^^^^^^^ cannot borrow as mutable + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/borrowck-errors.rs:35:23 + | +LL | if let &Some(Some(x)) = &Some(&mut Some(0)) { + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/borrowck-errors.rs:40:11 + | +LL | let &[x] = &&mut [0]; + | ^ cannot borrow as mutable + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0308, E0507, E0596. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural.stderr deleted file mode 100644 index c6246114075..00000000000 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error[E0507]: cannot move out of a shared reference - --> $DIR/borrowck-errors.rs:9:29 - | -LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) { - | - ^^^^^^^^^^^^^^^^^^^ - | | - | data moved here - | move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait - | -help: consider removing the borrow - | -LL - if let Some(&Some(x)) = Some(&Some(&mut 0)) { -LL + if let Some(Some(x)) = Some(&Some(&mut 0)) { - | - -error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-errors.rs:14:10 - | -LL | let &ref mut x = &0; - | ^^^^^^^^^ cannot borrow as mutable - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0507, E0596. -For more information about an error, try `rustc --explain E0507`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural2024.stderr index c6246114075..30d2f9f3d70 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural2024.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of a shared reference - --> $DIR/borrowck-errors.rs:9:29 + --> $DIR/borrowck-errors.rs:27:29 | LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) { | - ^^^^^^^^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL + if let Some(Some(x)) = Some(&Some(&mut 0)) { | error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/borrowck-errors.rs:14:10 + --> $DIR/borrowck-errors.rs:32:10 | LL | let &ref mut x = &0; | ^^^^^^^^^ cannot borrow as mutable diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.classic.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.classic2024.stderr index 89a52ba7d1d..89a52ba7d1d 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.classic.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.classic2024.stderr diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.rs index e22bd1f8f6c..a493b672c92 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.rs @@ -1,9 +1,9 @@ //@ edition: 2024 -//@ revisions: classic structural +//@ revisions: classic2024 structural2024 //! Test that `&mut` patterns don't match shared reference types under new typing rules in Rust 2024 #![allow(incomplete_features)] -#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))] -#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))] +#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))] pub fn main() { let &mut _ = &&0; diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.structural2024.stderr index 89a52ba7d1d..89a52ba7d1d 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.structural.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.structural2024.stderr diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic2024.stderr index 43560a18030..afaa925a757 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic2024.stderr @@ -1,5 +1,5 @@ error[E0658]: binding cannot be both mutable and by-reference - --> $DIR/mut-ref-mut.rs:11:13 + --> $DIR/mut-ref-mut.rs:14:13 | LL | let Foo(mut a) = &Foo(0); | ^^^^ @@ -9,7 +9,7 @@ LL | let Foo(mut a) = &Foo(0); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: binding cannot be both mutable and by-reference - --> $DIR/mut-ref-mut.rs:15:13 + --> $DIR/mut-ref-mut.rs:19:13 | LL | let Foo(mut a) = &mut Foo(0); | ^^^^ @@ -18,6 +18,19 @@ LL | let Foo(mut a) = &mut Foo(0); = help: add `#![feature(mut_ref)]` 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 +error[E0308]: mismatched types + --> $DIR/mut-ref-mut.rs:24:10 + | +LL | let [&mut mut x] = &[&mut 0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | let [&mut x] = &[&mut 0]; + | ~ + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0308, E0658. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs index 786587984ba..fbd6514df73 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs @@ -1,18 +1,29 @@ -//@ edition: 2024 -//@ revisions: classic structural +//@ revisions: stable2021 classic2024 structural2024 +//@[stable2021] edition: 2021 +//@[classic2024] edition: 2024 +//@[structural2024] edition: 2024 +//@[stable2021] run-pass //! Test diagnostics for binding with `mut` when the default binding mode is by-ref. -#![allow(incomplete_features)] -#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))] -#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))] +#![allow(incomplete_features, unused_assignments, unused_variables)] +#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))] pub fn main() { struct Foo(u8); let Foo(mut a) = &Foo(0); - //~^ ERROR: binding cannot be both mutable and by-reference - a = &42; + //[classic2024,structural2024]~^ ERROR: binding cannot be both mutable and by-reference + #[cfg(stable2021)] { a = 42 } + #[cfg(any(classic2024, structural2024))] { a = &42 } let Foo(mut a) = &mut Foo(0); - //~^ ERROR: binding cannot be both mutable and by-reference - a = &mut 42; + //[classic2024,structural2024]~^ ERROR: binding cannot be both mutable and by-reference + #[cfg(stable2021)] { a = 42 } + #[cfg(any(classic2024, structural2024))] { a = &mut 42 } + + let [&mut mut x] = &[&mut 0]; + //[classic2024]~^ ERROR: mismatched types + //[classic2024]~| cannot match inherited `&` with `&mut` pattern + //[structural2024]~^^^ binding cannot be both mutable and by-reference + #[cfg(stable2021)] { x = 0 } } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural2024.stderr index 43560a18030..fd82da70a18 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural2024.stderr @@ -1,5 +1,5 @@ error[E0658]: binding cannot be both mutable and by-reference - --> $DIR/mut-ref-mut.rs:11:13 + --> $DIR/mut-ref-mut.rs:14:13 | LL | let Foo(mut a) = &Foo(0); | ^^^^ @@ -9,7 +9,7 @@ LL | let Foo(mut a) = &Foo(0); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: binding cannot be both mutable and by-reference - --> $DIR/mut-ref-mut.rs:15:13 + --> $DIR/mut-ref-mut.rs:19:13 | LL | let Foo(mut a) = &mut Foo(0); | ^^^^ @@ -18,6 +18,16 @@ LL | let Foo(mut a) = &mut Foo(0); = help: add `#![feature(mut_ref)]` 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 +error[E0658]: binding cannot be both mutable and by-reference + --> $DIR/mut-ref-mut.rs:24:15 + | +LL | let [&mut mut x] = &[&mut 0]; + | ^^^^ + | + = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information + = help: add `#![feature(mut_ref)]` 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 3 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic2024.stderr index 2bc3ecb7636..3a124dcead5 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic2024.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:15:17 + --> $DIR/pattern-errors.rs:12:17 | LL | if let Some(&mut x) = &Some(&mut 0) { | ^^^^^ @@ -11,7 +11,7 @@ LL | if let Some(&x) = &Some(&mut 0) { | ~ error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:19:17 + --> $DIR/pattern-errors.rs:18:17 | LL | if let Some(&mut Some(&x)) = &Some(&mut Some(0)) { | ^^^^^ @@ -23,7 +23,7 @@ LL | if let Some(&Some(&x)) = &Some(&mut Some(0)) { | ~ error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:23:22 + --> $DIR/pattern-errors.rs:24:22 | LL | if let Some(Some(&mut x)) = &Some(Some(&mut 0)) { | ^^^^^ @@ -35,7 +35,7 @@ LL | if let Some(Some(&x)) = &Some(Some(&mut 0)) { | ~ error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:28:17 + --> $DIR/pattern-errors.rs:31:17 | LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { | ^^^^^ @@ -47,65 +47,77 @@ LL | if let Some(&Some(&_)) = &Some(&Some(0)) { | ~ error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:31:23 + --> $DIR/pattern-errors.rs:41:23 | -LL | if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { +LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { | ^^^^^ | = note: cannot match inherited `&` with `&mut` pattern help: replace this `&mut` pattern with `&` | -LL | if let Some(&Some(&_)) = &Some(&mut Some(0)) { +LL | if let Some(&Some(&_)) = &mut Some(&Some(0)) { | ~ error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:34:23 + --> $DIR/pattern-errors.rs:51:17 | -LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { - | ^^^^^ +LL | if let Some(&mut Some(x)) = &Some(Some(0)) { + | ^^^^^ | = note: cannot match inherited `&` with `&mut` pattern help: replace this `&mut` pattern with `&` | -LL | if let Some(&Some(&_)) = &mut Some(&Some(0)) { - | ~ +LL | if let Some(&Some(x)) = &Some(Some(0)) { + | ~ error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:37:29 + --> $DIR/pattern-errors.rs:147:10 | -LL | if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) { - | ^^^^^ +LL | let [&mut x] = &[&mut 0]; + | ^^^^^ | = note: cannot match inherited `&` with `&mut` pattern help: replace this `&mut` pattern with `&` | -LL | if let Some(&Some(Some((&_)))) = &Some(Some(&mut Some(0))) { - | ~ +LL | let [&x] = &[&mut 0]; + | ~ error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:40:17 + --> $DIR/pattern-errors.rs:153:10 | -LL | if let Some(&mut Some(x)) = &Some(Some(0)) { - | ^^^^^ +LL | let [&mut &x] = &[&mut 0]; + | ^^^^^ | = note: cannot match inherited `&` with `&mut` pattern help: replace this `&mut` pattern with `&` | -LL | if let Some(&Some(x)) = &Some(Some(0)) { - | ~ +LL | let [&&x] = &[&mut 0]; + | ~ error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:43:17 + --> $DIR/pattern-errors.rs:159:10 | -LL | if let Some(&mut Some(x)) = &Some(Some(0)) { - | ^^^^^ +LL | let [&mut &ref x] = &[&mut 0]; + | ^^^^^ | = note: cannot match inherited `&` with `&mut` pattern help: replace this `&mut` pattern with `&` | -LL | if let Some(&Some(x)) = &Some(Some(0)) { - | ~ +LL | let [&&ref x] = &[&mut 0]; + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:165:10 + | +LL | let [&mut &(mut x)] = &[&mut 0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | let [&&(mut x)] = &[&mut 0]; + | ~ -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs index 3535ba9c701..c07c2972cd0 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs @@ -1,46 +1,170 @@ -//@ edition: 2024 -//@ revisions: classic structural +//@ revisions: stable2021 classic2024 structural2024 +//@[stable2021] edition: 2021 +//@[classic2024] edition: 2024 +//@[structural2024] edition: 2024 //! Test cases for poorly-typed patterns in edition 2024 which are caught by HIR typeck. These must //! be separate from cases caught by MIR borrowck or the latter errors may not be emitted. #![allow(incomplete_features)] -#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))] -#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))] +#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))] pub fn main() { - if let Some(&mut x) = &mut Some(&0) { - //[structural]~^ ERROR: mismatched types - let _: &u32 = x; - } - if let Some(&mut x) = &Some(&mut 0) { - //[classic]~^ ERROR: mismatched types - let _: &u32 = x; + //[classic2024]~^ ERROR: mismatched types + //[classic2024]~| cannot match inherited `&` with `&mut` pattern + #[cfg(stable2021)] let _: u32 = x; + #[cfg(structural2024)] let _: &u32 = x; } if let Some(&mut Some(&x)) = &Some(&mut Some(0)) { - //[classic]~^ ERROR: mismatched types + //[stable2021,classic2024]~^ ERROR: mismatched types + //[stable2021]~| expected integer, found `&_` + //[classic2024]~| cannot match inherited `&` with `&mut` pattern let _: u32 = x; } if let Some(Some(&mut x)) = &Some(Some(&mut 0)) { - //[classic]~^ ERROR: mismatched types - let _: &u32 = x; + //[classic2024]~^ ERROR: mismatched types + //[classic2024]~| cannot match inherited `&` with `&mut` pattern + #[cfg(stable2021)] let _: u32 = x; + #[cfg(structural2024)] let _: &u32 = x; } if let Some(&mut Some(&_)) = &Some(&Some(0)) { //~^ ERROR: mismatched types + //[stable2021]~| types differ in mutability + //[classic2024,structural2024]~| cannot match inherited `&` with `&mut` pattern } if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { - //~^ ERROR: mismatched types + //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021]~| types differ in mutability + //[structural2024]~| cannot match inherited `&` with `&mut` pattern } if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { //~^ ERROR: mismatched types + //[stable2021]~| expected integer, found `&mut _` + //[classic2024,structural2024]~| cannot match inherited `&` with `&mut` pattern } - if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) { - //~^ ERROR: mismatched types - } - if let Some(&mut Some(x)) = &Some(Some(0)) { - //~^ ERROR: mismatched types + if let Some(&Some(Some(&mut _))) = &Some(Some(&mut Some(0))) { + //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021]~| expected `Option<&mut Option<{integer}>>`, found `&_` + //[structural2024]~| cannot match inherited `&` with `&mut` pattern } if let Some(&mut Some(x)) = &Some(Some(0)) { //~^ ERROR: mismatched types + //[stable2021]~| expected `Option<{integer}>`, found `&mut _` + //[classic2024,structural2024]~| cannot match inherited `&` with `&mut` pattern } } + +fn structural_errors_0() { + let &[&mut x] = &&mut [0]; + //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021]~| expected integer, found `&mut _` + //[structural2024]~| cannot match inherited `&` with `&mut` pattern + let _: u32 = x; + + let &[&mut x] = &mut &mut [0]; + //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021]~| types differ in mutability + //[structural2024]~| cannot match inherited `&` with `&mut` pattern + let _: u32 = x; + + let &[&mut ref x] = &&mut [0]; + //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021]~| expected integer, found `&mut _` + //[structural2024]~| cannot match inherited `&` with `&mut` pattern + let _: &u32 = x; + + let &[&mut ref x] = &mut &mut [0]; + //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021]~| types differ in mutability + //[structural2024]~| cannot match inherited `&` with `&mut` pattern + let _: &u32 = x; + + let &[&mut mut x] = &&mut [0]; + //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021]~| expected integer, found `&mut _` + //[structural2024]~| cannot match inherited `&` with `&mut` pattern + let _: u32 = x; + + let &[&mut mut x] = &mut &mut [0]; + //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021]~| types differ in mutability + //[structural2024]~| cannot match inherited `&` with `&mut` pattern + let _: u32 = x; +} + +fn structural_errors_1() { + let [&(mut x)] = &[&0]; + //[structural2024]~^ ERROR: binding cannot be both mutable and by-reference + #[cfg(stable2021)] let _: u32 = x; + #[cfg(classic2024)] let _: &u32 = x; + + let [&(mut x)] = &mut [&0]; + //[structural2024]~^ ERROR: binding cannot be both mutable and by-reference + #[cfg(stable2021)] let _: u32 = x; + #[cfg(classic2024)] let _: &u32 = x; +} + +fn structural_errors_2() { + let [&&mut x] = &[&mut 0]; + //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021]~| types differ in mutability + //[structural2024]~| cannot match inherited `&` with `&mut` pattern + let _: u32 = x; + + let [&&mut x] = &mut [&mut 0]; + //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021]~| types differ in mutability + //[structural2024]~| cannot match inherited `&` with `&mut` pattern + let _: u32 = x; + + let [&&mut ref x] = &[&mut 0]; + //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021]~| types differ in mutability + //[structural2024]~| cannot match inherited `&` with `&mut` pattern + let _: &u32 = x; + + let [&&mut ref x] = &mut [&mut 0]; + //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021]~| types differ in mutability + //[structural2024]~| cannot match inherited `&` with `&mut` pattern + let _: &u32 = x; + + let [&&mut mut x] = &[&mut 0]; + //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021]~| types differ in mutability + //[structural2024]~| cannot match inherited `&` with `&mut` pattern + let _: u32 = x; + + let [&&mut mut x] = &mut [&mut 0]; + //[stable2021,structural2024]~^ ERROR: mismatched types + //[stable2021]~| types differ in mutability + //[structural2024]~| cannot match inherited `&` with `&mut` pattern + let _: u32 = x; +} + +fn classic_errors_0() { + let [&mut x] = &[&mut 0]; + //[classic2024]~^ ERROR: mismatched types + //[classic2024]~| cannot match inherited `&` with `&mut` pattern + #[cfg(stable2021)] let _: u32 = x; + #[cfg(structural2024)] let _: &u32 = x; + + let [&mut &x] = &[&mut 0]; + //[stable2021,classic2024]~^ ERROR: mismatched types + //[stable2021]~| expected integer, found `&_` + //[classic2024]~| cannot match inherited `&` with `&mut` pattern + let _: u32 = x; + + let [&mut &ref x] = &[&mut 0]; + //[stable2021,classic2024]~^ ERROR: mismatched types + //[stable2021]~| expected integer, found `&_` + //[classic2024]~| cannot match inherited `&` with `&mut` pattern + let _: &u32 = x; + + let [&mut &(mut x)] = &[&mut 0]; + //[stable2021,classic2024]~^ ERROR: mismatched types + //[stable2021]~| expected integer, found `&_` + //[classic2024]~| cannot match inherited `&` with `&mut` pattern + let _: u32 = x; +} diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.stable2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.stable2021.stderr new file mode 100644 index 00000000000..e7eb1813846 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.stable2021.stderr @@ -0,0 +1,283 @@ +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:18:27 + | +LL | if let Some(&mut Some(&x)) = &Some(&mut Some(0)) { + | ^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL | if let Some(&mut Some(x)) = &Some(&mut Some(0)) { + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:31:17 + | +LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { + | ^^^^^^^^^^^^^ --------------- this expression has type `&Option<&Option<{integer}>>` + | | + | types differ in mutability + | + = note: expected reference `&Option<{integer}>` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:36:17 + | +LL | if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { + | ^^^^^^^^^^^^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut Option<{integer}>` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:41:23 + | +LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { + | ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:46:17 + | +LL | if let Some(&Some(Some(&mut _))) = &Some(Some(&mut Some(0))) { + | ^^^^^^^^^^^^^^^^^^^ ------------------------- this expression has type `&Option<Option<&mut Option<{integer}>>>` + | | + | expected `Option<&mut Option<{integer}>>`, found `&_` + | + = note: expected enum `Option<&mut Option<{integer}>>` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:51:17 + | +LL | if let Some(&mut Some(x)) = &Some(Some(0)) { + | ^^^^^^^^^^^^ -------------- this expression has type `&Option<Option<{integer}>>` + | | + | expected `Option<{integer}>`, found `&mut _` + | + = note: expected enum `Option<{integer}>` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:59:11 + | +LL | let &[&mut x] = &&mut [0]; + | ^^^^^^ --------- this expression has type `&&mut [{integer}; 1]` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut x` + --> $DIR/pattern-errors.rs:59:11 + | +LL | let &[&mut x] = &&mut [0]; + | ^^^^^^ +help: consider removing `&mut` from the pattern + | +LL - let &[&mut x] = &&mut [0]; +LL + let &[x] = &&mut [0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:65:9 + | +LL | let &[&mut x] = &mut &mut [0]; + | ^^^^^^^^^ ------------- this expression has type `&mut &mut [{integer}; 1]` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut &mut [{integer}; 1]` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:71:11 + | +LL | let &[&mut ref x] = &&mut [0]; + | ^^^^^^^^^^ --------- this expression has type `&&mut [{integer}; 1]` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut x` + --> $DIR/pattern-errors.rs:71:11 + | +LL | let &[&mut ref x] = &&mut [0]; + | ^^^^^^^^^^ +help: consider removing `&mut` from the pattern + | +LL - let &[&mut ref x] = &&mut [0]; +LL + let &[ref x] = &&mut [0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:77:9 + | +LL | let &[&mut ref x] = &mut &mut [0]; + | ^^^^^^^^^^^^^ ------------- this expression has type `&mut &mut [{integer}; 1]` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut &mut [{integer}; 1]` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:83:11 + | +LL | let &[&mut mut x] = &&mut [0]; + | ^^^^^^^^^^ --------- this expression has type `&&mut [{integer}; 1]` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut x` + --> $DIR/pattern-errors.rs:83:11 + | +LL | let &[&mut mut x] = &&mut [0]; + | ^^^^^^^^^^ +help: consider removing `&mut` from the pattern + | +LL - let &[&mut mut x] = &&mut [0]; +LL + let &[mut x] = &&mut [0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:89:9 + | +LL | let &[&mut mut x] = &mut &mut [0]; + | ^^^^^^^^^^^^^ ------------- this expression has type `&mut &mut [{integer}; 1]` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut &mut [{integer}; 1]` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:109:10 + | +LL | let [&&mut x] = &[&mut 0]; + | ^^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut {integer}` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:115:10 + | +LL | let [&&mut x] = &mut [&mut 0]; + | ^^^^^^^ ------------- this expression has type `&mut [&mut {integer}; 1]` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut {integer}` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:121:10 + | +LL | let [&&mut ref x] = &[&mut 0]; + | ^^^^^^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut {integer}` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:127:10 + | +LL | let [&&mut ref x] = &mut [&mut 0]; + | ^^^^^^^^^^^ ------------- this expression has type `&mut [&mut {integer}; 1]` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut {integer}` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:133:10 + | +LL | let [&&mut mut x] = &[&mut 0]; + | ^^^^^^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut {integer}` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:139:10 + | +LL | let [&&mut mut x] = &mut [&mut 0]; + | ^^^^^^^^^^^ ------------- this expression has type `&mut [&mut {integer}; 1]` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut {integer}` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:153:15 + | +LL | let [&mut &x] = &[&mut 0]; + | ^^ --------- this expression has type `&[&mut {integer}; 1]` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - let [&mut &x] = &[&mut 0]; +LL + let [&mut x] = &[&mut 0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:159:15 + | +LL | let [&mut &ref x] = &[&mut 0]; + | ^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - let [&mut &ref x] = &[&mut 0]; +LL + let [&mut ref x] = &[&mut 0]; + | + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:165:15 + | +LL | let [&mut &(mut x)] = &[&mut 0]; + | ^^^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - let [&mut &(mut x)] = &[&mut 0]; +LL + let [&mut mut x)] = &[&mut 0]; + | + +error: aborting due to 21 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural.stderr deleted file mode 100644 index 59d65553fae..00000000000 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural.stderr +++ /dev/null @@ -1,89 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:10:17 - | -LL | if let Some(&mut x) = &mut Some(&0) { - | ^^^^^^ ------------- this expression has type `&mut Option<&{integer}>` - | | - | types differ in mutability - | - = note: expected reference `&{integer}` - found mutable reference `&mut _` -note: to declare a mutable binding use: `mut x` - --> $DIR/pattern-errors.rs:10:17 - | -LL | if let Some(&mut x) = &mut Some(&0) { - | ^^^^^^ -help: consider removing `&mut` from the pattern - | -LL | if let Some(x) = &mut Some(&0) { - | ~ - -error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:28:17 - | -LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { - | ^^^^^^^^^^^^^ --------------- this expression has type `&Option<&Option<{integer}>>` - | | - | types differ in mutability - | - = note: expected reference `&Option<{integer}>` - found mutable reference `&mut _` - -error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:31:23 - | -LL | if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { - | ^^^^^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>` - | | - | expected integer, found `&mut _` - | - = note: expected type `{integer}` - found mutable reference `&mut _` - -error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:34:23 - | -LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { - | ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>` - | | - | expected integer, found `&mut _` - | - = note: expected type `{integer}` - found mutable reference `&mut _` - -error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:37:29 - | -LL | if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) { - | ^^^^^^ ------------------------- this expression has type `&Option<Option<&mut Option<{integer}>>>` - | | - | expected integer, found `&mut _` - | - = note: expected type `{integer}` - found mutable reference `&mut _` - -error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:40:17 - | -LL | if let Some(&mut Some(x)) = &Some(Some(0)) { - | ^^^^^^^^^^^^ -------------- this expression has type `&Option<Option<{integer}>>` - | | - | expected `Option<{integer}>`, found `&mut _` - | - = note: expected enum `Option<{integer}>` - found mutable reference `&mut _` - -error[E0308]: mismatched types - --> $DIR/pattern-errors.rs:43:17 - | -LL | if let Some(&mut Some(x)) = &Some(Some(0)) { - | ^^^^^^^^^^^^ -------------- this expression has type `&Option<Option<{integer}>>` - | | - | expected `Option<{integer}>`, found `&mut _` - | - = note: expected enum `Option<{integer}>` - found mutable reference `&mut _` - -error: aborting due to 7 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural2024.stderr new file mode 100644 index 00000000000..861ed2216cd --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural2024.stderr @@ -0,0 +1,228 @@ +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:31:17 + | +LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(&_)) = &Some(&Some(0)) { + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:36:23 + | +LL | if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(&_)) = &Some(&mut Some(0)) { + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:41:23 + | +LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(&_)) = &mut Some(&Some(0)) { + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:46:28 + | +LL | if let Some(&Some(Some(&mut _))) = &Some(Some(&mut Some(0))) { + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(Some(&_))) = &Some(Some(&mut Some(0))) { + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:51:17 + | +LL | if let Some(&mut Some(x)) = &Some(Some(0)) { + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(x)) = &Some(Some(0)) { + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:59:11 + | +LL | let &[&mut x] = &&mut [0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | let &[&x] = &&mut [0]; + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:65:11 + | +LL | let &[&mut x] = &mut &mut [0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | let &[&x] = &mut &mut [0]; + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:71:11 + | +LL | let &[&mut ref x] = &&mut [0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | let &[&ref x] = &&mut [0]; + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:77:11 + | +LL | let &[&mut ref x] = &mut &mut [0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | let &[&ref x] = &mut &mut [0]; + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:83:11 + | +LL | let &[&mut mut x] = &&mut [0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | let &[&mut x] = &&mut [0]; + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:89:11 + | +LL | let &[&mut mut x] = &mut &mut [0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | let &[&mut x] = &mut &mut [0]; + | ~ + +error[E0658]: binding cannot be both mutable and by-reference + --> $DIR/pattern-errors.rs:97:12 + | +LL | let [&(mut x)] = &[&0]; + | ^^^^ + | + = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information + = help: add `#![feature(mut_ref)]` 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]: binding cannot be both mutable and by-reference + --> $DIR/pattern-errors.rs:102:12 + | +LL | let [&(mut x)] = &mut [&0]; + | ^^^^ + | + = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information + = help: add `#![feature(mut_ref)]` 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[E0308]: mismatched types + --> $DIR/pattern-errors.rs:109:11 + | +LL | let [&&mut x] = &[&mut 0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | let [&&x] = &[&mut 0]; + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:115:11 + | +LL | let [&&mut x] = &mut [&mut 0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | let [&&x] = &mut [&mut 0]; + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:121:11 + | +LL | let [&&mut ref x] = &[&mut 0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | let [&&ref x] = &[&mut 0]; + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:127:11 + | +LL | let [&&mut ref x] = &mut [&mut 0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | let [&&ref x] = &mut [&mut 0]; + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:133:11 + | +LL | let [&&mut mut x] = &[&mut 0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | let [&&mut x] = &[&mut 0]; + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:139:11 + | +LL | let [&&mut mut x] = &mut [&mut 0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | let [&&mut x] = &mut [&mut 0]; + | ~ + +error: aborting due to 19 previous errors + +Some errors have detailed explanations: E0308, E0658. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr new file mode 100644 index 00000000000..70cdcbd62eb --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr @@ -0,0 +1,70 @@ +error[E0308]: mismatched types + --> $DIR/ref-binding-on-inh-ref-errors.rs:60:10 + | +LL | let [&mut ref x] = &[&mut 0]; + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | let [&ref x] = &[&mut 0]; + | ~ + +error: this pattern relies on behavior which may change in edition 2024 + --> $DIR/ref-binding-on-inh-ref-errors.rs:74:10 + | +LL | let [ref mut x] = &[0]; + | ^^^^^^^ cannot override to bind by-reference when that is the implicit default + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +help: make the implied reference pattern explicit + | +LL | let &[ref mut x] = &[0]; + | + + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/ref-binding-on-inh-ref-errors.rs:74:10 + | +LL | let [ref mut x] = &[0]; + | ^^^^^^^^^ cannot borrow as mutable + +error: this pattern relies on behavior which may change in edition 2024 + --> $DIR/ref-binding-on-inh-ref-errors.rs:83:10 + | +LL | let [ref x] = &[0]; + | ^^^ cannot override to bind by-reference when that is the implicit default + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +help: make the implied reference pattern explicit + | +LL | let &[ref x] = &[0]; + | + + +error: this pattern relies on behavior which may change in edition 2024 + --> $DIR/ref-binding-on-inh-ref-errors.rs:88:10 + | +LL | let [ref x] = &mut [0]; + | ^^^ cannot override to bind by-reference when that is the implicit default + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +help: make the implied reference pattern explicit + | +LL | let &mut [ref x] = &mut [0]; + | ++++ + +error: this pattern relies on behavior which may change in edition 2024 + --> $DIR/ref-binding-on-inh-ref-errors.rs:93:10 + | +LL | let [ref mut x] = &mut [0]; + | ^^^^^^^ cannot override to bind by-reference when that is the implicit default + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +help: make the implied reference pattern explicit + | +LL | let &mut [ref mut x] = &mut [0]; + | ++++ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0308, E0596. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.rs new file mode 100644 index 00000000000..4c88c0c63ae --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.rs @@ -0,0 +1,97 @@ +//@ revisions: stable2021 classic2024 structural2024 +//@[stable2021] edition: 2021 +//@[classic2024] edition: 2024 +//@[structural2024] edition: 2024 +//! Tests for errors from binding with `ref x` under a by-ref default binding mode in edition 2024. +//! These can't be in the same body as tests for other errors, since they're emitted during THIR +//! construction. The errors on stable edition 2021 Rust are unrelated. +#![allow(incomplete_features)] +#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))] + +/// These only fail on the eat-inner variant of the new edition 2024 pattern typing rules. +/// The eat-outer variant eats the inherited reference, so binding with `ref` isn't a problem. +fn errors_from_eating_the_real_reference() { + let [&ref x] = &[&0]; + //[structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024 + //[structural2024]~| cannot override to bind by-reference when that is the implicit default + #[cfg(stable2021)] let _: &u32 = x; + #[cfg(classic2024)] let _: &&u32 = x; + + let [&ref x] = &mut [&0]; + //[structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024 + //[structural2024]~| cannot override to bind by-reference when that is the implicit default + #[cfg(stable2021)] let _: &u32 = x; + #[cfg(classic2024)] let _: &&u32 = x; + + let [&mut ref x] = &mut [&mut 0]; + //[structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024 + //[structural2024]~| cannot override to bind by-reference when that is the implicit default + #[cfg(stable2021)] let _: &u32 = x; + #[cfg(classic2024)] let _: &&mut u32 = x; + + let [&mut ref mut x] = &mut [&mut 0]; + //[structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024 + //[structural2024]~| cannot override to bind by-reference when that is the implicit default + #[cfg(stable2021)] let _: &mut u32 = x; + #[cfg(classic2024)] let _: &mut &mut u32 = x; +} + +/// To make absolutely sure binding with `ref` ignores inherited references on stable, let's +/// quarantine these typeck errors (from using a `&` pattern to match a `&mut` reference type). +fn errors_from_eating_the_real_reference_caught_in_hir_typeck_on_stable() { + let [&ref x] = &[&mut 0]; + //[stable2021]~^ ERROR: mismatched types + //[stable2021]~| types differ in mutability + //[structural2024]~^^^ ERROR: this pattern relies on behavior which may change in edition 2024 + //[structural2024]~| cannot override to bind by-reference when that is the implicit default + #[cfg(classic2024)] let _: &&mut u32 = x; + + let [&ref x] = &mut [&mut 0]; + //[stable2021]~^ ERROR: mismatched types + //[stable2021]~| types differ in mutability + //[structural2024]~^^^ ERROR: this pattern relies on behavior which may change in edition 2024 + //[structural2024]~| cannot override to bind by-reference when that is the implicit default + #[cfg(classic2024)] let _: &&mut u32 = x; +} + +/// This one also needs to be quarantined for a typeck error on `classic2024` (eat-outer). +fn errors_dependent_on_eating_order_caught_in_hir_typeck_when_eating_outer() { + let [&mut ref x] = &[&mut 0]; + //[classic2024]~^ ERROR: mismatched types + //[classic2024]~| cannot match inherited `&` with `&mut` pattern + //[structural2024]~^^^ ERROR: this pattern relies on behavior which may change in edition 2024 + //[structural2024]~| cannot override to bind by-reference when that is the implicit default + #[cfg(stable2021)] let _: &u32 = x; +} + +/// These should be errors in all editions. In edition 2024, they should be caught by the pattern +/// typing rules disallowing `ref` when there's an inherited reference. In old editions where that +/// resets the binding mode, they're borrowck errors due to binding with `ref mut`. +/// As a quirk of how the edition 2024 error is emitted during THIR construction, it ends up going +/// through borrowck as well, using the old `ref` behavior as a fallback, so we get that error too. +fn borrowck_errors_in_old_editions() { + let [ref mut x] = &[0]; + //~^ ERROR: cannot borrow data in a `&` reference as mutable + //[classic2024,structural2024]~| ERROR: this pattern relies on behavior which may change in edition 2024 + //[classic2024,structural2024]~| cannot override to bind by-reference when that is the implicit default +} + +/// The remaining tests are purely for testing `ref` bindings in the presence of an inherited +/// reference. These should always fail on edition 2024 and succeed on edition 2021. +pub fn main() { + let [ref x] = &[0]; + //[classic2024,structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024 + //[classic2024,structural2024]~| cannot override to bind by-reference when that is the implicit default + #[cfg(stable2021)] let _: &u32 = x; + + let [ref x] = &mut [0]; + //[classic2024,structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024 + //[classic2024,structural2024]~| cannot override to bind by-reference when that is the implicit default + #[cfg(stable2021)] let _: &u32 = x; + + let [ref mut x] = &mut [0]; + //[classic2024,structural2024]~^ ERROR: this pattern relies on behavior which may change in edition 2024 + //[classic2024,structural2024]~| cannot override to bind by-reference when that is the implicit default + #[cfg(stable2021)] let _: &mut u32 = x; +} diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.stable2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.stable2021.stderr new file mode 100644 index 00000000000..a21e4bb5b8f --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.stable2021.stderr @@ -0,0 +1,42 @@ +error[E0308]: mismatched types + --> $DIR/ref-binding-on-inh-ref-errors.rs:43:10 + | +LL | let [&ref x] = &[&mut 0]; + | ^^^^^^ --------- this expression has type `&[&mut {integer}; 1]` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut {integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - let [&ref x] = &[&mut 0]; +LL + let [ref x] = &[&mut 0]; + | + +error[E0308]: mismatched types + --> $DIR/ref-binding-on-inh-ref-errors.rs:50:10 + | +LL | let [&ref x] = &mut [&mut 0]; + | ^^^^^^ ------------- this expression has type `&mut [&mut {integer}; 1]` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut {integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - let [&ref x] = &mut [&mut 0]; +LL + let [ref x] = &mut [&mut 0]; + | + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/ref-binding-on-inh-ref-errors.rs:74:10 + | +LL | let [ref mut x] = &[0]; + | ^^^^^^^^^ cannot borrow as mutable + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0308, E0596. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2024.stderr new file mode 100644 index 00000000000..ee2c831bfcc --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2024.stderr @@ -0,0 +1,141 @@ +error: this pattern relies on behavior which may change in edition 2024 + --> $DIR/ref-binding-on-inh-ref-errors.rs:15:11 + | +LL | let [&ref x] = &[&0]; + | ^^^ cannot override to bind by-reference when that is the implicit default + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +help: make the implied reference pattern explicit + | +LL | let &[&ref x] = &[&0]; + | + + +error: this pattern relies on behavior which may change in edition 2024 + --> $DIR/ref-binding-on-inh-ref-errors.rs:21:11 + | +LL | let [&ref x] = &mut [&0]; + | ^^^ cannot override to bind by-reference when that is the implicit default + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +help: make the implied reference pattern explicit + | +LL | let &mut [&ref x] = &mut [&0]; + | ++++ + +error: this pattern relies on behavior which may change in edition 2024 + --> $DIR/ref-binding-on-inh-ref-errors.rs:27:15 + | +LL | let [&mut ref x] = &mut [&mut 0]; + | ^^^ cannot override to bind by-reference when that is the implicit default + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +help: make the implied reference pattern explicit + | +LL | let &mut [&mut ref x] = &mut [&mut 0]; + | ++++ + +error: this pattern relies on behavior which may change in edition 2024 + --> $DIR/ref-binding-on-inh-ref-errors.rs:33:15 + | +LL | let [&mut ref mut x] = &mut [&mut 0]; + | ^^^^^^^ cannot override to bind by-reference when that is the implicit default + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +help: make the implied reference pattern explicit + | +LL | let &mut [&mut ref mut x] = &mut [&mut 0]; + | ++++ + +error: this pattern relies on behavior which may change in edition 2024 + --> $DIR/ref-binding-on-inh-ref-errors.rs:43:11 + | +LL | let [&ref x] = &[&mut 0]; + | ^^^ cannot override to bind by-reference when that is the implicit default + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +help: make the implied reference pattern explicit + | +LL | let &[&ref x] = &[&mut 0]; + | + + +error: this pattern relies on behavior which may change in edition 2024 + --> $DIR/ref-binding-on-inh-ref-errors.rs:50:11 + | +LL | let [&ref x] = &mut [&mut 0]; + | ^^^ cannot override to bind by-reference when that is the implicit default + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +help: make the implied reference pattern explicit + | +LL | let &mut [&ref x] = &mut [&mut 0]; + | ++++ + +error: this pattern relies on behavior which may change in edition 2024 + --> $DIR/ref-binding-on-inh-ref-errors.rs:60:15 + | +LL | let [&mut ref x] = &[&mut 0]; + | ^^^ cannot override to bind by-reference when that is the implicit default + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +help: make the implied reference pattern explicit + | +LL | let &[&mut ref x] = &[&mut 0]; + | + + +error: this pattern relies on behavior which may change in edition 2024 + --> $DIR/ref-binding-on-inh-ref-errors.rs:74:10 + | +LL | let [ref mut x] = &[0]; + | ^^^^^^^ cannot override to bind by-reference when that is the implicit default + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +help: make the implied reference pattern explicit + | +LL | let &[ref mut x] = &[0]; + | + + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/ref-binding-on-inh-ref-errors.rs:74:10 + | +LL | let [ref mut x] = &[0]; + | ^^^^^^^^^ cannot borrow as mutable + +error: this pattern relies on behavior which may change in edition 2024 + --> $DIR/ref-binding-on-inh-ref-errors.rs:83:10 + | +LL | let [ref x] = &[0]; + | ^^^ cannot override to bind by-reference when that is the implicit default + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +help: make the implied reference pattern explicit + | +LL | let &[ref x] = &[0]; + | + + +error: this pattern relies on behavior which may change in edition 2024 + --> $DIR/ref-binding-on-inh-ref-errors.rs:88:10 + | +LL | let [ref x] = &mut [0]; + | ^^^ cannot override to bind by-reference when that is the implicit default + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +help: make the implied reference pattern explicit + | +LL | let &mut [ref x] = &mut [0]; + | ++++ + +error: this pattern relies on behavior which may change in edition 2024 + --> $DIR/ref-binding-on-inh-ref-errors.rs:93:10 + | +LL | let [ref mut x] = &mut [0]; + | ^^^^^^^ cannot override to bind by-reference when that is the implicit default + | + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/match-ergonomics.html> +help: make the implied reference pattern explicit + | +LL | let &mut [ref mut x] = &mut [0]; + | ++++ + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.fixed b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.fixed deleted file mode 100644 index 4f4941975d8..00000000000 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.fixed +++ /dev/null @@ -1,33 +0,0 @@ -//@ edition: 2024 -//@ run-rustfix -//@ revisions: classic structural -//! Tests for `&` patterns matched against `&mut` reference types where the inner pattern attempts -//! to bind by mutable reference. -#![allow(incomplete_features)] -#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))] -#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))] - -pub fn main() { - if let Some(&mut Some(ref mut x)) = &mut Some(Some(0)) { - //~^ ERROR: cannot borrow as mutable inside an `&` pattern - let _: &mut u8 = x; - } - - if let &mut Some(Some(ref mut x)) = &mut Some(Some(0)) { - //~^ ERROR: cannot borrow as mutable inside an `&` pattern - let _: &mut u8 = x; - } - - macro_rules! pat { - ($var:ident) => { ref mut $var }; - } - let &mut pat!(x) = &mut 0; - //~^ ERROR: cannot borrow as mutable inside an `&` pattern - let _: &mut u8 = x; - - let &mut (ref mut a, ref mut b) = &mut (true, false); - //~^ ERROR: cannot borrow as mutable inside an `&` pattern - //~| ERROR: cannot borrow as mutable inside an `&` pattern - let _: &mut bool = a; - let _: &mut bool = b; -} diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2024.fixed b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2024.fixed new file mode 100644 index 00000000000..c01784d5076 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2024.fixed @@ -0,0 +1,45 @@ +//@ revisions: stable2021 classic2024 structural2024 +//@[stable2021] edition: 2021 +//@[classic2024] edition: 2024 +//@[structural2024] edition: 2024 +//@[classic2024] run-rustfix +//@[structural2024] run-rustfix +//! Tests for `&` patterns matched against `&mut` reference types where the inner pattern attempts +//! to bind by mutable reference. +#![allow(incomplete_features)] +#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))] + +pub fn main() { + if let Some(&mut Some(ref mut x)) = &mut Some(Some(0)) { + //[stable2021]~^ ERROR: mismatched types + //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + let _: &mut u8 = x; + } + + if let &mut Some(Some(ref mut x)) = &mut Some(Some(0)) { + //[stable2021]~^ ERROR: mismatched types + //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + let _: &mut u8 = x; + } + + macro_rules! pat { + ($var:ident) => { ref mut $var }; + } + let &mut pat!(x) = &mut 0; + //[stable2021]~^ ERROR: mismatched types + //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + let _: &mut u8 = x; + + let &mut (ref mut a, ref mut b) = &mut (true, false); + //[stable2021]~^ ERROR: mismatched types + //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2024,structural2024]~| ERROR: cannot borrow as mutable inside an `&` pattern + let _: &mut bool = a; + let _: &mut bool = b; + + let &mut [x] = &mut &mut [0]; + //[stable2021]~^ ERROR: mismatched types + //[classic2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + let _: &u32 = x; +} diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2024.stderr index 6c384a51fac..5e98b77be40 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic2024.stderr @@ -1,5 +1,5 @@ error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:11:31 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:14:31 | LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { | - ^ @@ -7,7 +7,7 @@ LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:16:31 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:20:31 | LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { | - ^ @@ -15,7 +15,7 @@ LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:24:15 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:29:15 | LL | let &pat!(x) = &mut 0; | - ^ @@ -23,7 +23,7 @@ LL | let &pat!(x) = &mut 0; | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:28:19 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:34:19 | LL | let &(ref mut a, ref mut b) = &mut (true, false); | - ^ @@ -31,13 +31,21 @@ LL | let &(ref mut a, ref mut b) = &mut (true, false); | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:28:30 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:34:30 | LL | let &(ref mut a, ref mut b) = &mut (true, false); | - ^ | | | help: replace this `&` with `&mut`: `&mut` -error: aborting due to 5 previous errors +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref-mut-inside-shared-ref-pat.rs:41:11 + | +LL | let &[x] = &mut &mut [0]; + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.rs index b29bff7603f..fe40dabb553 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.rs @@ -1,20 +1,25 @@ -//@ edition: 2024 -//@ run-rustfix -//@ revisions: classic structural +//@ revisions: stable2021 classic2024 structural2024 +//@[stable2021] edition: 2021 +//@[classic2024] edition: 2024 +//@[structural2024] edition: 2024 +//@[classic2024] run-rustfix +//@[structural2024] run-rustfix //! Tests for `&` patterns matched against `&mut` reference types where the inner pattern attempts //! to bind by mutable reference. #![allow(incomplete_features)] -#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))] -#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))] +#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))] pub fn main() { if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { - //~^ ERROR: cannot borrow as mutable inside an `&` pattern + //[stable2021]~^ ERROR: mismatched types + //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern let _: &mut u8 = x; } if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { - //~^ ERROR: cannot borrow as mutable inside an `&` pattern + //[stable2021]~^ ERROR: mismatched types + //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern let _: &mut u8 = x; } @@ -22,12 +27,19 @@ pub fn main() { ($var:ident) => { ref mut $var }; } let &pat!(x) = &mut 0; - //~^ ERROR: cannot borrow as mutable inside an `&` pattern + //[stable2021]~^ ERROR: mismatched types + //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern let _: &mut u8 = x; let &(ref mut a, ref mut b) = &mut (true, false); - //~^ ERROR: cannot borrow as mutable inside an `&` pattern - //~| ERROR: cannot borrow as mutable inside an `&` pattern + //[stable2021]~^ ERROR: mismatched types + //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2024,structural2024]~| ERROR: cannot borrow as mutable inside an `&` pattern let _: &mut bool = a; let _: &mut bool = b; + + let &[x] = &mut &mut [0]; + //[stable2021]~^ ERROR: mismatched types + //[classic2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + let _: &u32 = x; } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.stable2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.stable2021.stderr new file mode 100644 index 00000000000..72c6c05e184 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.stable2021.stderr @@ -0,0 +1,58 @@ +error[E0308]: mismatched types + --> $DIR/ref-mut-inside-shared-ref-pat.rs:14:17 + | +LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { + | ^^^^^^^^^^^^^^^^ ------------------ this expression has type `&mut Option<Option<{integer}>>` + | | + | expected `Option<{integer}>`, found `&_` + | + = note: expected enum `Option<{integer}>` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/ref-mut-inside-shared-ref-pat.rs:20:12 + | +LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { + | ^^^^^^^^^^^^^^^^^^^^^^ ------------------ this expression has type `&mut Option<Option<{integer}>>` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut Option<Option<{integer}>>` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/ref-mut-inside-shared-ref-pat.rs:29:9 + | +LL | let &pat!(x) = &mut 0; + | ^^^^^^^^ ------ this expression has type `&mut {integer}` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut {integer}` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/ref-mut-inside-shared-ref-pat.rs:34:9 + | +LL | let &(ref mut a, ref mut b) = &mut (true, false); + | ^^^^^^^^^^^^^^^^^^^^^^^ ------------------ this expression has type `&mut (bool, bool)` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut (bool, bool)` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/ref-mut-inside-shared-ref-pat.rs:41:9 + | +LL | let &[x] = &mut &mut [0]; + | ^^^^ ------------- this expression has type `&mut &mut [{integer}; 1]` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut &mut [{integer}; 1]` + found reference `&_` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.fixed b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.fixed deleted file mode 100644 index 4f4941975d8..00000000000 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.fixed +++ /dev/null @@ -1,33 +0,0 @@ -//@ edition: 2024 -//@ run-rustfix -//@ revisions: classic structural -//! Tests for `&` patterns matched against `&mut` reference types where the inner pattern attempts -//! to bind by mutable reference. -#![allow(incomplete_features)] -#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))] -#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))] - -pub fn main() { - if let Some(&mut Some(ref mut x)) = &mut Some(Some(0)) { - //~^ ERROR: cannot borrow as mutable inside an `&` pattern - let _: &mut u8 = x; - } - - if let &mut Some(Some(ref mut x)) = &mut Some(Some(0)) { - //~^ ERROR: cannot borrow as mutable inside an `&` pattern - let _: &mut u8 = x; - } - - macro_rules! pat { - ($var:ident) => { ref mut $var }; - } - let &mut pat!(x) = &mut 0; - //~^ ERROR: cannot borrow as mutable inside an `&` pattern - let _: &mut u8 = x; - - let &mut (ref mut a, ref mut b) = &mut (true, false); - //~^ ERROR: cannot borrow as mutable inside an `&` pattern - //~| ERROR: cannot borrow as mutable inside an `&` pattern - let _: &mut bool = a; - let _: &mut bool = b; -} diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2024.fixed b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2024.fixed new file mode 100644 index 00000000000..4ee849b38c5 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2024.fixed @@ -0,0 +1,45 @@ +//@ revisions: stable2021 classic2024 structural2024 +//@[stable2021] edition: 2021 +//@[classic2024] edition: 2024 +//@[structural2024] edition: 2024 +//@[classic2024] run-rustfix +//@[structural2024] run-rustfix +//! Tests for `&` patterns matched against `&mut` reference types where the inner pattern attempts +//! to bind by mutable reference. +#![allow(incomplete_features)] +#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))] + +pub fn main() { + if let Some(&mut Some(ref mut x)) = &mut Some(Some(0)) { + //[stable2021]~^ ERROR: mismatched types + //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + let _: &mut u8 = x; + } + + if let &mut Some(Some(ref mut x)) = &mut Some(Some(0)) { + //[stable2021]~^ ERROR: mismatched types + //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + let _: &mut u8 = x; + } + + macro_rules! pat { + ($var:ident) => { ref mut $var }; + } + let &mut pat!(x) = &mut 0; + //[stable2021]~^ ERROR: mismatched types + //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + let _: &mut u8 = x; + + let &mut (ref mut a, ref mut b) = &mut (true, false); + //[stable2021]~^ ERROR: mismatched types + //[classic2024,structural2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + //[classic2024,structural2024]~| ERROR: cannot borrow as mutable inside an `&` pattern + let _: &mut bool = a; + let _: &mut bool = b; + + let &[x] = &mut &mut [0]; + //[stable2021]~^ ERROR: mismatched types + //[classic2024]~^^ ERROR: cannot borrow as mutable inside an `&` pattern + let _: &u32 = x; +} diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2024.stderr index 6c384a51fac..69cb6c438b6 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural2024.stderr @@ -1,5 +1,5 @@ error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:11:31 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:14:31 | LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { | - ^ @@ -7,7 +7,7 @@ LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:16:31 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:20:31 | LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { | - ^ @@ -15,7 +15,7 @@ LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:24:15 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:29:15 | LL | let &pat!(x) = &mut 0; | - ^ @@ -23,7 +23,7 @@ LL | let &pat!(x) = &mut 0; | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:28:19 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:34:19 | LL | let &(ref mut a, ref mut b) = &mut (true, false); | - ^ @@ -31,7 +31,7 @@ LL | let &(ref mut a, ref mut b) = &mut (true, false); | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref-mut-inside-shared-ref-pat.rs:28:30 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:34:30 | LL | let &(ref mut a, ref mut b) = &mut (true, false); | - ^ diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021.rs index 9372049a2b2..ab3264704ac 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021.rs @@ -6,9 +6,11 @@ #![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))] pub fn main() { + #[cfg(structural)] if let &Some(Some(x)) = &Some(&mut Some(0)) { let _: &u32 = x; } + if let Some(&x) = Some(&mut 0) { let _: u32 = x; } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs index 077b52d8f27..3114b9d3bf8 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs @@ -1,59 +1,127 @@ -//@ edition: 2024 -//@ revisions: classic structural -//@ run-pass +//@ revisions: stable2021 classic2024 structural2024 +//@[stable2021] edition: 2021 +//@[classic2024] edition: 2024 +//@[structural2024] edition: 2024 +//@[classic2024] run-pass +//@[structural2024] run-pass //! Test cases for well-typed patterns in edition 2024. These are in their own file to ensure we //! pass both HIR typeck and MIR borrowck, as we may skip the latter if grouped with failing tests. -#![allow(incomplete_features)] -#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))] -#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))] +#![allow(incomplete_features, unused_mut)] +#![cfg_attr(classic2024, feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(structural2024, feature(ref_pat_eat_one_layer_2024_structural))] pub fn main() { - if let Some(Some(&x)) = &Some(&Some(0)) { - let _: u32 = x; - } - if let Some(Some(&x)) = &Some(Some(&0)) { + // Tests not using match ergonomics. These should always succeed with the same bindings. + if let Some(&Some(&mut ref x)) = Some(&Some(&mut 0)) { let _: &u32 = x; } - if let Some(Some(&&x)) = &Some(Some(&0)) { - let _: u32 = x; + + // Tests for differences in how many layers of reference are eaten by reference patterns + if let Some(Some(&x)) = &Some(Some(&0)) { + #[cfg(stable2021)] let _: u32 = x; + #[cfg(any(classic2024, structural2024))] let _: &u32 = x; } - if let Some(&Some(x)) = &Some(Some(0)) { - let _: u32 = x; + if let Some(&Some(x)) = &mut Some(&Some(0)) { + // This additionally tests that `&` patterns can eat inherited `&mut` refs. + // This is possible on stable when the real reference being eaten is of a `&` type. + #[cfg(stable2021)] let _: u32 = x; + #[cfg(any(classic2024, structural2024))] let _: &u32 = x; } - if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { + if let Some(Some(&&x)) = &Some(Some(&0)) { + //[stable2021]~^ mismatched types + //[stable2021]~| expected integer, found `&_` let _: u32 = x; } + + // Tests for eating a lone inherited reference if let Some(Some(&x)) = &Some(&Some(0)) { + //[stable2021]~^ mismatched types + //[stable2021]~| expected integer, found `&_` let _: u32 = x; } - if let Some(&Some(&x)) = &mut Some(&Some(0)) { + if let Some(&Some(x)) = &Some(Some(0)) { + //[stable2021]~^ mismatched types + //[stable2021]~| expected `Option<{integer}>`, found `&_` let _: u32 = x; } - if let Some(&Some(x)) = &mut Some(&Some(0)) { - let _: &u32 = x; - } - if let Some(&Some(&mut ref x)) = Some(&Some(&mut 0)) { - let _: &u32 = x; - } - if let &Some(Some(x)) = &Some(&mut Some(0)) { - let _: &u32 = x; + if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { + //[stable2021]~^ mismatched types + //[stable2021]~| expected integer, found `&mut _` + let _: u32 = x; } - if let Some(&Some(&x)) = &Some(&mut Some(0)) { + + // Tests for `&` patterns matching real `&mut` reference types + if let Some(&Some(&x)) = Some(&Some(&mut 0)) { + //[stable2021]~^ mismatched types + //[stable2021]~| types differ in mutability let _: u32 = x; } + + // Tests for eating only one layer and also eating a lone inherited reference if let Some(&Some(&x)) = &Some(&Some(0)) { + //[stable2021]~^ mismatched types + //[stable2021]~| expected integer, found `&_` let _: u32 = x; } - if let Some(&Some(&x)) = &Some(&mut Some(0)) { + + // Tests for `&` matching a lone inherited possibly-`&mut` reference + if let Some(&Some(Some(&x))) = &Some(Some(&mut Some(0))) { + //[stable2021]~^ mismatched types + //[stable2021]~| expected `Option<&mut Option<{integer}>>`, found `&_` let _: u32 = x; } - if let Some(&Some(Some(&x))) = &Some(Some(&mut Some(0))) { + if let Some(&Some(x)) = &mut Some(Some(0)) { + //[stable2021]~^ mismatched types + //[stable2021]~| expected `Option<{integer}>`, found `&_` let _: u32 = x; } - if let Some(&Some(&x)) = Some(&Some(&mut 0)) { + + // Tests eating one layer, eating a lone inherited ref, and `&` eating `&mut` (realness varies) + if let Some(&Some(&x)) = &Some(&mut Some(0)) { + //[stable2021]~^ mismatched types + //[stable2021]~| types differ in mutability let _: u32 = x; } - if let Some(&Some(x)) = &mut Some(Some(0)) { + if let Some(&Some(&x)) = &mut Some(&Some(0)) { + //[stable2021]~^ mismatched types + //[stable2021]~| expected integer, found `&_` let _: u32 = x; } + + // Tests for eat-inner rulesets matching on the outer reference if matching on the inner + // reference causes a mutability mismatch, i.e. `Deref(EatInner, FallbackToOuter)`: + let [&mut x] = &mut [&0]; + //[stable2021]~^ mismatched types + //[stable2021]~| types differ in mutability + let _: &u32 = x; + + let [&mut ref x] = &mut [&0]; + //[stable2021]~^ mismatched types + //[stable2021]~| types differ in mutability + let _: &&u32 = x; + + let [&mut ref mut x] = &mut [&0]; + //[stable2021]~^ mismatched types + //[stable2021]~| types differ in mutability + let _: &mut &u32 = x; + + let [&mut mut x] = &mut [&0]; + //[stable2021]~^ mismatched types + //[stable2021]~| types differ in mutability + let _: &u32 = x; + + let [&mut &x] = &mut [&0]; + //[stable2021]~^ mismatched types + //[stable2021]~| types differ in mutability + let _: u32 = x; + + let [&mut &ref x] = &mut [&0]; + //[stable2021]~^ mismatched types + //[stable2021]~| types differ in mutability + let _: &u32 = x; + + let [&mut &(mut x)] = &mut [&0]; + //[stable2021]~^ mismatched types + //[stable2021]~| types differ in mutability + let _: u32 = x; } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.stable2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.stable2021.stderr new file mode 100644 index 00000000000..e9c338de243 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.stable2021.stderr @@ -0,0 +1,260 @@ +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:30:23 + | +LL | if let Some(Some(&&x)) = &Some(Some(&0)) { + | ^^ --------------- this expression has type `&Option<Option<&{integer}>>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL - if let Some(Some(&&x)) = &Some(Some(&0)) { +LL + if let Some(Some(&x)) = &Some(Some(&0)) { + | + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:37:22 + | +LL | if let Some(Some(&x)) = &Some(&Some(0)) { + | ^^ --------------- this expression has type `&Option<&Option<{integer}>>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL | if let Some(Some(x)) = &Some(&Some(0)) { + | ~ + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:42:17 + | +LL | if let Some(&Some(x)) = &Some(Some(0)) { + | ^^^^^^^^ -------------- this expression has type `&Option<Option<{integer}>>` + | | + | expected `Option<{integer}>`, found `&_` + | + = note: expected enum `Option<{integer}>` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:47:22 + | +LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { + | ^^^^^^ ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>` + | | + | expected integer, found `&mut _` + | + = note: expected type `{integer}` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut x` + --> $DIR/well-typed-edition-2024.rs:47:22 + | +LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { + | ^^^^^^ +help: consider removing `&mut` from the pattern + | +LL | if let Some(Some(x)) = &mut Some(&mut Some(0)) { + | ~ + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:54:23 + | +LL | if let Some(&Some(&x)) = Some(&Some(&mut 0)) { + | ^^ ------------------- this expression has type `Option<&Option<&mut {integer}>>` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut {integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) { + | ~ + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:61:23 + | +LL | if let Some(&Some(&x)) = &Some(&Some(0)) { + | ^^ --------------- this expression has type `&Option<&Option<{integer}>>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL | if let Some(&Some(x)) = &Some(&Some(0)) { + | ~ + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:68:17 + | +LL | if let Some(&Some(Some(&x))) = &Some(Some(&mut Some(0))) { + | ^^^^^^^^^^^^^^^ ------------------------- this expression has type `&Option<Option<&mut Option<{integer}>>>` + | | + | expected `Option<&mut Option<{integer}>>`, found `&_` + | + = note: expected enum `Option<&mut Option<{integer}>>` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:73:17 + | +LL | if let Some(&Some(x)) = &mut Some(Some(0)) { + | ^^^^^^^^ ------------------ this expression has type `&mut Option<Option<{integer}>>` + | | + | expected `Option<{integer}>`, found `&_` + | + = note: expected enum `Option<{integer}>` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:80:17 + | +LL | if let Some(&Some(&x)) = &Some(&mut Some(0)) { + | ^^^^^^^^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut Option<{integer}>` + found reference `&_` + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:85:23 + | +LL | if let Some(&Some(&x)) = &mut Some(&Some(0)) { + | ^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL | if let Some(&Some(x)) = &mut Some(&Some(0)) { + | ~ + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:93:10 + | +LL | let [&mut x] = &mut [&0]; + | ^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` + | | + | types differ in mutability + | + = note: expected reference `&{integer}` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut x` + --> $DIR/well-typed-edition-2024.rs:93:10 + | +LL | let [&mut x] = &mut [&0]; + | ^^^^^^ +help: consider removing `&mut` from the pattern + | +LL - let [&mut x] = &mut [&0]; +LL + let [x] = &mut [&0]; + | + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:98:10 + | +LL | let [&mut ref x] = &mut [&0]; + | ^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` + | | + | types differ in mutability + | + = note: expected reference `&{integer}` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut x` + --> $DIR/well-typed-edition-2024.rs:98:10 + | +LL | let [&mut ref x] = &mut [&0]; + | ^^^^^^^^^^ +help: consider removing `&mut` from the pattern + | +LL - let [&mut ref x] = &mut [&0]; +LL + let [ref x] = &mut [&0]; + | + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:103:10 + | +LL | let [&mut ref mut x] = &mut [&0]; + | ^^^^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` + | | + | types differ in mutability + | + = note: expected reference `&{integer}` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut x` + --> $DIR/well-typed-edition-2024.rs:103:10 + | +LL | let [&mut ref mut x] = &mut [&0]; + | ^^^^^^^^^^^^^^ +help: consider removing `&mut` from the pattern + | +LL - let [&mut ref mut x] = &mut [&0]; +LL + let [ref mut x] = &mut [&0]; + | + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:108:10 + | +LL | let [&mut mut x] = &mut [&0]; + | ^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` + | | + | types differ in mutability + | + = note: expected reference `&{integer}` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut x` + --> $DIR/well-typed-edition-2024.rs:108:10 + | +LL | let [&mut mut x] = &mut [&0]; + | ^^^^^^^^^^ +help: consider removing `&mut` from the pattern + | +LL - let [&mut mut x] = &mut [&0]; +LL + let [mut x] = &mut [&0]; + | + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:113:10 + | +LL | let [&mut &x] = &mut [&0]; + | ^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` + | | + | types differ in mutability + | + = note: expected reference `&{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:118:10 + | +LL | let [&mut &ref x] = &mut [&0]; + | ^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` + | | + | types differ in mutability + | + = note: expected reference `&{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/well-typed-edition-2024.rs:123:10 + | +LL | let [&mut &(mut x)] = &mut [&0]; + | ^^^^^^^^^^^^^ --------- this expression has type `&mut [&{integer}; 1]` + | | + | types differ in mutability + | + = note: expected reference `&{integer}` + found mutable reference `&mut _` + +error: aborting due to 17 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/privacy/sysroot-private.default.stderr b/tests/ui/privacy/sysroot-private.default.stderr index 845d4558d13..fef88d107e6 100644 --- a/tests/ui/privacy/sysroot-private.default.stderr +++ b/tests/ui/privacy/sysroot-private.default.stderr @@ -1,11 +1,11 @@ error[E0405]: cannot find trait `Equivalent` in this scope - --> $DIR/sysroot-private.rs:26:18 + --> $DIR/sysroot-private.rs:27:18 | LL | trait Trait2<K>: Equivalent<K> {} | ^^^^^^^^^^ not found in this scope error[E0412]: cannot find type `K` in this scope - --> $DIR/sysroot-private.rs:31:35 + --> $DIR/sysroot-private.rs:32:35 | LL | fn trait_member<T>(val: &T, key: &K) -> bool { | - ^ @@ -22,13 +22,13 @@ LL | fn trait_member<T, K>(val: &T, key: &K) -> bool { | +++ error[E0220]: associated type `ExpressionStack` not found for `Trait` - --> $DIR/sysroot-private.rs:21:31 + --> $DIR/sysroot-private.rs:22:31 | LL | type AssociatedTy = dyn Trait<ExpressionStack = i32, Bar = i32>; | ^^^^^^^^^^^^^^^ help: `Trait` has the following associated type: `Bar` error[E0425]: cannot find function `memchr2` in this scope - --> $DIR/sysroot-private.rs:39:5 + --> $DIR/sysroot-private.rs:40:5 | LL | memchr2(b'a', b'b', buf) | ^^^^^^^ not found in this scope diff --git a/tests/ui/privacy/sysroot-private.rs b/tests/ui/privacy/sysroot-private.rs index 67ab67c7f5c..86818574592 100644 --- a/tests/ui/privacy/sysroot-private.rs +++ b/tests/ui/privacy/sysroot-private.rs @@ -7,6 +7,7 @@ //! of `std`'s dependencies, but may not be robust against dependency upgrades/changes. //@ only-unix Windows sysroots seem to not expose this dependency +//@ ignore-emscripten neither does Emscripten //@ revisions: default rustc_private_enabled // Enabling `rustc_private` should `std`'s dependencies accessible, so they should show up diff --git a/tests/ui/privacy/sysroot-private.rustc_private_enabled.stderr b/tests/ui/privacy/sysroot-private.rustc_private_enabled.stderr index 98e6922428a..4b54b59714a 100644 --- a/tests/ui/privacy/sysroot-private.rustc_private_enabled.stderr +++ b/tests/ui/privacy/sysroot-private.rustc_private_enabled.stderr @@ -1,11 +1,11 @@ error[E0405]: cannot find trait `Equivalent` in this scope - --> $DIR/sysroot-private.rs:26:18 + --> $DIR/sysroot-private.rs:27:18 | LL | trait Trait2<K>: Equivalent<K> {} | ^^^^^^^^^^ not found in this scope error[E0412]: cannot find type `K` in this scope - --> $DIR/sysroot-private.rs:31:35 + --> $DIR/sysroot-private.rs:32:35 | LL | fn trait_member<T>(val: &T, key: &K) -> bool { | - ^ @@ -22,13 +22,13 @@ LL | fn trait_member<T, K>(val: &T, key: &K) -> bool { | +++ error[E0220]: associated type `ExpressionStack` not found for `Trait` - --> $DIR/sysroot-private.rs:21:31 + --> $DIR/sysroot-private.rs:22:31 | LL | type AssociatedTy = dyn Trait<ExpressionStack = i32, Bar = i32>; | ^^^^^^^^^^^^^^^ there is an associated type `ExpressionStack` in the trait `gimli::read::op::EvaluationStorage` error[E0425]: cannot find function `memchr2` in this scope - --> $DIR/sysroot-private.rs:39:5 + --> $DIR/sysroot-private.rs:40:5 | LL | memchr2(b'a', b'b', buf) | ^^^^^^^ not found in this scope diff --git a/tests/ui/recursion/recursion.rs b/tests/ui/recursion/recursion.rs index f3c633983b1..ce56fe974b7 100644 --- a/tests/ui/recursion/recursion.rs +++ b/tests/ui/recursion/recursion.rs @@ -1,6 +1,7 @@ //@ build-fail //@ compile-flags:-C overflow-checks=off -//@ normalize-stderr: ".nll/" -> "/" +// The regex below normalizes the long type file name to make it suitable for compare-modes. +//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type.txt'" enum Nil {NilValue} struct Cons<T> {head:isize, tail:T} diff --git a/tests/ui/recursion/recursion.stderr b/tests/ui/recursion/recursion.stderr index 7a9f04d4bd6..cb9f67ba741 100644 --- a/tests/ui/recursion/recursion.stderr +++ b/tests/ui/recursion/recursion.stderr @@ -1,15 +1,15 @@ error: reached the recursion limit while instantiating `test::<Cons<Cons<Cons<Cons<Cons<...>>>>>>` - --> $DIR/recursion.rs:18:11 + --> $DIR/recursion.rs:19:11 | LL | _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `test` defined here - --> $DIR/recursion.rs:16:1 + --> $DIR/recursion.rs:17:1 | LL | fn test<T:Dot> (n:isize, i:isize, first:T, second:T) ->isize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/recursion/recursion.long-type.txt' + = note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type.txt' error: aborting due to 1 previous error diff --git a/tests/ui/resolve/issue-3907-2.stderr b/tests/ui/resolve/issue-3907-2.stderr index 4ab72a42eb8..40cdfb7a302 100644 --- a/tests/ui/resolve/issue-3907-2.stderr +++ b/tests/ui/resolve/issue-3907-2.stderr @@ -5,7 +5,7 @@ LL | fn bar(_x: Foo) {} | ^^^ `issue_3907::Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/auxiliary/issue-3907.rs:2:8 | LL | fn bar(); diff --git a/tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr b/tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr index 3e018995ba5..8382b4867e2 100644 --- a/tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr +++ b/tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr @@ -8,7 +8,7 @@ LL | let x = Rc::new(5usize) as Rc<dyn Foo>; | ^^^^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/arbitrary-self-types-dyn-incompatible.rs:8:18 | LL | trait Foo { @@ -27,7 +27,7 @@ LL | let x = Rc::new(5usize) as Rc<dyn Foo>; | ^^^^^^^^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/arbitrary-self-types-dyn-incompatible.rs:8:18 | LL | trait Foo { diff --git a/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr b/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr index 12c93d58537..d324f4641cf 100644 --- a/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr +++ b/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr @@ -8,7 +8,7 @@ LL | let x = Rc::new(5usize) as Rc<dyn Foo>; | ^^^^^^^^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/arbitrary-self-types-dyn-incompatible.rs:8:18 | LL | trait Foo { diff --git a/tests/ui/stability-attribute/allowed-through-unstable.rs b/tests/ui/stability-attribute/allowed-through-unstable.rs index e03417a4dae..5baa0fda940 100644 --- a/tests/ui/stability-attribute/allowed-through-unstable.rs +++ b/tests/ui/stability-attribute/allowed-through-unstable.rs @@ -5,6 +5,5 @@ extern crate allowed_through_unstable_core; -use allowed_through_unstable_core::unstable_module::OldStableTraitAllowedThoughUnstable; -use allowed_through_unstable_core::unstable_module::OldStableTraitAllowedThoughUnstableWithDeprecation; //~WARN use of deprecated module `allowed_through_unstable_core::unstable_module`: use the new path instead +use allowed_through_unstable_core::unstable_module::OldStableTraitAllowedThoughUnstable; //~WARN use of deprecated module `allowed_through_unstable_core::unstable_module`: use the new path instead use allowed_through_unstable_core::unstable_module::NewStableTraitNotAllowedThroughUnstable; //~ ERROR use of unstable library feature `unstable_test_feature` diff --git a/tests/ui/stability-attribute/allowed-through-unstable.stderr b/tests/ui/stability-attribute/allowed-through-unstable.stderr index 8d07b0cf9e8..bda68045002 100644 --- a/tests/ui/stability-attribute/allowed-through-unstable.stderr +++ b/tests/ui/stability-attribute/allowed-through-unstable.stderr @@ -1,13 +1,13 @@ warning: use of deprecated module `allowed_through_unstable_core::unstable_module`: use the new path instead - --> $DIR/allowed-through-unstable.rs:9:53 + --> $DIR/allowed-through-unstable.rs:8:53 | -LL | use allowed_through_unstable_core::unstable_module::OldStableTraitAllowedThoughUnstableWithDeprecation; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | use allowed_through_unstable_core::unstable_module::OldStableTraitAllowedThoughUnstable; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(deprecated)]` on by default error[E0658]: use of unstable library feature `unstable_test_feature` - --> $DIR/allowed-through-unstable.rs:10:5 + --> $DIR/allowed-through-unstable.rs:9:5 | LL | use allowed_through_unstable_core::unstable_module::NewStableTraitNotAllowedThroughUnstable; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/stability-attribute/auxiliary/allowed-through-unstable-core.rs b/tests/ui/stability-attribute/auxiliary/allowed-through-unstable-core.rs index 9dfbb451d04..23c722d6e8e 100644 --- a/tests/ui/stability-attribute/auxiliary/allowed-through-unstable-core.rs +++ b/tests/ui/stability-attribute/auxiliary/allowed-through-unstable-core.rs @@ -6,12 +6,8 @@ #[unstable(feature = "unstable_test_feature", issue = "1")] pub mod unstable_module { #[stable(feature = "stable_test_feature", since = "1.2.0")] - #[rustc_allowed_through_unstable_modules] - pub trait OldStableTraitAllowedThoughUnstable {} - - #[stable(feature = "stable_test_feature", since = "1.2.0")] #[rustc_allowed_through_unstable_modules = "use the new path instead"] - pub trait OldStableTraitAllowedThoughUnstableWithDeprecation {} + pub trait OldStableTraitAllowedThoughUnstable {} #[stable(feature = "stable_test_feature", since = "1.2.0")] pub trait NewStableTraitNotAllowedThroughUnstable {} diff --git a/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr b/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr index 08c744979f5..28427161e87 100644 --- a/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr +++ b/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr @@ -5,7 +5,7 @@ LL | pub desc: &'static dyn Qux, | ^^^^^^^ `Qux` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/unsizing-wfcheck-issue-127299.rs:4:8 | LL | trait Qux { @@ -44,7 +44,7 @@ LL | static FOO: &Lint = &Lint { desc: "desc" }; | ^^^^^^ `Qux` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/unsizing-wfcheck-issue-127299.rs:4:8 | LL | trait Qux { @@ -68,7 +68,7 @@ LL | static FOO: &Lint = &Lint { desc: "desc" }; | ^^^^^^ `Qux` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/unsizing-wfcheck-issue-127299.rs:4:8 | LL | trait Qux { diff --git a/tests/ui/suggestions/box-future-wrong-output.stderr b/tests/ui/suggestions/box-future-wrong-output.stderr index 6a232c3444d..bac26ae8fb5 100644 --- a/tests/ui/suggestions/box-future-wrong-output.stderr +++ b/tests/ui/suggestions/box-future-wrong-output.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/box-future-wrong-output.rs:20:39 | LL | let _: BoxFuture<'static, bool> = async {}.boxed(); - | ------------------------ ^^^^^^^^^^^^^^^^ expected `bool`, found `()` + | ------------------------ ^^^^^^^^^^^^^^^^ expected `Pin<Box<...>>`, found `Pin<Box<dyn Future<Output = ()> + Send>>` | | | expected due to this | diff --git a/tests/ui/suggestions/dont-suggest-boxing-async-closure-body.rs b/tests/ui/suggestions/dont-suggest-boxing-async-closure-body.rs index 47a590668dd..e03c43d15ee 100644 --- a/tests/ui/suggestions/dont-suggest-boxing-async-closure-body.rs +++ b/tests/ui/suggestions/dont-suggest-boxing-async-closure-body.rs @@ -7,6 +7,6 @@ fn bar<X>(x: Box<dyn FnOnce() -> X>) {} fn main() { foo(async move || {}); - //~^ ERROR expected `{async closure@dont-suggest-boxing-async-closure-body.rs:9:9}` to be a closure that returns `Box<_>` + //~^ ERROR expected `{async closure@dont-suggest-boxing-async-closure-body.rs:9:9}` to return `Box<_>` bar(async move || {}); //~ ERROR mismatched types } diff --git a/tests/ui/suggestions/dont-suggest-boxing-async-closure-body.stderr b/tests/ui/suggestions/dont-suggest-boxing-async-closure-body.stderr index db2a3b9a9c1..abf8e2d824b 100644 --- a/tests/ui/suggestions/dont-suggest-boxing-async-closure-body.stderr +++ b/tests/ui/suggestions/dont-suggest-boxing-async-closure-body.stderr @@ -1,4 +1,4 @@ -error[E0271]: expected `{async closure@dont-suggest-boxing-async-closure-body.rs:9:9}` to be a closure that returns `Box<_>`, but it returns `{async closure body@$DIR/dont-suggest-boxing-async-closure-body.rs:9:23: 9:25}` +error[E0271]: expected `{async closure@dont-suggest-boxing-async-closure-body.rs:9:9}` to return `Box<_>`, but it returns `{async closure body@$DIR/dont-suggest-boxing-async-closure-body.rs:9:23: 9:25}` --> $DIR/dont-suggest-boxing-async-closure-body.rs:9:9 | LL | foo(async move || {}); diff --git a/tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr b/tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr index cb0e7fce910..ae009d26029 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr @@ -5,7 +5,7 @@ LL | fn bar(x: &dyn Trait) {} | ^^^^^^^^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/dyn-incompatible-trait-references-self.rs:2:22 | LL | trait Trait { @@ -25,7 +25,7 @@ LL | fn foo(x: &dyn Other) {} | ^^^^^^^^^ `Other` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/dyn-incompatible-trait-references-self.rs:11:14 | LL | trait Other: Sized {} diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr index 2efcad1e7bd..742011ad0c0 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr @@ -18,7 +18,7 @@ LL | fn f(a: dyn A) -> dyn A; | ^^^^^ `A` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:3:10 | LL | trait A: Sized { @@ -46,7 +46,7 @@ LL | fn f(a: dyn B) -> dyn B; | ^^^^^ `B` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:9:8 | LL | trait B { diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr index ecb3ee9185f..843c139851d 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr @@ -18,7 +18,7 @@ LL | fn f(a: A) -> A; | ^ `A` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/dyn-incompatible-trait-should-use-self.rs:2:10 | LL | trait A: Sized { @@ -46,7 +46,7 @@ LL | fn f(a: B) -> B; | ^ `B` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/dyn-incompatible-trait-should-use-self.rs:8:8 | LL | trait B { diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr index 696840d3ba4..e2250807603 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr @@ -5,7 +5,7 @@ LL | fn bar(x: &dyn Trait) {} | ^^^^^^^^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/dyn-incompatible-trait-should-use-where-sized.rs:5:8 | LL | trait Trait { diff --git a/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr b/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr index 42bc094859a..61a1d30d31d 100644 --- a/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr +++ b/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr @@ -32,7 +32,7 @@ error[E0308]: mismatched types LL | fn baz<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> { | - found this type parameter LL | Pin::new(x) - | -------- ^ expected `Box<dyn Future<Output = ...> + Send>`, found type parameter `F` + | -------- ^ expected `Box<dyn Future<Output = i32> + Send>`, found type parameter `F` | | | arguments to this function are incorrect | help: use `Box::pin` to pin and box this expression: `Box::pin` diff --git a/tests/ui/suggestions/issue-107860.stderr b/tests/ui/suggestions/issue-107860.stderr index 4be495da46b..2bfd2193981 100644 --- a/tests/ui/suggestions/issue-107860.stderr +++ b/tests/ui/suggestions/issue-107860.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-107860.rs:3:36 | LL | async fn str<T>(T: &str) -> &str { &str } - | ^^^^ expected `&str`, found `&fn(&str) -> ... {str::<...>}` + | ^^^^ expected `&str`, found `&fn(&str) -> ... {str::<_>}` | = note: expected reference `&str` found reference `&for<'a> fn(&'a str) -> impl Future<Output = &'a str> {str::<_>}` diff --git a/tests/ui/suggestions/issue-116434-2015.stderr b/tests/ui/suggestions/issue-116434-2015.stderr index 508c3ec5e4f..e7b8cd2f101 100644 --- a/tests/ui/suggestions/issue-116434-2015.stderr +++ b/tests/ui/suggestions/issue-116434-2015.stderr @@ -47,7 +47,7 @@ LL | fn foo() -> Clone; | = note: the trait is not dyn compatible because it requires `Self: Sized` = note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> help: there is an associated type with the same name | LL | fn foo() -> Self::Clone; @@ -74,7 +74,7 @@ LL | fn handle() -> DbHandle; | ^^^^^^^^ `DbHandle` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-116434-2015.rs:14:17 | LL | trait DbHandle: Sized {} diff --git a/tests/ui/suggestions/issue-98500.stderr b/tests/ui/suggestions/issue-98500.stderr index 97b712acfcb..ec984c0d60e 100644 --- a/tests/ui/suggestions/issue-98500.stderr +++ b/tests/ui/suggestions/issue-98500.stderr @@ -5,7 +5,7 @@ LL | struct S(Box<dyn B>); | ^^^^^ `B` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/auxiliary/dyn-incompatible.rs:4:8 | LL | fn f(); diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs index dab01179c0b..215e64979f7 100644 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs @@ -1,3 +1,4 @@ +//! Ensure ABI-incompatible features cannot be enabled via `#[target_feature]`. //@ compile-flags: --target=riscv32e-unknown-none-elf --crate-type=lib //@ needs-llvm-components: riscv #![feature(no_core, lang_items, riscv_target_feature)] diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr index 9df56d86729..bfe767e5ffb 100644 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr @@ -1,5 +1,5 @@ error: target feature `d` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI - --> $DIR/forbidden-hardfloat-target-feature-attribute.rs:9:18 + --> $DIR/forbidden-hardfloat-target-feature-attribute.rs:10:18 | LL | #[target_feature(enable = "d")] | ^^^^^^^^^^^^ diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-cfg.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-cfg.rs deleted file mode 100644 index 8755791c1c0..00000000000 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-cfg.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib -//@ needs-llvm-components: x86 -//@ check-pass -#![feature(no_core, lang_items)] -#![no_core] -#![allow(unexpected_cfgs)] - -#[lang = "sized"] -pub trait Sized {} - -// The compile_error macro does not exist, so if the `cfg` evaluates to `true` this -// complains about the missing macro rather than showing the error... but that's good enough. -#[cfg(not(target_feature = "x87"))] -compile_error!("the x87 feature *should* be exposed in `cfg`"); diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.rs index 3d09217327a..81f138b175f 100644 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.rs +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.rs @@ -1,8 +1,11 @@ +//! Ensure that if disabling a target feature implies disabling an ABI-required target feature, +//! we complain. //@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib //@ needs-llvm-components: x86 //@ compile-flags: -Ctarget-feature=-sse // For now this is just a warning. //@ build-pass +//@error-pattern: must be enabled to ensure that the ABI #![feature(no_core, lang_items)] #![no_core] diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.rs index 95c366bb3f5..7242bcc85bf 100644 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.rs +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.rs @@ -3,6 +3,7 @@ //@ compile-flags: -Ctarget-feature=-neon // For now this is just a warning. //@ build-pass +//@error-pattern: must be enabled to ensure that the ABI #![feature(no_core, lang_items)] #![no_core] diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.rs index fd8023664da..7eebcf05dc0 100644 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.rs +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.rs @@ -1,8 +1,10 @@ +//! Ensure ABI-required features cannot be disabled via `-Ctarget-feature`. //@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib //@ needs-llvm-components: x86 //@ compile-flags: -Ctarget-feature=-x87 // For now this is just a warning. //@ build-pass +//@error-pattern: must be enabled to ensure that the ABI #![feature(no_core, lang_items)] #![no_core] diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag.rs new file mode 100644 index 00000000000..f277a309cd6 --- /dev/null +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag.rs @@ -0,0 +1,12 @@ +//! Ensure ABI-incompatible features cannot be enabled via `-Ctarget-feature`. +//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib +//@ needs-llvm-components: x86 +//@ compile-flags: -Ctarget-feature=+soft-float +// For now this is just a warning. +//@ build-pass +//@error-pattern: must be disabled to ensure that the ABI +#![feature(no_core, lang_items, riscv_target_feature)] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag.stderr new file mode 100644 index 00000000000..e49672f33b9 --- /dev/null +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag.stderr @@ -0,0 +1,11 @@ +warning: target feature `soft-float` must be disabled to ensure that the ABI of the current target can be implemented correctly + | + = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344> + +warning: unstable feature specified for `-Ctarget-feature`: `soft-float` + | + = note: this feature is not stably supported; its behavior can change in the future + +warning: 2 warnings emitted + diff --git a/tests/ui/target-feature/forbidden-target-feature-attribute.rs b/tests/ui/target-feature/forbidden-target-feature-attribute.rs index 2ba5f2215c7..6bb6f8aaffb 100644 --- a/tests/ui/target-feature/forbidden-target-feature-attribute.rs +++ b/tests/ui/target-feature/forbidden-target-feature-attribute.rs @@ -1,11 +1,12 @@ -//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib -//@ needs-llvm-components: x86 +//! Ensure "forbidden" target features cannot be enabled via `#[target_feature]`. +//@ compile-flags: --target=riscv32e-unknown-none-elf --crate-type=lib +//@ needs-llvm-components: riscv #![feature(no_core, lang_items)] #![no_core] #[lang = "sized"] pub trait Sized {} -#[target_feature(enable = "soft-float")] +#[target_feature(enable = "forced-atomics")] //~^ERROR: cannot be enabled with pub unsafe fn my_fun() {} diff --git a/tests/ui/target-feature/forbidden-target-feature-attribute.stderr b/tests/ui/target-feature/forbidden-target-feature-attribute.stderr index f3d54cc19d3..f8ea0c0e793 100644 --- a/tests/ui/target-feature/forbidden-target-feature-attribute.stderr +++ b/tests/ui/target-feature/forbidden-target-feature-attribute.stderr @@ -1,8 +1,8 @@ -error: target feature `soft-float` cannot be enabled with `#[target_feature]`: unsound because it changes float ABI - --> $DIR/forbidden-target-feature-attribute.rs:9:18 +error: target feature `forced-atomics` cannot be enabled with `#[target_feature]`: unsound because it changes the ABI of atomic operations + --> $DIR/forbidden-target-feature-attribute.rs:10:18 | -LL | #[target_feature(enable = "soft-float")] - | ^^^^^^^^^^^^^^^^^^^^^ +LL | #[target_feature(enable = "forced-atomics")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/target-feature/forbidden-target-feature-cfg.rs b/tests/ui/target-feature/forbidden-target-feature-cfg.rs index 1f001e9f8ff..e848ffde018 100644 --- a/tests/ui/target-feature/forbidden-target-feature-cfg.rs +++ b/tests/ui/target-feature/forbidden-target-feature-cfg.rs @@ -1,5 +1,6 @@ -//@ compile-flags: --target=x86_64-unknown-none --crate-type=lib -//@ needs-llvm-components: x86 +//! Ensure "forbidden" target features are not exposed via `cfg`. +//@ compile-flags: --target=riscv32e-unknown-none-elf --crate-type=lib +//@ needs-llvm-components: riscv //@ check-pass #![feature(no_core, lang_items)] #![no_core] @@ -10,5 +11,5 @@ pub trait Sized {} // The compile_error macro does not exist, so if the `cfg` evaluates to `true` this // complains about the missing macro rather than showing the error... but that's good enough. -#[cfg(target_feature = "soft-float")] -compile_error!("the soft-float feature should not be exposed in `cfg`"); +#[cfg(target_feature = "forced-atomics")] +compile_error!("the forced-atomics feature should not be exposed in `cfg`"); diff --git a/tests/ui/target-feature/forbidden-target-feature-flag-disable.rs b/tests/ui/target-feature/forbidden-target-feature-flag-disable.rs index b09c53bd46a..cf85c521228 100644 --- a/tests/ui/target-feature/forbidden-target-feature-flag-disable.rs +++ b/tests/ui/target-feature/forbidden-target-feature-flag-disable.rs @@ -1,8 +1,10 @@ -//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib -//@ needs-llvm-components: x86 -//@ compile-flags: -Ctarget-feature=-soft-float +//! Ensure "forbidden" target features cannot be disabled via `-Ctarget-feature`. +//@ compile-flags: --target=riscv32e-unknown-none-elf --crate-type=lib +//@ needs-llvm-components: riscv +//@ compile-flags: -Ctarget-feature=-forced-atomics // For now this is just a warning. //@ build-pass +//@error-pattern: unsound because it changes the ABI #![feature(no_core, lang_items)] #![no_core] diff --git a/tests/ui/target-feature/forbidden-target-feature-flag-disable.stderr b/tests/ui/target-feature/forbidden-target-feature-flag-disable.stderr index 797cd4be5c2..171ed0de6aa 100644 --- a/tests/ui/target-feature/forbidden-target-feature-flag-disable.stderr +++ b/tests/ui/target-feature/forbidden-target-feature-flag-disable.stderr @@ -1,4 +1,4 @@ -warning: target feature `soft-float` cannot be disabled with `-Ctarget-feature`: unsound because it changes float ABI +warning: target feature `forced-atomics` cannot be disabled with `-Ctarget-feature`: unsound because it changes the ABI of atomic operations | = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344> diff --git a/tests/ui/target-feature/forbidden-target-feature-flag.rs b/tests/ui/target-feature/forbidden-target-feature-flag.rs index 0f688fde7f4..245841eb039 100644 --- a/tests/ui/target-feature/forbidden-target-feature-flag.rs +++ b/tests/ui/target-feature/forbidden-target-feature-flag.rs @@ -1,8 +1,10 @@ -//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib -//@ needs-llvm-components: x86 -//@ compile-flags: -Ctarget-feature=+soft-float +//! Ensure "forbidden" target features cannot be enabled via `-Ctarget-feature`. +//@ compile-flags: --target=riscv32e-unknown-none-elf --crate-type=lib +//@ needs-llvm-components: riscv +//@ compile-flags: -Ctarget-feature=+forced-atomics // For now this is just a warning. //@ build-pass +//@error-pattern: unsound because it changes the ABI #![feature(no_core, lang_items)] #![no_core] diff --git a/tests/ui/target-feature/forbidden-target-feature-flag.stderr b/tests/ui/target-feature/forbidden-target-feature-flag.stderr index 075666fbf66..f8490f066d1 100644 --- a/tests/ui/target-feature/forbidden-target-feature-flag.stderr +++ b/tests/ui/target-feature/forbidden-target-feature-flag.stderr @@ -1,4 +1,4 @@ -warning: target feature `soft-float` cannot be enabled with `-Ctarget-feature`: unsound because it changes float ABI +warning: target feature `forced-atomics` cannot be enabled with `-Ctarget-feature`: unsound because it changes the ABI of atomic operations | = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344> diff --git a/tests/ui/target_modifiers/auxiliary/default_reg_struct_return.rs b/tests/ui/target_modifiers/auxiliary/default_reg_struct_return.rs new file mode 100644 index 00000000000..355e7c56e94 --- /dev/null +++ b/tests/ui/target_modifiers/auxiliary/default_reg_struct_return.rs @@ -0,0 +1,20 @@ +//@ compile-flags: --target i686-unknown-linux-gnu -Cpanic=abort +// Auxiliary build problems with aarch64-apple: +// Shared library linking cc seems to convert "-m32" flag into -arch armv4t +// Auxiliary build problems with i686-mingw: linker `cc` not found +//@ only-x86 +//@ ignore-windows +//@ ignore-apple +//@ needs-llvm-components: x86 +#![crate_type = "rlib"] +#![no_core] +#![feature(no_core, lang_items, repr_simd)] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +pub fn somefun() {} + +pub struct S; diff --git a/tests/ui/target_modifiers/auxiliary/wrong_regparm.rs b/tests/ui/target_modifiers/auxiliary/wrong_regparm.rs new file mode 100644 index 00000000000..2e16f1ee747 --- /dev/null +++ b/tests/ui/target_modifiers/auxiliary/wrong_regparm.rs @@ -0,0 +1,20 @@ +//@ compile-flags: --target i686-unknown-linux-gnu -Zregparm=2 -Cpanic=abort +// Auxiliary build problems with aarch64-apple: +// Shared library linking cc seems to convert "-m32" flag into -arch armv4t +// Auxiliary build problems with i686-mingw: linker `cc` not found +//@ only-x86 +//@ ignore-windows +//@ ignore-apple +//@ needs-llvm-components: x86 +#![crate_type = "rlib"] +#![no_core] +#![feature(no_core, lang_items, repr_simd)] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +pub fn somefun() {} + +pub struct S; diff --git a/tests/ui/target_modifiers/auxiliary/wrong_regparm_and_ret.rs b/tests/ui/target_modifiers/auxiliary/wrong_regparm_and_ret.rs new file mode 100644 index 00000000000..39c6be9d589 --- /dev/null +++ b/tests/ui/target_modifiers/auxiliary/wrong_regparm_and_ret.rs @@ -0,0 +1,20 @@ +//@ compile-flags: --target i686-unknown-linux-gnu -Zregparm=2 -Zreg-struct-return=true -Cpanic=abort +// Auxiliary build problems with aarch64-apple: +// Shared library linking cc seems to convert "-m32" flag into -arch armv4t +// Auxiliary build problems with i686-mingw: linker `cc` not found +//@ only-x86 +//@ ignore-windows +//@ ignore-apple +//@ needs-llvm-components: x86 +#![crate_type = "rlib"] +#![no_core] +#![feature(no_core, lang_items, repr_simd)] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +pub fn somefun() {} + +pub struct S; diff --git a/tests/ui/target_modifiers/defaults_check.error.stderr b/tests/ui/target_modifiers/defaults_check.error.stderr new file mode 100644 index 00000000000..c545dd71069 --- /dev/null +++ b/tests/ui/target_modifiers/defaults_check.error.stderr @@ -0,0 +1,13 @@ +error: mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `defaults_check` + --> $DIR/defaults_check.rs:20:1 + | +LL | #![crate_type = "rlib"] + | ^ + | + = help: the `-Zreg-struct-return` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely + = note: `-Zreg-struct-return=true` in this crate is incompatible with `-Zreg-struct-return=` in dependency `default_reg_struct_return` + = help: set `-Zreg-struct-return=` in this crate or `-Zreg-struct-return=true` in `default_reg_struct_return` + = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=reg-struct-return` to silence this error + +error: aborting due to 1 previous error + diff --git a/tests/ui/target_modifiers/defaults_check.rs b/tests/ui/target_modifiers/defaults_check.rs new file mode 100644 index 00000000000..b8f4848d3a4 --- /dev/null +++ b/tests/ui/target_modifiers/defaults_check.rs @@ -0,0 +1,27 @@ +// Tests that default unspecified target modifier value in dependency crate is ok linked +// with the same value, explicitly specified +//@ aux-crate:default_reg_struct_return=default_reg_struct_return.rs +//@ compile-flags: --target i686-unknown-linux-gnu -Cpanic=abort +//@ revisions:error ok ok_explicit +//@[ok] compile-flags: +//@[ok_explicit] compile-flags: -Zreg-struct-return=false +//@[error] compile-flags: -Zreg-struct-return=true + +// Auxiliary build problems with aarch64-apple: +// Shared library linking cc seems to convert "-m32" flag into -arch armv4t +// Auxiliary build problems with i686-mingw: linker `cc` not found +//@ only-x86 +//@ ignore-windows +//@ ignore-apple +//@ needs-llvm-components: x86 +//@[ok] build-pass +//@[ok_explicit] build-pass + +#![crate_type = "rlib"] +//[error]~^ ERROR mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `defaults_check` +#![no_core] +#![feature(no_core, lang_items, repr_simd)] + +fn foo() { + default_reg_struct_return::somefun(); +} diff --git a/tests/ui/target_modifiers/incompatible_regparm.allow_no_value.stderr b/tests/ui/target_modifiers/incompatible_regparm.allow_no_value.stderr new file mode 100644 index 00000000000..8597332825b --- /dev/null +++ b/tests/ui/target_modifiers/incompatible_regparm.allow_no_value.stderr @@ -0,0 +1,2 @@ +error: codegen option `unsafe-allow-abi-mismatch` requires a comma-separated list of strings (C unsafe-allow-abi-mismatch=<value>) + diff --git a/tests/ui/target_modifiers/incompatible_regparm.error_generated.stderr b/tests/ui/target_modifiers/incompatible_regparm.error_generated.stderr new file mode 100644 index 00000000000..692fc7a4e3f --- /dev/null +++ b/tests/ui/target_modifiers/incompatible_regparm.error_generated.stderr @@ -0,0 +1,13 @@ +error: mixing `-Zregparm` will cause an ABI mismatch in crate `incompatible_regparm` + --> $DIR/incompatible_regparm.rs:16:1 + | +LL | #![crate_type = "rlib"] + | ^ + | + = help: the `-Zregparm` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely + = note: `-Zregparm=1` in this crate is incompatible with `-Zregparm=2` in dependency `wrong_regparm` + = help: set `-Zregparm=2` in this crate or `-Zregparm=1` in `wrong_regparm` + = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=regparm` to silence this error + +error: aborting due to 1 previous error + diff --git a/tests/ui/target_modifiers/incompatible_regparm.rs b/tests/ui/target_modifiers/incompatible_regparm.rs new file mode 100644 index 00000000000..e866c5aa891 --- /dev/null +++ b/tests/ui/target_modifiers/incompatible_regparm.rs @@ -0,0 +1,23 @@ +//@ aux-crate:wrong_regparm=wrong_regparm.rs +//@ compile-flags: --target i686-unknown-linux-gnu -Zregparm=1 -Cpanic=abort +// Auxiliary build problems with aarch64-apple: +// Shared library linking cc seems to convert "-m32" flag into -arch armv4t +// Auxiliary build problems with i686-mingw: linker `cc` not found +//@ only-x86 +//@ ignore-windows +//@ ignore-apple +//@ needs-llvm-components: x86 +//@ revisions:error_generated allow_regparm_mismatch allow_no_value + +//@[allow_regparm_mismatch] compile-flags: -Cunsafe-allow-abi-mismatch=regparm +//@[allow_regparm_mismatch] build-pass +//@[allow_no_value] compile-flags: -Cunsafe-allow-abi-mismatch + +#![crate_type = "rlib"] +//[error_generated]~^ ERROR mixing `-Zregparm` will cause an ABI mismatch in crate `incompatible_regparm` +#![no_core] +#![feature(no_core, lang_items, repr_simd)] + +fn foo() { + wrong_regparm::somefun(); +} diff --git a/tests/ui/target_modifiers/two_flags.rs b/tests/ui/target_modifiers/two_flags.rs new file mode 100644 index 00000000000..ca17117a267 --- /dev/null +++ b/tests/ui/target_modifiers/two_flags.rs @@ -0,0 +1,23 @@ +//@ aux-crate:wrong_regparm_and_ret=wrong_regparm_and_ret.rs +//@ compile-flags: --target i686-unknown-linux-gnu -Cpanic=abort +// Auxiliary build problems with aarch64-apple: +// Shared library linking cc seems to convert "-m32" flag into -arch armv4t +// Auxiliary build problems with i686-mingw: linker `cc` not found +//@ only-x86 +//@ ignore-windows +//@ ignore-apple +//@ needs-llvm-components: x86 +//@ revisions:two_allowed unknown_allowed + +//@[two_allowed] compile-flags: -Cunsafe-allow-abi-mismatch=regparm,reg-struct-return +//@[two_allowed] build-pass +//@[unknown_allowed] compile-flags: -Cunsafe-allow-abi-mismatch=unknown_flag -Zregparm=2 -Zreg-struct-return=true + +#![crate_type = "rlib"] +//[unknown_allowed]~^ ERROR unknown target modifier `unknown_flag`, requested by `-Cunsafe-allow-abi-mismatch=unknown_flag` +#![no_core] +#![feature(no_core, lang_items, repr_simd)] + +fn foo() { + wrong_regparm_and_ret::somefun(); +} diff --git a/tests/ui/target_modifiers/two_flags.unknown_allowed.stderr b/tests/ui/target_modifiers/two_flags.unknown_allowed.stderr new file mode 100644 index 00000000000..c8040c6e389 --- /dev/null +++ b/tests/ui/target_modifiers/two_flags.unknown_allowed.stderr @@ -0,0 +1,8 @@ +error: unknown target modifier `unknown_flag`, requested by `-Cunsafe-allow-abi-mismatch=unknown_flag` + --> $DIR/two_flags.rs:16:1 + | +LL | #![crate_type = "rlib"] + | ^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/traits/alias/generic-default-in-dyn.stderr b/tests/ui/traits/alias/generic-default-in-dyn.stderr index 1ab9e6d5c5c..c6f8ab4137b 100644 --- a/tests/ui/traits/alias/generic-default-in-dyn.stderr +++ b/tests/ui/traits/alias/generic-default-in-dyn.stderr @@ -15,7 +15,7 @@ LL | struct Foo<T>(dyn SendEqAlias<T>); | ^^^^^^^^^^^^^^ `SendEqAlias` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/generic-default-in-dyn.rs:1:24 | LL | trait SendEqAlias<T> = PartialEq; @@ -30,7 +30,7 @@ LL | struct Bar<T>(dyn SendEqAlias<T>, T); | ^^^^^^^^^^^^^^ `SendEqAlias` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/generic-default-in-dyn.rs:1:24 | LL | trait SendEqAlias<T> = PartialEq; diff --git a/tests/ui/traits/alias/object-fail.stderr b/tests/ui/traits/alias/object-fail.stderr index 52ce79a4597..d60d8843407 100644 --- a/tests/ui/traits/alias/object-fail.stderr +++ b/tests/ui/traits/alias/object-fail.stderr @@ -5,7 +5,7 @@ LL | let _: &dyn EqAlias = &123; | ^^^^^^^ `EqAlias` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $SRC_DIR/core/src/cmp.rs:LL:COL | = note: ...because it uses `Self` as a type parameter diff --git a/tests/ui/traits/alias/self-in-const-generics.stderr b/tests/ui/traits/alias/self-in-const-generics.stderr index 3c799492591..b5538cb6e2f 100644 --- a/tests/ui/traits/alias/self-in-const-generics.stderr +++ b/tests/ui/traits/alias/self-in-const-generics.stderr @@ -5,7 +5,7 @@ LL | fn foo(x: &dyn BB) {} | ^^ `BB` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/self-in-const-generics.rs:7:12 | LL | trait BB = Bar<{ 2 + 1 }>; diff --git a/tests/ui/traits/alias/self-in-generics.stderr b/tests/ui/traits/alias/self-in-generics.stderr index 5639b2b44a1..afe4dff45ed 100644 --- a/tests/ui/traits/alias/self-in-generics.stderr +++ b/tests/ui/traits/alias/self-in-generics.stderr @@ -5,7 +5,7 @@ LL | pub fn f(_f: &dyn SelfInput) {} | ^^^^^^^^^ `SelfInput` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/self-in-generics.rs:6:23 | LL | pub trait SelfInput = Fn(&mut Self); diff --git a/tests/ui/traits/const-traits/enforce-deref-on-adjust.rs b/tests/ui/traits/const-traits/enforce-deref-on-adjust.rs new file mode 100644 index 00000000000..d5240b7e18d --- /dev/null +++ b/tests/ui/traits/const-traits/enforce-deref-on-adjust.rs @@ -0,0 +1,28 @@ +//@ check-pass + +#![feature(const_deref)] +#![feature(const_trait_impl)] + +use std::ops::Deref; + +struct Wrap<T>(T); +struct Foo; + +impl Foo { + const fn call(&self) {} +} + +impl<T> const Deref for Wrap<T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +const fn foo() { + let x = Wrap(Foo); + x.call(); +} + +fn main() {} diff --git a/tests/ui/traits/ice-with-dyn-pointee-errors.stderr b/tests/ui/traits/ice-with-dyn-pointee-errors.stderr index 8bfda71bac1..5299236026d 100644 --- a/tests/ui/traits/ice-with-dyn-pointee-errors.stderr +++ b/tests/ui/traits/ice-with-dyn-pointee-errors.stderr @@ -2,7 +2,7 @@ error[E0271]: type mismatch resolving `<dyn Pointee<Metadata = ()> as Pointee>:: --> $DIR/ice-with-dyn-pointee-errors.rs:9:33 | LL | unknown_sized_object_ptr_in(x) - | --------------------------- ^ expected `()`, found `DynMetadata<dyn Pointee<Metadata = ...>>` + | --------------------------- ^ expected `()`, found `DynMetadata<dyn Pointee<Metadata = ()>>` | | | required by a bound introduced by this call | diff --git a/tests/ui/traits/issue-20692.stderr b/tests/ui/traits/issue-20692.stderr index 50ea7cde961..32e29de49a1 100644 --- a/tests/ui/traits/issue-20692.stderr +++ b/tests/ui/traits/issue-20692.stderr @@ -5,7 +5,7 @@ LL | &dyn Array; | ^^^^^^^^^^ `Array` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-20692.rs:1:14 | LL | trait Array: Sized + Copy {} @@ -21,7 +21,7 @@ LL | let _ = x | ^ `Array` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-20692.rs:1:14 | LL | trait Array: Sized + Copy {} diff --git a/tests/ui/traits/issue-28576.stderr b/tests/ui/traits/issue-28576.stderr index ba113d573d6..ba61ce98554 100644 --- a/tests/ui/traits/issue-28576.stderr +++ b/tests/ui/traits/issue-28576.stderr @@ -27,7 +27,7 @@ LL | | <Assoc=()> | |________________________^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-28576.rs:5:16 | LL | pub trait Bar: Foo<Assoc=()> { diff --git a/tests/ui/traits/issue-38404.stderr b/tests/ui/traits/issue-38404.stderr index f9e592255dd..63269d3379e 100644 --- a/tests/ui/traits/issue-38404.stderr +++ b/tests/ui/traits/issue-38404.stderr @@ -5,7 +5,7 @@ LL | trait C<T>: A<dyn B<T, Output = usize>> {} | ^^^^^^^^^^^^^^^^^^^^ `B` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-38404.rs:1:13 | LL | trait A<T>: std::ops::Add<Self> + Sized {} @@ -20,7 +20,7 @@ LL | trait C<T>: A<dyn B<T, Output = usize>> {} | ^^^^^^^^^^^^^^^^^^^^ `B` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-38404.rs:1:13 | LL | trait A<T>: std::ops::Add<Self> + Sized {} @@ -36,7 +36,7 @@ LL | trait C<T>: A<dyn B<T, Output = usize>> {} | ^^^^^^^^^^^^^^^^^^^^ `B` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-38404.rs:1:13 | LL | trait A<T>: std::ops::Add<Self> + Sized {} diff --git a/tests/ui/traits/issue-38604.stderr b/tests/ui/traits/issue-38604.stderr index 94f9c1540ad..e6a6b44e730 100644 --- a/tests/ui/traits/issue-38604.stderr +++ b/tests/ui/traits/issue-38604.stderr @@ -5,7 +5,7 @@ LL | let _f: Box<dyn Foo> = | ^^^^^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-38604.rs:2:22 | LL | trait Foo where u32: Q<Self> { @@ -21,7 +21,7 @@ LL | Box::new(()); | ^^^^^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-38604.rs:2:22 | LL | trait Foo where u32: Q<Self> { diff --git a/tests/ui/traits/issue-72410.stderr b/tests/ui/traits/issue-72410.stderr index 002345bff84..c9e133437dd 100644 --- a/tests/ui/traits/issue-72410.stderr +++ b/tests/ui/traits/issue-72410.stderr @@ -5,7 +5,7 @@ LL | where for<'a> &'a mut [dyn Bar]: ; | ^^^^^^^^^^^^^^^^^ `Bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-72410.rs:13:8 | LL | pub trait Bar { diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr index c97158a5b76..58c558d6685 100644 --- a/tests/ui/traits/item-privacy.stderr +++ b/tests/ui/traits/item-privacy.stderr @@ -143,7 +143,7 @@ LL | <dyn C>::A; | ^^^^^ `assoc_const::C` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/item-privacy.rs:25:15 | LL | const A: u8 = 0; diff --git a/tests/ui/traits/missing-for-type-in-impl.e2015.stderr b/tests/ui/traits/missing-for-type-in-impl.e2015.stderr index 682d18842b8..c8a1329e3d0 100644 --- a/tests/ui/traits/missing-for-type-in-impl.e2015.stderr +++ b/tests/ui/traits/missing-for-type-in-impl.e2015.stderr @@ -41,7 +41,7 @@ LL | impl Foo<i64> { | ^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/missing-for-type-in-impl.rs:4:8 | LL | trait Foo<T> { diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr index 377dfc8b529..425f2d59222 100644 --- a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr +++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot normalize `X::{constant#0}` +error[E0284]: type annotations needed: cannot satisfy `the constant `{ || {} }` can be evaluated` --> $DIR/const-region-infer-to-static-in-binder.rs:4:10 | LL | struct X<const FN: fn() = { || {} }>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `X::{constant#0}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `{ || {} }` can be evaluated` error: using function pointers as const generic parameters is forbidden --> $DIR/const-region-infer-to-static-in-binder.rs:4:20 diff --git a/tests/ui/traits/next-solver/specialization-transmute.stderr b/tests/ui/traits/next-solver/specialization-transmute.stderr index b96bfab927d..2d0c503bc95 100644 --- a/tests/ui/traits/next-solver/specialization-transmute.stderr +++ b/tests/ui/traits/next-solver/specialization-transmute.stderr @@ -10,11 +10,11 @@ LL | #![feature(specialization)] error: cannot normalize `<T as Default>::Id: '_` -error[E0284]: type annotations needed: cannot normalize `<T as Default>::Id` +error[E0282]: type annotations needed --> $DIR/specialization-transmute.rs:15:23 | LL | fn intu(&self) -> &Self::Id { - | ^^^^^^^^^ cannot normalize `<T as Default>::Id` + | ^^^^^^^^^ cannot infer type for reference `&<T as Default>::Id` error[E0284]: type annotations needed: cannot satisfy `<T as Default>::Id normalizes-to T` --> $DIR/specialization-transmute.rs:17:9 @@ -36,4 +36,5 @@ LL | fn transmute<T: Default<Id = U>, U: Copy>(t: T) -> U { error: aborting due to 4 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0284`. +Some errors have detailed explanations: E0282, E0284. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr index 8448890c084..43b69d0b50e 100644 --- a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr +++ b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr @@ -14,7 +14,7 @@ LL | let x: &dyn Foo = &(); | ^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/supertrait-dyn-compatibility.rs:4:12 | LL | trait Foo: for<T> Bar<T> {} @@ -31,7 +31,7 @@ LL | let x: &dyn Foo = &(); | ^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/supertrait-dyn-compatibility.rs:4:12 | LL | trait Foo: for<T> Bar<T> {} @@ -47,7 +47,7 @@ LL | needs_bar(x); | ^^^^^^^^^ `Foo` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/supertrait-dyn-compatibility.rs:4:12 | LL | trait Foo: for<T> Bar<T> {} diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs b/tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs index 2a301788525..2a301788525 100644 --- a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs +++ b/tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder-in-constraint.rs diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr b/tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr index 38dcdbd0af2..38dcdbd0af2 100644 --- a/tests/ui/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr +++ b/tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder-in-constraint.stderr diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs b/tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder.rs index 23f3666618b..23f3666618b 100644 --- a/tests/ui/type-alias-impl-trait/non-lifetime-binder.rs +++ b/tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder.rs diff --git a/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr b/tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder.stderr index 3c352c9889c..3c352c9889c 100644 --- a/tests/ui/type-alias-impl-trait/non-lifetime-binder.stderr +++ b/tests/ui/traits/non_lifetime_binders/type-alias-impl-trait/non-lifetime-binder.stderr diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr index ae3762704c6..b4bbd65b2f4 100644 --- a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr +++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr @@ -20,7 +20,7 @@ LL | let b: &dyn FromResidual = &(); | ^^^ `FromResidual` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:2:8 | LL | trait FromResidual<R = <Self as Try>::Residual> { @@ -44,7 +44,7 @@ LL | let b: &dyn FromResidual = &(); | ^^^^^^^^^^^^^^^^^ `FromResidual` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:2:8 | LL | trait FromResidual<R = <Self as Try>::Residual> { diff --git a/tests/ui/traits/object/macro-matcher.stderr b/tests/ui/traits/object/macro-matcher.stderr index ab0fc213c9f..3c668ce99c7 100644 --- a/tests/ui/traits/object/macro-matcher.stderr +++ b/tests/ui/traits/object/macro-matcher.stderr @@ -12,7 +12,7 @@ LL | m!(dyn Copy + Send + 'static); | = note: the trait is not dyn compatible because it requires `Self: Sized` = note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> error: aborting due to 2 previous errors diff --git a/tests/ui/traits/object/pretty.stderr b/tests/ui/traits/object/pretty.stderr index af941e69c5f..2f9fdf151f0 100644 --- a/tests/ui/traits/object/pretty.stderr +++ b/tests/ui/traits/object/pretty.stderr @@ -110,7 +110,7 @@ error[E0308]: mismatched types --> $DIR/pretty.rs:36:79 | LL | fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x } - | - ^ expected `()`, found `&dyn FixedGeneric1<'a, Assoc2 = ...>` + | - ^ expected `()`, found `&dyn FixedGeneric1<'a, Assoc2 = &u8>` | | | help: try adding a return type: `-> &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>` | @@ -132,7 +132,7 @@ error[E0308]: mismatched types --> $DIR/pretty.rs:38:73 | LL | fn dyn_any_different_binders(x: &dyn AnyDifferentBinders<Assoc = u8>) { x } - | - ^ expected `()`, found `&dyn AnyDifferentBinders<Assoc = ...>` + | - ^ expected `()`, found `&dyn AnyDifferentBinders<Assoc = u8>` | | | help: try adding a return type: `-> &dyn AnyDifferentBinders<Assoc = u8>` | diff --git a/tests/ui/traits/object/print_vtable_sizes.rs b/tests/ui/traits/object/print_vtable_sizes.rs deleted file mode 100644 index 2b1745da5f3..00000000000 --- a/tests/ui/traits/object/print_vtable_sizes.rs +++ /dev/null @@ -1,62 +0,0 @@ -//@ check-pass -//@ compile-flags: -Z print-vtable-sizes -#![crate_type = "lib"] - -trait A<T: help::V>: AsRef<[T::V]> + AsMut<[T::V]> {} - -trait B<T>: AsRef<T> + AsRef<T> + AsRef<T> + AsRef<T> {} - -trait C { - fn x() {} // not dyn-compatible, shouldn't be reported -} - -// This does not have any upcasting cost, -// because both `Send` and `Sync` are traits -// with no methods -trait D: Send + Sync + help::MarkerWithSuper {} - -// This can't have no cost without reordering, -// because `Super::f`. -trait E: help::MarkerWithSuper + Send + Sync {} - -trait F { - fn a(&self); - fn b(&self); - fn c(&self); - - fn d() -> Self - where - Self: Sized; -} - -trait G: AsRef<u8> + AsRef<u16> + help::MarkerWithSuper { - fn a(&self); - fn b(&self); - fn c(&self); - fn d(&self); - fn e(&self); - - fn f() -> Self - where - Self: Sized; -} - -// Traits with the same name -const _: () = { - trait S {} -}; -const _: () = { - trait S {} -}; - -mod help { - pub trait V { - type V; - } - - pub trait MarkerWithSuper: Super {} - - pub trait Super { - fn f(&self); - } -} diff --git a/tests/ui/traits/object/print_vtable_sizes.stdout b/tests/ui/traits/object/print_vtable_sizes.stdout deleted file mode 100644 index 4daf4769576..00000000000 --- a/tests/ui/traits/object/print_vtable_sizes.stdout +++ /dev/null @@ -1,11 +0,0 @@ -print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "A", "entries": "6", "entries_ignoring_upcasting": "5", "entries_for_upcasting": "1", "upcasting_cost_percent": "20" } -print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "G", "entries": "13", "entries_ignoring_upcasting": "11", "entries_for_upcasting": "2", "upcasting_cost_percent": "18.181818181818183" } -print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "B", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" } -print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "D", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" } -print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "E", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" } -print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "F", "entries": "6", "entries_ignoring_upcasting": "6", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" } -print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "_::S", "entries": "3", "entries_ignoring_upcasting": "3", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" } -print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "_::S", "entries": "3", "entries_ignoring_upcasting": "3", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" } -print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "help::MarkerWithSuper", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" } -print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "help::Super", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" } -print-vtable-sizes { "crate_name": "print_vtable_sizes", "trait_name": "help::V", "entries": "3", "entries_ignoring_upcasting": "3", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" } diff --git a/tests/ui/traits/object/safety.stderr b/tests/ui/traits/object/safety.stderr index eab59f39c28..593e42619f4 100644 --- a/tests/ui/traits/object/safety.stderr +++ b/tests/ui/traits/object/safety.stderr @@ -5,7 +5,7 @@ LL | let _: &dyn Tr = &St; | ^^^ `Tr` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/safety.rs:4:8 | LL | trait Tr { @@ -30,7 +30,7 @@ LL | let _: &dyn Tr = &St; | ^^^^^^^ `Tr` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/safety.rs:4:8 | LL | trait Tr { diff --git a/tests/ui/traits/on_unimplemented_long_types.rs b/tests/ui/traits/on_unimplemented_long_types.rs index 98749b8db7a..c652b71e51a 100644 --- a/tests/ui/traits/on_unimplemented_long_types.rs +++ b/tests/ui/traits/on_unimplemented_long_types.rs @@ -1,5 +1,6 @@ //@ compile-flags: --diagnostic-width=60 -Z write-long-types-to-disk=yes -//@ normalize-stderr: "long-type-\d+" -> "long-type-hash" +// The regex below normalizes the long type file name to make it suitable for compare-modes. +//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type-\d+.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type-hash.txt'" pub fn foo() -> impl std::fmt::Display { //~^ ERROR doesn't implement `std::fmt::Display` diff --git a/tests/ui/traits/on_unimplemented_long_types.stderr b/tests/ui/traits/on_unimplemented_long_types.stderr index bddc5695696..2705d7c501e 100644 --- a/tests/ui/traits/on_unimplemented_long_types.stderr +++ b/tests/ui/traits/on_unimplemented_long_types.stderr @@ -1,5 +1,5 @@ error[E0277]: `Option<Option<Option<...>>>` doesn't implement `std::fmt::Display` - --> $DIR/on_unimplemented_long_types.rs:4:17 + --> $DIR/on_unimplemented_long_types.rs:5:17 | LL | pub fn foo() -> impl std::fmt::Display { | ^^^^^^^^^^^^^^^^^^^^^^ `Option<Option<Option<...>>>` cannot be formatted with the default formatter @@ -13,11 +13,9 @@ LL | | ))))))))))), LL | | ))))))))))) | |_______________- return type was inferred to be `Option<Option<Option<...>>>` here | - = note: the full name for the type has been written to '$TEST_BUILD_DIR/traits/on_unimplemented_long_types/on_unimplemented_long_types.long-type-hash.txt' - = note: consider using `--verbose` to print the full type name to the console = help: the trait `std::fmt::Display` is not implemented for `Option<Option<Option<...>>>` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead - = note: the full name for the type has been written to '$TEST_BUILD_DIR/traits/on_unimplemented_long_types/on_unimplemented_long_types.long-type-hash.txt' + = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console error: aborting due to 1 previous error diff --git a/tests/ui/traits/sized-coniductive.rs b/tests/ui/traits/sized-coniductive.rs deleted file mode 100644 index 5f63b166f98..00000000000 --- a/tests/ui/traits/sized-coniductive.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ check-pass -// https://github.com/rust-lang/rust/issues/129541 - -#[derive(Clone)] -struct Test { - field: std::borrow::Cow<'static, [Self]>, -} - -#[derive(Clone)] -struct Hello { - a: <[Hello] as std::borrow::ToOwned>::Owned, -} - -fn main(){} diff --git a/tests/ui/traits/solver-cycles/129541-recursive-struct-and-array-impl.rs b/tests/ui/traits/solver-cycles/129541-recursive-struct-and-array-impl.rs deleted file mode 100644 index defb39aae06..00000000000 --- a/tests/ui/traits/solver-cycles/129541-recursive-struct-and-array-impl.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Regression test for #129541 - -//@ check-pass - -trait Bound {} -trait Normalize { - type Assoc; -} - -impl<T: Bound> Normalize for T { - type Assoc = T; -} - -impl<T: Bound> Normalize for [T] { - type Assoc = T; -} - -impl Bound for Hello {} -struct Hello { - a: <[Hello] as Normalize>::Assoc, -} - -fn main() {} diff --git a/tests/ui/traits/solver-cycles/129541-recursive-struct.rs b/tests/ui/traits/solver-cycles/129541-recursive-struct.rs index d4339dd54d6..4fbcbefec91 100644 --- a/tests/ui/traits/solver-cycles/129541-recursive-struct.rs +++ b/tests/ui/traits/solver-cycles/129541-recursive-struct.rs @@ -1,5 +1,6 @@ // Regression test for #129541 +//@ revisions: unique multiple //@ check-pass trait Bound {} @@ -7,6 +8,10 @@ trait Normalize { type Assoc; } +#[cfg(multiple)] +impl<T: Bound> Normalize for T { + type Assoc = T; +} impl<T: Bound> Normalize for [T] { type Assoc = T; } diff --git a/tests/ui/traits/test-2.stderr b/tests/ui/traits/test-2.stderr index 8915e490b4d..6a6cb503aa4 100644 --- a/tests/ui/traits/test-2.stderr +++ b/tests/ui/traits/test-2.stderr @@ -33,7 +33,7 @@ LL | (Box::new(10) as Box<dyn bar>).dup(); | ^^^^^^^^^^^^ `bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/test-2.rs:4:30 | LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); } @@ -56,7 +56,7 @@ LL | (Box::new(10) as Box<dyn bar>).dup(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/test-2.rs:4:30 | LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); } @@ -79,7 +79,7 @@ LL | (Box::new(10) as Box<dyn bar>).dup(); | ^^^^^^^^^^^^ `bar` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/test-2.rs:4:30 | LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); } diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder-vtable.rs b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder-vtable.rs new file mode 100644 index 00000000000..796ddec46ac --- /dev/null +++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder-vtable.rs @@ -0,0 +1,27 @@ +#![feature(rustc_attrs)] + +// Test for <https://github.com/rust-lang/rust/issues/135316>. + +trait Supertrait<T> { + fn _print_numbers(&self, mem: &[usize; 100]) { + } +} +impl<T> Supertrait<T> for () {} + +trait Trait<T, U>: Supertrait<T> + Supertrait<U> { + fn say_hello(&self, _: &usize) { + } +} +impl<T, U> Trait<T, U> for () {} + +// We should observe compatibility between these two vtables. + +#[rustc_dump_vtable] +type First = dyn for<'a> Trait<&'static (), &'a ()>; +//~^ ERROR vtable entries + +#[rustc_dump_vtable] +type Second = dyn Trait<&'static (), &'static ()>; +//~^ ERROR vtable entries + +fn main() {} diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder-vtable.stderr b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder-vtable.stderr new file mode 100644 index 00000000000..24fa1650ca1 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder-vtable.stderr @@ -0,0 +1,26 @@ +error: vtable entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(<dyn for<'a> Trait<&(), &'a ()> as Supertrait<&()>>::_print_numbers - shim(reify)), + Method(<dyn for<'a> Trait<&(), &'a ()> as Trait<&(), &()>>::say_hello - shim(reify)), + ] + --> $DIR/multiple-supertraits-modulo-binder-vtable.rs:20:1 + | +LL | type First = dyn for<'a> Trait<&'static (), &'a ()>; + | ^^^^^^^^^^ + +error: vtable entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(<dyn Trait<&(), &()> as Supertrait<&()>>::_print_numbers - shim(reify)), + Method(<dyn Trait<&(), &()> as Trait<&(), &()>>::say_hello - shim(reify)), + ] + --> $DIR/multiple-supertraits-modulo-binder-vtable.rs:24:1 + | +LL | type Second = dyn Trait<&'static (), &'static ()>; + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.rs b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.rs new file mode 100644 index 00000000000..510a1471af2 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.rs @@ -0,0 +1,26 @@ +//@ run-pass +//@ check-run-results + +// Test for <https://github.com/rust-lang/rust/issues/135316>. + +#![feature(trait_upcasting)] + +trait Supertrait<T> { + fn _print_numbers(&self, mem: &[usize; 100]) { + println!("{mem:?}"); + } +} +impl<T> Supertrait<T> for () {} + +trait Trait<T, U>: Supertrait<T> + Supertrait<U> { + fn say_hello(&self, _: &usize) { + println!("Hello!"); + } +} +impl<T, U> Trait<T, U> for () {} + +fn main() { + (&() as &'static dyn for<'a> Trait<&'static (), &'a ()> + as &'static dyn Trait<&'static (), &'static ()>) + .say_hello(&0); +} diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.run.stdout b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.run.stdout new file mode 100644 index 00000000000..10ddd6d257e --- /dev/null +++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-binder.run.stdout @@ -0,0 +1 @@ +Hello! diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.rs b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.rs new file mode 100644 index 00000000000..69a71859a5c --- /dev/null +++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.rs @@ -0,0 +1,37 @@ +#![feature(rustc_attrs)] +#![feature(trait_upcasting)] + +// Test for <https://github.com/rust-lang/rust/issues/135315>. + +trait Supertrait<T> { + fn _print_numbers(&self, mem: &[usize; 100]) { + println!("{mem:?}"); + } +} +impl<T> Supertrait<T> for () {} + +trait Identity { + type Selff; +} +impl<Selff> Identity for Selff { + type Selff = Selff; +} + +trait Middle<T>: Supertrait<()> + Supertrait<T> { + fn say_hello(&self, _: &usize) { + println!("Hello!"); + } +} +impl<T> Middle<T> for () {} + +trait Trait: Middle<<() as Identity>::Selff> {} + +#[rustc_dump_vtable] +impl Trait for () {} +//~^ ERROR vtable entries + +#[rustc_dump_vtable] +type Virtual = dyn Middle<()>; +//~^ ERROR vtable entries + +fn main() {} diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.stderr b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.stderr new file mode 100644 index 00000000000..757e2dc6939 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization-vtable.stderr @@ -0,0 +1,26 @@ +error: vtable entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(<() as Supertrait<()>>::_print_numbers), + Method(<() as Middle<()>>::say_hello), + ] + --> $DIR/multiple-supertraits-modulo-normalization-vtable.rs:30:1 + | +LL | impl Trait for () {} + | ^^^^^^^^^^^^^^^^^ + +error: vtable entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(<dyn Middle<()> as Supertrait<()>>::_print_numbers - shim(reify)), + Method(<dyn Middle<()> as Middle<()>>::say_hello - shim(reify)), + ] + --> $DIR/multiple-supertraits-modulo-normalization-vtable.rs:34:1 + | +LL | type Virtual = dyn Middle<()>; + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization.rs b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization.rs new file mode 100644 index 00000000000..c744e6e64f5 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization.rs @@ -0,0 +1,34 @@ +//@ run-pass +//@ check-run-results + +#![feature(trait_upcasting)] + +// Test for <https://github.com/rust-lang/rust/issues/135315>. + +trait Supertrait<T> { + fn _print_numbers(&self, mem: &[usize; 100]) { + println!("{mem:?}"); + } +} +impl<T> Supertrait<T> for () {} + +trait Identity { + type Selff; +} +impl<Selff> Identity for Selff { + type Selff = Selff; +} + +trait Middle<T>: Supertrait<()> + Supertrait<T> { + fn say_hello(&self, _: &usize) { + println!("Hello!"); + } +} +impl<T> Middle<T> for () {} + +trait Trait: Middle<<() as Identity>::Selff> {} +impl Trait for () {} + +fn main() { + (&() as &dyn Trait as &dyn Middle<()>).say_hello(&0); +} diff --git a/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization.run.stdout b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization.run.stdout new file mode 100644 index 00000000000..10ddd6d257e --- /dev/null +++ b/tests/ui/traits/trait-upcasting/multiple-supertraits-modulo-normalization.run.stdout @@ -0,0 +1 @@ +Hello! diff --git a/tests/ui/traits/trait-upcasting/supertraits-modulo-inner-binder.rs b/tests/ui/traits/trait-upcasting/supertraits-modulo-inner-binder.rs new file mode 100644 index 00000000000..6cd74b6c7f7 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/supertraits-modulo-inner-binder.rs @@ -0,0 +1,30 @@ +//@ run-pass + +#![feature(trait_upcasting)] + +trait Super<U> { + fn call(&self) + where + U: HigherRanked, + { + } +} + +impl<T> Super<T> for () {} + +trait HigherRanked {} +impl HigherRanked for for<'a> fn(&'a ()) {} + +trait Unimplemented {} +impl<T: Unimplemented> HigherRanked for T {} + +trait Sub: Super<fn(&'static ())> + Super<for<'a> fn(&'a ())> {} +impl Sub for () {} + +fn main() { + let a: &dyn Sub = &(); + // `Super<fn(&'static ())>` and `Super<for<'a> fn(&'a ())>` have different + // vtables and we need to upcast to the latter! + let b: &dyn Super<for<'a> fn(&'a ())> = a; + b.call(); +} diff --git a/tests/ui/traits/vtable/multiple-markers.rs b/tests/ui/traits/vtable/multiple-markers.rs index 8a9e7a006cf..8eba5135582 100644 --- a/tests/ui/traits/vtable/multiple-markers.rs +++ b/tests/ui/traits/vtable/multiple-markers.rs @@ -2,8 +2,7 @@ // // This test makes sure that multiple marker (method-less) traits can reuse the // same pointer for upcasting. -// -//@ build-fail + #![crate_type = "lib"] #![feature(rustc_attrs)] @@ -17,17 +16,13 @@ trait T { fn method(&self) {} } -#[rustc_dump_vtable] -trait A: M0 + M1 + M2 + T {} //~ error: vtable entries for `<S as A>`: +trait A: M0 + M1 + M2 + T {} -#[rustc_dump_vtable] -trait B: M0 + M1 + T + M2 {} //~ error: vtable entries for `<S as B>`: +trait B: M0 + M1 + T + M2 {} -#[rustc_dump_vtable] -trait C: M0 + T + M1 + M2 {} //~ error: vtable entries for `<S as C>`: +trait C: M0 + T + M1 + M2 {} -#[rustc_dump_vtable] -trait D: T + M0 + M1 + M2 {} //~ error: vtable entries for `<S as D>`: +trait D: T + M0 + M1 + M2 {} struct S; @@ -35,13 +30,21 @@ impl M0 for S {} impl M1 for S {} impl M2 for S {} impl T for S {} + +#[rustc_dump_vtable] impl A for S {} +//~^ ERROR vtable entries + +#[rustc_dump_vtable] impl B for S {} +//~^ ERROR vtable entries + +#[rustc_dump_vtable] impl C for S {} -impl D for S {} +//~^ ERROR vtable entries -pub fn require_vtables() { - fn require_vtables(_: &dyn A, _: &dyn B, _: &dyn C, _: &dyn D) {} +#[rustc_dump_vtable] +impl D for S {} +//~^ ERROR vtable entries - require_vtables(&S, &S, &S, &S) -} +fn main() {} diff --git a/tests/ui/traits/vtable/multiple-markers.stderr b/tests/ui/traits/vtable/multiple-markers.stderr index 36ac8b24eb5..35dd3c2516d 100644 --- a/tests/ui/traits/vtable/multiple-markers.stderr +++ b/tests/ui/traits/vtable/multiple-markers.stderr @@ -1,46 +1,46 @@ -error: vtable entries for `<S as A>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, Method(<S as T>::method), ] - --> $DIR/multiple-markers.rs:21:1 + --> $DIR/multiple-markers.rs:35:1 | -LL | trait A: M0 + M1 + M2 + T {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl A for S {} + | ^^^^^^^^^^^^ -error: vtable entries for `<S as B>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, Method(<S as T>::method), ] - --> $DIR/multiple-markers.rs:24:1 + --> $DIR/multiple-markers.rs:39:1 | -LL | trait B: M0 + M1 + T + M2 {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl B for S {} + | ^^^^^^^^^^^^ -error: vtable entries for `<S as C>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, Method(<S as T>::method), ] - --> $DIR/multiple-markers.rs:27:1 + --> $DIR/multiple-markers.rs:43:1 | -LL | trait C: M0 + T + M1 + M2 {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl C for S {} + | ^^^^^^^^^^^^ -error: vtable entries for `<S as D>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, Method(<S as T>::method), ] - --> $DIR/multiple-markers.rs:30:1 + --> $DIR/multiple-markers.rs:47:1 | -LL | trait D: T + M0 + M1 + M2 {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl D for S {} + | ^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/tests/ui/traits/vtable/vtable-diamond.rs b/tests/ui/traits/vtable/vtable-diamond.rs index 2cfa86c526d..56053f6d026 100644 --- a/tests/ui/traits/vtable/vtable-diamond.rs +++ b/tests/ui/traits/vtable/vtable-diamond.rs @@ -1,44 +1,37 @@ -//@ build-fail #![feature(rustc_attrs)] -#[rustc_dump_vtable] trait A { fn foo_a(&self) {} } -#[rustc_dump_vtable] trait B: A { fn foo_b(&self) {} } -#[rustc_dump_vtable] trait C: A { - //~^ error vtable fn foo_c(&self) {} } -#[rustc_dump_vtable] trait D: B + C { - //~^ error vtable fn foo_d(&self) {} } struct S; +#[rustc_dump_vtable] impl A for S {} +//~^ ERROR vtable entries + +#[rustc_dump_vtable] impl B for S {} -impl C for S {} -impl D for S {} +//~^ ERROR vtable entries -fn foo(d: &dyn D) { - d.foo_d(); -} +#[rustc_dump_vtable] +impl C for S {} +//~^ ERROR vtable entries -fn bar(d: &dyn C) { - d.foo_c(); -} +#[rustc_dump_vtable] +impl D for S {} +//~^ ERROR vtable entries -fn main() { - foo(&S); - bar(&S); -} +fn main() {} diff --git a/tests/ui/traits/vtable/vtable-diamond.stderr b/tests/ui/traits/vtable/vtable-diamond.stderr index f3718c5d852..4644bf339b1 100644 --- a/tests/ui/traits/vtable/vtable-diamond.stderr +++ b/tests/ui/traits/vtable/vtable-diamond.stderr @@ -1,29 +1,52 @@ -error: vtable entries for `<S as D>`: [ +error: vtable entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(<S as A>::foo_a), + ] + --> $DIR/vtable-diamond.rs:22:1 + | +LL | impl A for S {} + | ^^^^^^^^^^^^ + +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, Method(<S as A>::foo_a), Method(<S as B>::foo_b), + ] + --> $DIR/vtable-diamond.rs:26:1 + | +LL | impl B for S {} + | ^^^^^^^^^^^^ + +error: vtable entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(<S as A>::foo_a), Method(<S as C>::foo_c), - TraitVPtr(<S as C>), - Method(<S as D>::foo_d), ] - --> $DIR/vtable-diamond.rs:21:1 + --> $DIR/vtable-diamond.rs:30:1 | -LL | trait D: B + C { - | ^^^^^^^^^^^^^^ +LL | impl C for S {} + | ^^^^^^^^^^^^ -error: vtable entries for `<S as C>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, Method(<S as A>::foo_a), + Method(<S as B>::foo_b), Method(<S as C>::foo_c), + TraitVPtr(<S as C>), + Method(<S as D>::foo_d), ] - --> $DIR/vtable-diamond.rs:15:1 + --> $DIR/vtable-diamond.rs:34:1 | -LL | trait C: A { - | ^^^^^^^^^^ +LL | impl D for S {} + | ^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/traits/vtable/vtable-dyn-incompatible.rs b/tests/ui/traits/vtable/vtable-dyn-incompatible.rs index 64a8138bdcf..fb19dec4ace 100644 --- a/tests/ui/traits/vtable/vtable-dyn-incompatible.rs +++ b/tests/ui/traits/vtable/vtable-dyn-incompatible.rs @@ -1,15 +1,16 @@ -//@ build-fail #![feature(rustc_attrs)] // Ensure that dyn-incompatible methods in Iterator does not generate // vtable entries. -#[rustc_dump_vtable] trait A: Iterator {} -//~^ error vtable impl<T> A for T where T: Iterator {} +#[rustc_dump_vtable] +type Test = dyn A<Item=u8>; +//~^ error vtable + fn foo(_a: &mut dyn A<Item=u8>) { } diff --git a/tests/ui/traits/vtable/vtable-dyn-incompatible.stderr b/tests/ui/traits/vtable/vtable-dyn-incompatible.stderr index e442c3eac00..c80a763998b 100644 --- a/tests/ui/traits/vtable/vtable-dyn-incompatible.stderr +++ b/tests/ui/traits/vtable/vtable-dyn-incompatible.stderr @@ -1,16 +1,16 @@ -error: vtable entries for `<std::vec::IntoIter<u8> as A>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, - Method(<std::vec::IntoIter<u8> as Iterator>::next), - Method(<std::vec::IntoIter<u8> as Iterator>::size_hint), - Method(<std::vec::IntoIter<u8> as Iterator>::advance_by), - Method(<std::vec::IntoIter<u8> as Iterator>::nth), + Method(<dyn A<Item = u8> as Iterator>::next - shim(reify)), + Method(<dyn A<Item = u8> as Iterator>::size_hint - shim(reify)), + Method(<dyn A<Item = u8> as Iterator>::advance_by - shim(reify)), + Method(<dyn A<Item = u8> as Iterator>::nth - shim(reify)), ] - --> $DIR/vtable-dyn-incompatible.rs:8:1 + --> $DIR/vtable-dyn-incompatible.rs:11:1 | -LL | trait A: Iterator {} - | ^^^^^^^^^^^^^^^^^ +LL | type Test = dyn A<Item=u8>; + | ^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/traits/vtable/vtable-multi-level.rs b/tests/ui/traits/vtable/vtable-multi-level.rs index bedbf84d303..67bac49f9f6 100644 --- a/tests/ui/traits/vtable/vtable-multi-level.rs +++ b/tests/ui/traits/vtable/vtable-multi-level.rs @@ -1,4 +1,3 @@ -//@ build-fail #![feature(rustc_attrs)] // O --> G --> C --> A @@ -10,134 +9,126 @@ // |-> M --> K // \-> L -#[rustc_dump_vtable] trait A { - //~^ error vtable fn foo_a(&self) {} } -#[rustc_dump_vtable] trait B { - //~^ error vtable fn foo_b(&self) {} } -#[rustc_dump_vtable] trait C: A + B { - //~^ error vtable fn foo_c(&self) {} } -#[rustc_dump_vtable] trait D { - //~^ error vtable fn foo_d(&self) {} } -#[rustc_dump_vtable] trait E { - //~^ error vtable fn foo_e(&self) {} } -#[rustc_dump_vtable] trait F: D + E { - //~^ error vtable fn foo_f(&self) {} } -#[rustc_dump_vtable] trait G: C + F { fn foo_g(&self) {} } -#[rustc_dump_vtable] trait H { - //~^ error vtable fn foo_h(&self) {} } -#[rustc_dump_vtable] trait I { - //~^ error vtable fn foo_i(&self) {} } -#[rustc_dump_vtable] trait J: H + I { - //~^ error vtable fn foo_j(&self) {} } -#[rustc_dump_vtable] trait K { - //~^ error vtable fn foo_k(&self) {} } -#[rustc_dump_vtable] trait L { - //~^ error vtable fn foo_l(&self) {} } -#[rustc_dump_vtable] trait M: K + L { - //~^ error vtable fn foo_m(&self) {} } -#[rustc_dump_vtable] trait N: J + M { - //~^ error vtable fn foo_n(&self) {} } -#[rustc_dump_vtable] trait O: G + N { - //~^ error vtable fn foo_o(&self) {} } struct S; +#[rustc_dump_vtable] impl A for S {} +//~^ ERROR vtable entries + +#[rustc_dump_vtable] impl B for S {} +//~^ ERROR vtable entries + +#[rustc_dump_vtable] impl C for S {} +//~^ ERROR vtable entries + +#[rustc_dump_vtable] impl D for S {} +//~^ ERROR vtable entries + +#[rustc_dump_vtable] impl E for S {} +//~^ ERROR vtable entries + +#[rustc_dump_vtable] impl F for S {} +//~^ ERROR vtable entries + +#[rustc_dump_vtable] impl G for S {} +//~^ ERROR vtable entries + +#[rustc_dump_vtable] impl H for S {} +//~^ ERROR vtable entries + +#[rustc_dump_vtable] impl I for S {} +//~^ ERROR vtable entries + +#[rustc_dump_vtable] impl J for S {} +//~^ ERROR vtable entries + +#[rustc_dump_vtable] impl K for S {} +//~^ ERROR vtable entries + +#[rustc_dump_vtable] impl L for S {} +//~^ ERROR vtable entries + +#[rustc_dump_vtable] impl M for S {} +//~^ ERROR vtable entries + +#[rustc_dump_vtable] impl N for S {} -impl O for S {} +//~^ ERROR vtable entries -macro_rules! monomorphize_vtable { - ($trait:ident) => {{ - fn foo(_ : &dyn $trait) {} - foo(&S); - }} -} +#[rustc_dump_vtable] +impl O for S {} +//~^ ERROR vtable entries -fn main() { - monomorphize_vtable!(O); - - monomorphize_vtable!(A); - monomorphize_vtable!(B); - monomorphize_vtable!(C); - monomorphize_vtable!(D); - monomorphize_vtable!(E); - monomorphize_vtable!(F); - monomorphize_vtable!(H); - monomorphize_vtable!(I); - monomorphize_vtable!(J); - monomorphize_vtable!(K); - monomorphize_vtable!(L); - monomorphize_vtable!(M); - monomorphize_vtable!(N); -} +fn main() {} diff --git a/tests/ui/traits/vtable/vtable-multi-level.stderr b/tests/ui/traits/vtable/vtable-multi-level.stderr index c4389e23fc1..961900aa3d2 100644 --- a/tests/ui/traits/vtable/vtable-multi-level.stderr +++ b/tests/ui/traits/vtable/vtable-multi-level.stderr @@ -1,134 +1,119 @@ -error: vtable entries for `<S as O>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, Method(<S as A>::foo_a), - Method(<S as B>::foo_b), - TraitVPtr(<S as B>), - Method(<S as C>::foo_c), - Method(<S as D>::foo_d), - TraitVPtr(<S as D>), - Method(<S as E>::foo_e), - TraitVPtr(<S as E>), - Method(<S as F>::foo_f), - TraitVPtr(<S as F>), - Method(<S as G>::foo_g), - Method(<S as H>::foo_h), - TraitVPtr(<S as H>), - Method(<S as I>::foo_i), - TraitVPtr(<S as I>), - Method(<S as J>::foo_j), - TraitVPtr(<S as J>), - Method(<S as K>::foo_k), - TraitVPtr(<S as K>), - Method(<S as L>::foo_l), - TraitVPtr(<S as L>), - Method(<S as M>::foo_m), - TraitVPtr(<S as M>), - Method(<S as N>::foo_n), - TraitVPtr(<S as N>), - Method(<S as O>::foo_o), ] - --> $DIR/vtable-multi-level.rs:97:1 + --> $DIR/vtable-multi-level.rs:75:1 | -LL | trait O: G + N { - | ^^^^^^^^^^^^^^ +LL | impl A for S {} + | ^^^^^^^^^^^^ -error: vtable entries for `<S as A>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, - Method(<S as A>::foo_a), + Method(<S as B>::foo_b), ] - --> $DIR/vtable-multi-level.rs:14:1 + --> $DIR/vtable-multi-level.rs:79:1 | -LL | trait A { - | ^^^^^^^ +LL | impl B for S {} + | ^^^^^^^^^^^^ -error: vtable entries for `<S as B>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, + Method(<S as A>::foo_a), Method(<S as B>::foo_b), + TraitVPtr(<S as B>), + Method(<S as C>::foo_c), ] - --> $DIR/vtable-multi-level.rs:20:1 + --> $DIR/vtable-multi-level.rs:83:1 | -LL | trait B { - | ^^^^^^^ +LL | impl C for S {} + | ^^^^^^^^^^^^ -error: vtable entries for `<S as C>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, - Method(<S as A>::foo_a), - Method(<S as B>::foo_b), - TraitVPtr(<S as B>), - Method(<S as C>::foo_c), + Method(<S as D>::foo_d), ] - --> $DIR/vtable-multi-level.rs:26:1 + --> $DIR/vtable-multi-level.rs:87:1 | -LL | trait C: A + B { - | ^^^^^^^^^^^^^^ +LL | impl D for S {} + | ^^^^^^^^^^^^ -error: vtable entries for `<S as D>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, - Method(<S as D>::foo_d), + Method(<S as E>::foo_e), ] - --> $DIR/vtable-multi-level.rs:32:1 + --> $DIR/vtable-multi-level.rs:91:1 | -LL | trait D { - | ^^^^^^^ +LL | impl E for S {} + | ^^^^^^^^^^^^ -error: vtable entries for `<S as E>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, + Method(<S as D>::foo_d), Method(<S as E>::foo_e), + TraitVPtr(<S as E>), + Method(<S as F>::foo_f), ] - --> $DIR/vtable-multi-level.rs:38:1 + --> $DIR/vtable-multi-level.rs:95:1 | -LL | trait E { - | ^^^^^^^ +LL | impl F for S {} + | ^^^^^^^^^^^^ -error: vtable entries for `<S as F>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, + Method(<S as A>::foo_a), + Method(<S as B>::foo_b), + TraitVPtr(<S as B>), + Method(<S as C>::foo_c), Method(<S as D>::foo_d), + TraitVPtr(<S as D>), Method(<S as E>::foo_e), TraitVPtr(<S as E>), Method(<S as F>::foo_f), + TraitVPtr(<S as F>), + Method(<S as G>::foo_g), ] - --> $DIR/vtable-multi-level.rs:44:1 + --> $DIR/vtable-multi-level.rs:99:1 | -LL | trait F: D + E { - | ^^^^^^^^^^^^^^ +LL | impl G for S {} + | ^^^^^^^^^^^^ -error: vtable entries for `<S as H>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, Method(<S as H>::foo_h), ] - --> $DIR/vtable-multi-level.rs:55:1 + --> $DIR/vtable-multi-level.rs:103:1 | -LL | trait H { - | ^^^^^^^ +LL | impl H for S {} + | ^^^^^^^^^^^^ -error: vtable entries for `<S as I>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, Method(<S as I>::foo_i), ] - --> $DIR/vtable-multi-level.rs:61:1 + --> $DIR/vtable-multi-level.rs:107:1 | -LL | trait I { - | ^^^^^^^ +LL | impl I for S {} + | ^^^^^^^^^^^^ -error: vtable entries for `<S as J>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -137,34 +122,34 @@ error: vtable entries for `<S as J>`: [ TraitVPtr(<S as I>), Method(<S as J>::foo_j), ] - --> $DIR/vtable-multi-level.rs:67:1 + --> $DIR/vtable-multi-level.rs:111:1 | -LL | trait J: H + I { - | ^^^^^^^^^^^^^^ +LL | impl J for S {} + | ^^^^^^^^^^^^ -error: vtable entries for `<S as K>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, Method(<S as K>::foo_k), ] - --> $DIR/vtable-multi-level.rs:73:1 + --> $DIR/vtable-multi-level.rs:115:1 | -LL | trait K { - | ^^^^^^^ +LL | impl K for S {} + | ^^^^^^^^^^^^ -error: vtable entries for `<S as L>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, Method(<S as L>::foo_l), ] - --> $DIR/vtable-multi-level.rs:79:1 + --> $DIR/vtable-multi-level.rs:119:1 | -LL | trait L { - | ^^^^^^^ +LL | impl L for S {} + | ^^^^^^^^^^^^ -error: vtable entries for `<S as M>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -173,12 +158,12 @@ error: vtable entries for `<S as M>`: [ TraitVPtr(<S as L>), Method(<S as M>::foo_m), ] - --> $DIR/vtable-multi-level.rs:85:1 + --> $DIR/vtable-multi-level.rs:123:1 | -LL | trait M: K + L { - | ^^^^^^^^^^^^^^ +LL | impl M for S {} + | ^^^^^^^^^^^^ -error: vtable entries for `<S as N>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -194,10 +179,46 @@ error: vtable entries for `<S as N>`: [ TraitVPtr(<S as M>), Method(<S as N>::foo_n), ] - --> $DIR/vtable-multi-level.rs:91:1 + --> $DIR/vtable-multi-level.rs:127:1 + | +LL | impl N for S {} + | ^^^^^^^^^^^^ + +error: vtable entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(<S as A>::foo_a), + Method(<S as B>::foo_b), + TraitVPtr(<S as B>), + Method(<S as C>::foo_c), + Method(<S as D>::foo_d), + TraitVPtr(<S as D>), + Method(<S as E>::foo_e), + TraitVPtr(<S as E>), + Method(<S as F>::foo_f), + TraitVPtr(<S as F>), + Method(<S as G>::foo_g), + Method(<S as H>::foo_h), + TraitVPtr(<S as H>), + Method(<S as I>::foo_i), + TraitVPtr(<S as I>), + Method(<S as J>::foo_j), + TraitVPtr(<S as J>), + Method(<S as K>::foo_k), + TraitVPtr(<S as K>), + Method(<S as L>::foo_l), + TraitVPtr(<S as L>), + Method(<S as M>::foo_m), + TraitVPtr(<S as M>), + Method(<S as N>::foo_n), + TraitVPtr(<S as N>), + Method(<S as O>::foo_o), + ] + --> $DIR/vtable-multi-level.rs:131:1 | -LL | trait N: J + M { - | ^^^^^^^^^^^^^^ +LL | impl O for S {} + | ^^^^^^^^^^^^ -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/traits/vtable/vtable-multiple.rs b/tests/ui/traits/vtable/vtable-multiple.rs index beaaf4db6b1..51e20ee20c9 100644 --- a/tests/ui/traits/vtable/vtable-multiple.rs +++ b/tests/ui/traits/vtable/vtable-multiple.rs @@ -1,33 +1,29 @@ -//@ build-fail #![feature(rustc_attrs)] -#[rustc_dump_vtable] trait A { fn foo_a(&self) {} } -#[rustc_dump_vtable] trait B { - //~^ error vtable fn foo_b(&self) {} } -#[rustc_dump_vtable] trait C: A + B { - //~^ error vtable fn foo_c(&self) {} } struct S; +#[rustc_dump_vtable] impl A for S {} +//~^ error vtable + +#[rustc_dump_vtable] impl B for S {} -impl C for S {} +//~^ error vtable -fn foo(c: &dyn C) {} -fn bar(c: &dyn B) {} +#[rustc_dump_vtable] +impl C for S {} +//~^ error vtable -fn main() { - foo(&S); - bar(&S); -} +fn main() {} diff --git a/tests/ui/traits/vtable/vtable-multiple.stderr b/tests/ui/traits/vtable/vtable-multiple.stderr index 0dcd8443309..bae44148baa 100644 --- a/tests/ui/traits/vtable/vtable-multiple.stderr +++ b/tests/ui/traits/vtable/vtable-multiple.stderr @@ -1,27 +1,38 @@ -error: vtable entries for `<S as C>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, Method(<S as A>::foo_a), + ] + --> $DIR/vtable-multiple.rs:18:1 + | +LL | impl A for S {} + | ^^^^^^^^^^^^ + +error: vtable entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, Method(<S as B>::foo_b), - TraitVPtr(<S as B>), - Method(<S as C>::foo_c), ] - --> $DIR/vtable-multiple.rs:16:1 + --> $DIR/vtable-multiple.rs:22:1 | -LL | trait C: A + B { - | ^^^^^^^^^^^^^^ +LL | impl B for S {} + | ^^^^^^^^^^^^ -error: vtable entries for `<S as B>`: [ +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, + Method(<S as A>::foo_a), Method(<S as B>::foo_b), + TraitVPtr(<S as B>), + Method(<S as C>::foo_c), ] - --> $DIR/vtable-multiple.rs:10:1 + --> $DIR/vtable-multiple.rs:26:1 | -LL | trait B { - | ^^^^^^^ +LL | impl C for S {} + | ^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/traits/vtable/vtable-vacant.rs b/tests/ui/traits/vtable/vtable-vacant.rs index b3c76815703..b023565c56e 100644 --- a/tests/ui/traits/vtable/vtable-vacant.rs +++ b/tests/ui/traits/vtable/vtable-vacant.rs @@ -1,18 +1,14 @@ -//@ build-fail #![feature(rustc_attrs)] #![feature(negative_impls)] // B --> A -#[rustc_dump_vtable] trait A { fn foo_a1(&self) {} fn foo_a2(&self) where Self: Send {} } -#[rustc_dump_vtable] trait B: A { - //~^ error vtable fn foo_b1(&self) {} fn foo_b2(&self) where Self: Send {} } @@ -20,11 +16,12 @@ trait B: A { struct S; impl !Send for S {} +#[rustc_dump_vtable] impl A for S {} -impl B for S {} +//~^ error vtable -fn foo(_: &dyn B) {} +#[rustc_dump_vtable] +impl B for S {} +//~^ error vtable -fn main() { - foo(&S); -} +fn main() {} diff --git a/tests/ui/traits/vtable/vtable-vacant.stderr b/tests/ui/traits/vtable/vtable-vacant.stderr index f6961ca010e..ed8466f7f2e 100644 --- a/tests/ui/traits/vtable/vtable-vacant.stderr +++ b/tests/ui/traits/vtable/vtable-vacant.stderr @@ -1,4 +1,16 @@ -error: vtable entries for `<S as B>`: [ +error: vtable entries: [ + MetadataDropInPlace, + MetadataSize, + MetadataAlign, + Method(<S as A>::foo_a1), + Vacant, + ] + --> $DIR/vtable-vacant.rs:20:1 + | +LL | impl A for S {} + | ^^^^^^^^^^^^ + +error: vtable entries: [ MetadataDropInPlace, MetadataSize, MetadataAlign, @@ -7,10 +19,10 @@ error: vtable entries for `<S as B>`: [ Method(<S as B>::foo_b1), Vacant, ] - --> $DIR/vtable-vacant.rs:14:1 + --> $DIR/vtable-vacant.rs:24:1 | -LL | trait B: A { - | ^^^^^^^^^^ +LL | impl B for S {} + | ^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors diff --git a/tests/ui/type-alias-impl-trait/issue-98604.rs b/tests/ui/type-alias-impl-trait/issue-98604.rs index 9231e82d9f4..35c25c7f726 100644 --- a/tests/ui/type-alias-impl-trait/issue-98604.rs +++ b/tests/ui/type-alias-impl-trait/issue-98604.rs @@ -7,5 +7,5 @@ async fn test() {} #[allow(unused_must_use)] fn main() { Box::new(test) as AsyncFnPtr; - //~^ ERROR expected `test` to be a fn item that returns `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()> + //~^ ERROR expected `test` to return `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()> } diff --git a/tests/ui/type-alias-impl-trait/issue-98604.stderr b/tests/ui/type-alias-impl-trait/issue-98604.stderr index 2390b725356..77c6ba3003f 100644 --- a/tests/ui/type-alias-impl-trait/issue-98604.stderr +++ b/tests/ui/type-alias-impl-trait/issue-98604.stderr @@ -1,4 +1,4 @@ -error[E0271]: expected `test` to be a fn item that returns `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>` +error[E0271]: expected `test` to return `Pin<Box<dyn Future<Output = ()>>>`, but it returns `impl Future<Output = ()>` --> $DIR/issue-98604.rs:9:5 | LL | Box::new(test) as AsyncFnPtr; diff --git a/tests/ui/type-alias-impl-trait/issue-98608.rs b/tests/ui/type-alias-impl-trait/issue-98608.rs index 5e026ea4096..5612ccd6cae 100644 --- a/tests/ui/type-alias-impl-trait/issue-98608.rs +++ b/tests/ui/type-alias-impl-trait/issue-98608.rs @@ -4,7 +4,7 @@ fn hi() -> impl Sized { fn main() { let b: Box<dyn Fn() -> Box<u8>> = Box::new(hi); - //~^ ERROR expected `hi` to be a fn item that returns `Box<u8>`, but it returns `impl Sized` + //~^ ERROR expected `hi` to return `Box<u8>`, but it returns `impl Sized` let boxed = b(); let null = *boxed; println!("{null:?}"); diff --git a/tests/ui/type-alias-impl-trait/issue-98608.stderr b/tests/ui/type-alias-impl-trait/issue-98608.stderr index d5c56636f66..872a6ed4350 100644 --- a/tests/ui/type-alias-impl-trait/issue-98608.stderr +++ b/tests/ui/type-alias-impl-trait/issue-98608.stderr @@ -1,4 +1,4 @@ -error[E0271]: expected `hi` to be a fn item that returns `Box<u8>`, but it returns `impl Sized` +error[E0271]: expected `hi` to return `Box<u8>`, but it returns `impl Sized` --> $DIR/issue-98608.rs:6:39 | LL | fn hi() -> impl Sized { diff --git a/tests/ui/type/pattern_types/chars.rs b/tests/ui/type/pattern_types/chars.rs new file mode 100644 index 00000000000..9073998b387 --- /dev/null +++ b/tests/ui/type/pattern_types/chars.rs @@ -0,0 +1,12 @@ +//! Check that chars can be used in ranges + +//@ check-pass + +#![feature(pattern_types)] +#![feature(pattern_type_macro)] + +use std::pat::pattern_type; + +const LOWERCASE: pattern_type!(char is 'a'..='z') = unsafe { std::mem::transmute('b') }; + +fn main() {} diff --git a/tests/ui/type/pattern_types/nested.rs b/tests/ui/type/pattern_types/nested.rs new file mode 100644 index 00000000000..519fb3f05b4 --- /dev/null +++ b/tests/ui/type/pattern_types/nested.rs @@ -0,0 +1,26 @@ +//! Check that pattern types can only have specific base types + +#![feature(pattern_types)] +#![feature(pattern_type_macro)] + +use std::pat::pattern_type; + +// Undoing an inner pattern type's restrictions should either be forbidden, +// or still validate correctly. +const BAD_NESTING: pattern_type!(pattern_type!(u32 is 1..) is 0..) = todo!(); +//~^ ERROR: not a valid base type for range patterns + +// We want to get the most narrowest version that a pattern could be +const BAD_NESTING2: pattern_type!(pattern_type!(i32 is 1..) is ..=-1) = todo!(); +//~^ ERROR: not a valid base type for range patterns + +const BAD_NESTING3: pattern_type!(pattern_type!(i32 is 1..) is ..0) = todo!(); +//~^ ERROR: not a valid base type for range patterns + +const BAD_NESTING4: pattern_type!(() is ..0) = todo!(); +//~^ ERROR: not a valid base type for range patterns + +const BAD_NESTING5: pattern_type!(f32 is 1.0 .. 2.0) = todo!(); +//~^ ERROR: not a valid base type for range patterns + +fn main() {} diff --git a/tests/ui/type/pattern_types/nested.stderr b/tests/ui/type/pattern_types/nested.stderr new file mode 100644 index 00000000000..99d3979e98c --- /dev/null +++ b/tests/ui/type/pattern_types/nested.stderr @@ -0,0 +1,62 @@ +error: `(u32) is 1..=` is not a valid base type for range patterns + --> $DIR/nested.rs:10:34 + | +LL | const BAD_NESTING: pattern_type!(pattern_type!(u32 is 1..) is 0..) = todo!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: range patterns only support integers + --> $DIR/nested.rs:10:63 + | +LL | const BAD_NESTING: pattern_type!(pattern_type!(u32 is 1..) is 0..) = todo!(); + | ^^^ + +error: `(i32) is 1..=` is not a valid base type for range patterns + --> $DIR/nested.rs:14:35 + | +LL | const BAD_NESTING2: pattern_type!(pattern_type!(i32 is 1..) is ..=-1) = todo!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: range patterns only support integers + --> $DIR/nested.rs:14:64 + | +LL | const BAD_NESTING2: pattern_type!(pattern_type!(i32 is 1..) is ..=-1) = todo!(); + | ^^^^^ + +error: `(i32) is 1..=` is not a valid base type for range patterns + --> $DIR/nested.rs:17:35 + | +LL | const BAD_NESTING3: pattern_type!(pattern_type!(i32 is 1..) is ..0) = todo!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: range patterns only support integers + --> $DIR/nested.rs:17:64 + | +LL | const BAD_NESTING3: pattern_type!(pattern_type!(i32 is 1..) is ..0) = todo!(); + | ^^^ + +error: `()` is not a valid base type for range patterns + --> $DIR/nested.rs:20:35 + | +LL | const BAD_NESTING4: pattern_type!(() is ..0) = todo!(); + | ^^ + | +note: range patterns only support integers + --> $DIR/nested.rs:20:41 + | +LL | const BAD_NESTING4: pattern_type!(() is ..0) = todo!(); + | ^^^ + +error: `f32` is not a valid base type for range patterns + --> $DIR/nested.rs:23:35 + | +LL | const BAD_NESTING5: pattern_type!(f32 is 1.0 .. 2.0) = todo!(); + | ^^^ + | +note: range patterns only support integers + --> $DIR/nested.rs:23:42 + | +LL | const BAD_NESTING5: pattern_type!(f32 is 1.0 .. 2.0) = todo!(); + | ^^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/type/pattern_types/pattern_type_mismatch.rs b/tests/ui/type/pattern_types/pattern_type_mismatch.rs new file mode 100644 index 00000000000..8d375d7932b --- /dev/null +++ b/tests/ui/type/pattern_types/pattern_type_mismatch.rs @@ -0,0 +1,20 @@ +//! Check that pattern types patterns must be of the type of the base type + +//@ known-bug: unknown +//@ failure-status: 101 +//@ normalize-stderr: "note: .*\n\n" -> "" +//@ normalize-stderr: "thread 'rustc' panicked.*\n" -> "" +//@ normalize-stderr: "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: " +//@ normalize-stderr: "(delayed at compiler/rustc_mir_transform/src/lib.rs:)\d+:\d+" -> "$1:LL:CC" +//@ rustc-env:RUST_BACKTRACE=0 + +#![feature(pattern_types)] +#![feature(pattern_type_macro)] + +use std::pat::pattern_type; + +const BAD_NESTING4: pattern_type!(u8 is 'a'..='a') = todo!(); + +const BAD_NESTING5: pattern_type!(char is 1..=1) = todo!(); + +fn main() {} diff --git a/tests/ui/type/pattern_types/pattern_type_mismatch.stderr b/tests/ui/type/pattern_types/pattern_type_mismatch.stderr new file mode 100644 index 00000000000..ee413133ab3 --- /dev/null +++ b/tests/ui/type/pattern_types/pattern_type_mismatch.stderr @@ -0,0 +1,31 @@ +error: internal compiler error: ty::ConstKind::Error constructed but no error reported + | + = error: internal compiler error: ty::ConstKind::Error constructed but no error reported + | + = note: delayed at compiler/rustc_mir_build/src/thir/constant.rs:72:21 - disabled backtrace + = error: internal compiler error: mir_const_qualif: MIR had errors + --> $DIR/pattern_type_mismatch.rs:16:1 + | +LL | const BAD_NESTING4: pattern_type!(u8 is 'a'..='a') = todo!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: delayed at compiler/rustc_mir_transform/src/lib.rs::LL:CC - disabled backtrace + --> $DIR/pattern_type_mismatch.rs:16:1 + | +LL | const BAD_NESTING4: pattern_type!(u8 is 'a'..='a') = todo!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: internal compiler error: mir_const_qualif: MIR had errors + --> $DIR/pattern_type_mismatch.rs:18:1 + | +LL | const BAD_NESTING5: pattern_type!(char is 1..=1) = todo!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: delayed at compiler/rustc_mir_transform/src/lib.rs::LL:CC - disabled backtrace + --> $DIR/pattern_type_mismatch.rs:18:1 + | +LL | const BAD_NESTING5: pattern_type!(char is 1..=1) = todo!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +query stack during panic: +end of query stack diff --git a/tests/ui/type/pattern_types/reverse_range.rs b/tests/ui/type/pattern_types/reverse_range.rs new file mode 100644 index 00000000000..6a245615f1a --- /dev/null +++ b/tests/ui/type/pattern_types/reverse_range.rs @@ -0,0 +1,14 @@ +//! Check that the range start must be smaller than the range end +//@ known-bug: unknown +//@ failure-status: 101 +//@ normalize-stderr: "note: .*\n\n" -> "" +//@ normalize-stderr: "thread 'rustc' panicked.*\n" -> "" +//@ normalize-stderr: "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: " +//@ rustc-env:RUST_BACKTRACE=0 + +#![feature(pattern_types)] +#![feature(pattern_type_macro)] + +use std::pat::pattern_type; + +const NONE: pattern_type!(u8 is 1..0) = unsafe { std::mem::transmute(3_u8) }; diff --git a/tests/ui/type/pattern_types/reverse_range.stderr b/tests/ui/type/pattern_types/reverse_range.stderr new file mode 100644 index 00000000000..b714ca7d9ab --- /dev/null +++ b/tests/ui/type/pattern_types/reverse_range.stderr @@ -0,0 +1,17 @@ +error[E0601]: `main` function not found in crate `reverse_range` + --> $DIR/reverse_range.rs:14:78 + | +LL | const NONE: pattern_type!(u8 is 1..0) = unsafe { std::mem::transmute(3_u8) }; + | ^ consider adding a `main` function to `$DIR/reverse_range.rs` + + +assertion failed: end <= max_value +error: the compiler unexpectedly panicked. this is a bug. + +query stack during panic: +#0 [eval_to_allocation_raw] const-evaluating + checking `NONE` +#1 [eval_to_const_value_raw] simplifying constant for the type system `NONE` +... and 1 other queries... use `env RUST_BACKTRACE=1` to see the full query stack +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0601`. diff --git a/tests/ui/type/pattern_types/transmute.rs b/tests/ui/type/pattern_types/transmute.rs new file mode 100644 index 00000000000..cb76b2b938d --- /dev/null +++ b/tests/ui/type/pattern_types/transmute.rs @@ -0,0 +1,32 @@ +#![feature(pattern_types)] +#![feature(pattern_type_macro)] + +use std::pat::pattern_type; + +// ok +fn create<const S: u32, const E: u32>(x: u32) -> pattern_type!(u32 is S..=E) { + unsafe { std::mem::transmute(x) } +} + +// ok +fn unwrap<const S: u32, const E: u32>(x: pattern_type!(u32 is S..=E)) -> u32 { + unsafe { std::mem::transmute(x) } +} + +// bad, only when S != u32::MIN or E != u32::MAX will this ok +fn non_base_ty_transmute<const S: u32, const E: u32>( + x: Option<pattern_type!(u32 is S..=E)>, +) -> u32 { + unsafe { std::mem::transmute(x) } + //~^ ERROR types of different sizes +} + +// bad, only when S = u32::MIN and E = u32::MAX will this ok +fn wrapped_transmute<const S: u32, const E: u32>( + x: Option<pattern_type!(u32 is S..=E)>, +) -> Option<u32> { + unsafe { std::mem::transmute(x) } + //~^ ERROR types of different sizes +} + +fn main() {} diff --git a/tests/ui/type/pattern_types/transmute.stderr b/tests/ui/type/pattern_types/transmute.stderr new file mode 100644 index 00000000000..578549b515c --- /dev/null +++ b/tests/ui/type/pattern_types/transmute.stderr @@ -0,0 +1,21 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/transmute.rs:20:14 + | +LL | unsafe { std::mem::transmute(x) } + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `Option<(u32) is S..=E>` (size can vary because of u32) + = note: target type: `u32` (32 bits) + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/transmute.rs:28:14 + | +LL | unsafe { std::mem::transmute(x) } + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `Option<(u32) is S..=E>` (size can vary because of u32) + = note: target type: `Option<u32>` (64 bits) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0512`. diff --git a/tests/ui/type/pattern_types/validity.rs b/tests/ui/type/pattern_types/validity.rs new file mode 100644 index 00000000000..77a4e72f675 --- /dev/null +++ b/tests/ui/type/pattern_types/validity.rs @@ -0,0 +1,37 @@ +//! Check that pattern types have their validity checked + +#![feature(pattern_types)] +#![feature(pattern_type_macro)] + +use std::pat::pattern_type; + +const BAD: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(0) }; +//~^ ERROR: it is undefined behavior to use this value + +const BAD_UNINIT: pattern_type!(u32 is 1..) = + //~^ ERROR: evaluation of constant value failed + unsafe { std::mem::transmute(std::mem::MaybeUninit::<u32>::uninit()) }; + +const BAD_PTR: pattern_type!(usize is 1..) = unsafe { std::mem::transmute(&42) }; +//~^ ERROR: evaluation of constant value failed + +const BAD_AGGREGATE: (pattern_type!(u32 is 1..), u32) = (unsafe { std::mem::transmute(0) }, 0); +//~^ ERROR: it is undefined behavior to use this value + +struct Foo(Bar); +struct Bar(pattern_type!(u32 is 1..)); + +const BAD_FOO: Foo = Foo(Bar(unsafe { std::mem::transmute(0) })); +//~^ ERROR: it is undefined behavior to use this value + +const CHAR_UNINIT: pattern_type!(char is 'A'..'Z') = + //~^ ERROR: evaluation of constant value failed + unsafe { std::mem::transmute(std::mem::MaybeUninit::<u32>::uninit()) }; + +const CHAR_OOB_PAT: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute('a') }; +//~^ ERROR: it is undefined behavior to use this value + +const CHAR_OOB: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute(u32::MAX) }; +//~^ ERROR: it is undefined behavior to use this value + +fn main() {} diff --git a/tests/ui/type/pattern_types/validity.stderr b/tests/ui/type/pattern_types/validity.stderr new file mode 100644 index 00000000000..5bc18cfba3f --- /dev/null +++ b/tests/ui/type/pattern_types/validity.stderr @@ -0,0 +1,79 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/validity.rs:8:1 + | +LL | const BAD: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + 00 00 00 00 │ .... + } + +error[E0080]: evaluation of constant value failed + --> $DIR/validity.rs:11:1 + | +LL | const BAD_UNINIT: pattern_type!(u32 is 1..) = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error[E0080]: evaluation of constant value failed + --> $DIR/validity.rs:15:1 + | +LL | const BAD_PTR: pattern_type!(usize is 1..) = unsafe { std::mem::transmute(&42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer + | + = help: this code performed an operation that depends on the underlying bytes representing a pointer + = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported + +error[E0080]: it is undefined behavior to use this value + --> $DIR/validity.rs:18:1 + | +LL | const BAD_AGGREGATE: (pattern_type!(u32 is 1..), u32) = (unsafe { std::mem::transmute(0) }, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0, but expected something greater or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + 00 00 00 00 00 00 00 00 │ ........ + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/validity.rs:24:1 + | +LL | const BAD_FOO: Foo = Foo(Bar(unsafe { std::mem::transmute(0) })); + | ^^^^^^^^^^^^^^^^^^ constructing invalid value at .0.0: encountered 0, but expected something greater or equal to 1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + 00 00 00 00 │ .... + } + +error[E0080]: evaluation of constant value failed + --> $DIR/validity.rs:27:1 + | +LL | const CHAR_UNINIT: pattern_type!(char is 'A'..'Z') = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + +error[E0080]: it is undefined behavior to use this value + --> $DIR/validity.rs:31:1 + | +LL | const CHAR_OOB_PAT: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute('a') }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 97, but expected something in the range 65..=89 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + 61 00 00 00 │ a... + } + +error[E0080]: it is undefined behavior to use this value + --> $DIR/validity.rs:34:1 + | +LL | const CHAR_OOB: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute(u32::MAX) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + ff ff ff ff │ .... + } + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr b/tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr index 71717c6945e..eea2e75a238 100644 --- a/tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr +++ b/tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr @@ -17,7 +17,7 @@ LL | let y = x as dyn MyAdd<i32>; | ^^^^^^^^^^^^^^ `MyAdd` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/type-parameter-defaults-referencing-Self-ppaux.rs:6:55 | LL | trait MyAdd<Rhs=Self> { fn add(&self, other: &Rhs) -> Self; } diff --git a/tests/ui/type_length_limit.rs b/tests/ui/type_length_limit.rs index 87f5ffd76d7..b629455aced 100644 --- a/tests/ui/type_length_limit.rs +++ b/tests/ui/type_length_limit.rs @@ -2,6 +2,9 @@ //@ compile-flags: -Copt-level=0 -Zenforce-type-length-limit //~^^ ERROR reached the type-length limit +// The regex below normalizes the long type file name to make it suitable for compare-modes. +//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type.txt'" + // Test that the type length limit can be changed. // The exact type depends on optimizations, so disable them. diff --git a/tests/ui/type_length_limit.stderr b/tests/ui/type_length_limit.stderr index 83353547d34..d913b661c6f 100644 --- a/tests/ui/type_length_limit.stderr +++ b/tests/ui/type_length_limit.stderr @@ -1,11 +1,11 @@ error: reached the type-length limit while instantiating `std::mem::drop::<Option<((((..., ..., ...), ..., ...), ..., ...), ..., ...)>>` - --> $DIR/type_length_limit.rs:32:5 + --> $DIR/type_length_limit.rs:35:5 | LL | drop::<Option<A>>(None); | ^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider adding a `#![type_length_limit="4010"]` attribute to your crate - = note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt' + = note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type.txt' error: reached the type-length limit while instantiating `<{closure@rt::lang_start<()>::{closure#0}} as FnMut<()>>::call_mut` | diff --git a/tests/ui/typeck/issue-107775.stderr b/tests/ui/typeck/issue-107775.stderr index dad7e1581e7..1be26897469 100644 --- a/tests/ui/typeck/issue-107775.stderr +++ b/tests/ui/typeck/issue-107775.stderr @@ -6,7 +6,7 @@ LL | map.insert(1, Struct::do_something); | | | ... which causes `map` to have type `HashMap<{integer}, fn(u8) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>` LL | Self { map } - | ^^^ expected `HashMap<u16, fn(u8) -> Pin<...>>`, found `HashMap<{integer}, ...>` + | ^^^ expected `HashMap<u16, fn(u8) -> Pin<Box<...>>>`, found `HashMap<{integer}, ...>` | = note: expected struct `HashMap<u16, fn(_) -> Pin<Box<(dyn Future<Output = ()> + Send + 'static)>>>` found struct `HashMap<{integer}, fn(_) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>` diff --git a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.next.stderr b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.next.stderr index 1bcc0dbaf67..92ad83c3300 100644 --- a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.next.stderr +++ b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.next.stderr @@ -9,6 +9,8 @@ error: the constant `N` is not of type `usize` | LL | fn func<const N: u32>() -> [(); N]; | ^^^^^^^ expected `usize`, found `u32` + | + = note: the length of array `[(); N]` must be type `usize` error: aborting due to 2 previous errors diff --git a/tests/ui/typeck/path-to-method-sugg-unresolved-expr.rs b/tests/ui/typeck/path-to-method-sugg-unresolved-expr.rs index 7b4f62fea0c..e095850879c 100644 --- a/tests/ui/typeck/path-to-method-sugg-unresolved-expr.rs +++ b/tests/ui/typeck/path-to-method-sugg-unresolved-expr.rs @@ -5,6 +5,6 @@ fn main() { let page_size = page_size::get(); //~^ ERROR failed to resolve: use of unresolved module or unlinked crate `page_size` //~| NOTE use of unresolved module or unlinked crate `page_size` - //@[cargo-invoked]~^^^ HELP if you wanted to use a crate named `page_size`, use `cargo add - //@[only-rustc]~^^^^ HELP you might be missing a crate named `page_size` + //[cargo-invoked]~^^^ HELP if you wanted to use a crate named `page_size`, use `cargo add + //[only-rustc]~^^^^ HELP you might be missing a crate named `page_size` } diff --git a/tests/ui/typeck/return_type_containing_closure.rs b/tests/ui/typeck/return_type_containing_closure.rs index b81cac0a58a..a9bb89bae2d 100644 --- a/tests/ui/typeck/return_type_containing_closure.rs +++ b/tests/ui/typeck/return_type_containing_closure.rs @@ -2,7 +2,7 @@ fn foo() { //~ HELP try adding a return type vec!['a'].iter().map(|c| c) //~^ ERROR mismatched types [E0308] - //~| NOTE expected `()`, found `Map<Iter<'_, char>, ...>` + //~| NOTE expected `()`, found `Map<Iter<'_, char>, {closure@...}>` //~| NOTE expected unit type `()` //~| HELP consider using a semicolon here } diff --git a/tests/ui/typeck/return_type_containing_closure.stderr b/tests/ui/typeck/return_type_containing_closure.stderr index 3f14650a82c..a60bf79a57b 100644 --- a/tests/ui/typeck/return_type_containing_closure.stderr +++ b/tests/ui/typeck/return_type_containing_closure.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/return_type_containing_closure.rs:3:5 | LL | vec!['a'].iter().map(|c| c) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Map<Iter<'_, char>, ...>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Map<Iter<'_, char>, {closure@...}>` | = note: expected unit type `()` found struct `Map<std::slice::Iter<'_, char>, {closure@$DIR/return_type_containing_closure.rs:3:26: 3:29}>` diff --git a/tests/ui/union/union-derive-eq.next.stderr b/tests/ui/union/union-derive-eq.next.stderr index 3952b1f1284..151ceebe1ba 100644 --- a/tests/ui/union/union-derive-eq.next.stderr +++ b/tests/ui/union/union-derive-eq.next.stderr @@ -7,6 +7,8 @@ LL | union U2 { LL | a: PartialEqNotEq, | ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq` | +note: required by a bound in `AssertParamIsEq` + --> $SRC_DIR/core/src/cmp.rs:LL:COL = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `PartialEqNotEq` with `#[derive(Eq)]` | diff --git a/tests/ui/unsafe-binders/expr.rs b/tests/ui/unsafe-binders/expr.rs index 0fe68751f0a..d437d8f8ac0 100644 --- a/tests/ui/unsafe-binders/expr.rs +++ b/tests/ui/unsafe-binders/expr.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![feature(unsafe_binders)] //~^ WARN the feature `unsafe_binders` is incomplete @@ -7,8 +9,6 @@ fn main() { unsafe { let x = 1; let binder: unsafe<'a> &'a i32 = wrap_binder!(&x); - //~^ ERROR unsafe binder casts are not fully implemented let rx = *unwrap_binder!(binder); - //~^ ERROR unsafe binder casts are not fully implemented } } diff --git a/tests/ui/unsafe-binders/expr.stderr b/tests/ui/unsafe-binders/expr.stderr index 78a288e10a3..07026e18e12 100644 --- a/tests/ui/unsafe-binders/expr.stderr +++ b/tests/ui/unsafe-binders/expr.stderr @@ -1,5 +1,5 @@ warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/expr.rs:1:12 + --> $DIR/expr.rs:3:12 | LL | #![feature(unsafe_binders)] | ^^^^^^^^^^^^^^ @@ -7,17 +7,5 @@ LL | #![feature(unsafe_binders)] = note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information = note: `#[warn(incomplete_features)]` on by default -error: unsafe binder casts are not fully implemented - --> $DIR/expr.rs:9:55 - | -LL | let binder: unsafe<'a> &'a i32 = wrap_binder!(&x); - | ^^ - -error: unsafe binder casts are not fully implemented - --> $DIR/expr.rs:11:34 - | -LL | let rx = *unwrap_binder!(binder); - | ^^^^^^ - -error: aborting due to 2 previous errors; 1 warning emitted +warning: 1 warning emitted diff --git a/tests/ui/unsafe-binders/mismatch.rs b/tests/ui/unsafe-binders/mismatch.rs index 731fe2d1ce9..840d938cbe9 100644 --- a/tests/ui/unsafe-binders/mismatch.rs +++ b/tests/ui/unsafe-binders/mismatch.rs @@ -5,38 +5,31 @@ use std::unsafe_binder::{wrap_binder, unwrap_binder}; fn a() { let _: unsafe<'a> &'a i32 = wrap_binder!(&()); - //~^ ERROR unsafe binder casts are not fully implemented - //~| ERROR mismatched types + //~^ ERROR mismatched types } fn b() { let _: i32 = wrap_binder!(&()); - //~^ ERROR unsafe binder casts are not fully implemented - //~| ERROR `wrap_binder!()` can only wrap into unsafe binder + //~^ ERROR `wrap_binder!()` can only wrap into unsafe binder } fn c() { let y = 1; unwrap_binder!(y); - //~^ ERROR unsafe binder casts are not fully implemented - //~| ERROR expected unsafe binder, found integer as input + //~^ ERROR expected unsafe binder, found integer as input } fn d() { let unknown = Default::default(); + //~^ ERROR type annotations needed unwrap_binder!(unknown); - //~^ ERROR unsafe binder casts are not fully implemented - // FIXME(unsafe_binders): This should report ambiguity once we've removed - // the error above which taints the infcx. } fn e() { let x = wrap_binder!(&42); - //~^ ERROR unsafe binder casts are not fully implemented + //~^ ERROR type annotations needed // Currently, type inference doesn't flow backwards for unsafe binders. // It could, perhaps, but that may cause even more surprising corners. - // FIXME(unsafe_binders): This should report ambiguity once we've removed - // the error above which taints the infcx. let _: unsafe<'a> &'a i32 = x; } diff --git a/tests/ui/unsafe-binders/mismatch.stderr b/tests/ui/unsafe-binders/mismatch.stderr index a720e5dbdc1..f64db92eb65 100644 --- a/tests/ui/unsafe-binders/mismatch.stderr +++ b/tests/ui/unsafe-binders/mismatch.stderr @@ -7,12 +7,6 @@ LL | #![feature(unsafe_binders)] = note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information = note: `#[warn(incomplete_features)]` on by default -error: unsafe binder casts are not fully implemented - --> $DIR/mismatch.rs:7:46 - | -LL | let _: unsafe<'a> &'a i32 = wrap_binder!(&()); - | ^^^ - error[E0308]: mismatched types --> $DIR/mismatch.rs:7:46 | @@ -22,14 +16,8 @@ LL | let _: unsafe<'a> &'a i32 = wrap_binder!(&()); = note: expected reference `&i32` found reference `&()` -error: unsafe binder casts are not fully implemented - --> $DIR/mismatch.rs:13:31 - | -LL | let _: i32 = wrap_binder!(&()); - | ^^^ - error: `wrap_binder!()` can only wrap into unsafe binder, not `i32` - --> $DIR/mismatch.rs:13:18 + --> $DIR/mismatch.rs:12:18 | LL | let _: i32 = wrap_binder!(&()); | ^^^^^^^^^^^^^^^^^ @@ -37,32 +25,35 @@ LL | let _: i32 = wrap_binder!(&()); = note: unsafe binders are the only valid output of wrap = note: this error originates in the macro `wrap_binder` (in Nightly builds, run with -Z macro-backtrace for more info) -error: unsafe binder casts are not fully implemented - --> $DIR/mismatch.rs:20:20 - | -LL | unwrap_binder!(y); - | ^ - error: expected unsafe binder, found integer as input of `unwrap_binder!()` - --> $DIR/mismatch.rs:20:20 + --> $DIR/mismatch.rs:18:20 | LL | unwrap_binder!(y); | ^ | = note: only an unsafe binder type can be unwrapped -error: unsafe binder casts are not fully implemented - --> $DIR/mismatch.rs:27:20 +error[E0282]: type annotations needed + --> $DIR/mismatch.rs:23:9 | +LL | let unknown = Default::default(); + | ^^^^^^^ +LL | LL | unwrap_binder!(unknown); - | ^^^^^^^ + | ------- type must be known at this point + | +help: consider giving `unknown` an explicit type + | +LL | let unknown: /* Type */ = Default::default(); + | ++++++++++++ -error: unsafe binder casts are not fully implemented - --> $DIR/mismatch.rs:34:26 +error[E0282]: type annotations needed + --> $DIR/mismatch.rs:29:26 | LL | let x = wrap_binder!(&42); - | ^^^ + | ^^^ cannot infer type -error: aborting due to 8 previous errors; 1 warning emitted +error: aborting due to 5 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0282, E0308. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/unsafe-binders/moves.rs b/tests/ui/unsafe-binders/moves.rs new file mode 100644 index 00000000000..5bfcee62402 --- /dev/null +++ b/tests/ui/unsafe-binders/moves.rs @@ -0,0 +1,41 @@ +//@ known-bug: unknown + +#![feature(unsafe_binders)] +// FIXME(unsafe_binders) ~^ WARN the feature `unsafe_binders` is incomplete + +use std::unsafe_binder::{wrap_binder, unwrap_binder}; +use std::mem::{drop, ManuallyDrop}; + +struct NotCopyInner; +type NotCopy = ManuallyDrop<NotCopyInner>; + +fn use_after_wrap() { + unsafe { + let base = NotCopy; + let binder: unsafe<> NotCopy = wrap_binder!(base); + drop(base); + // FIXME(unsafe_binders) ~^ ERROR use of moved value: `base` + } +} + +fn move_out_of_wrap() { + unsafe { + let binder: unsafe<> NotCopy = wrap_binder!(NotCopy); + drop(unwrap_binder!(binder)); + drop(unwrap_binder!(binder)); + // FIXME(unsafe_binders) ~^ ERROR use of moved value: `binder` + } +} + +fn not_conflicting() { + unsafe { + let binder: unsafe<> (NotCopy, NotCopy) = wrap_binder!((NotCopy, NotCopy)); + drop(unwrap_binder!(binder).0); + drop(unwrap_binder!(binder).1); + // ^ NOT a problem. + drop(unwrap_binder!(binder).0); + // FIXME(unsafe_binders) ~^ ERROR use of moved value: `binder.0` + } +} + +fn main() {} diff --git a/tests/ui/unsafe-binders/moves.stderr b/tests/ui/unsafe-binders/moves.stderr new file mode 100644 index 00000000000..ca507964008 --- /dev/null +++ b/tests/ui/unsafe-binders/moves.stderr @@ -0,0 +1,85 @@ +error[E0423]: expected value, found type alias `NotCopy` + --> $DIR/moves.rs:14:20 + | +LL | let base = NotCopy; + | ^^^^^^^ + | + = note: can't use a type alias as a constructor + +error[E0423]: expected value, found type alias `NotCopy` + --> $DIR/moves.rs:23:53 + | +LL | let binder: unsafe<> NotCopy = wrap_binder!(NotCopy); + | ^^^^^^^ + | + = note: can't use a type alias as a constructor + +error[E0423]: expected value, found type alias `NotCopy` + --> $DIR/moves.rs:32:65 + | +LL | let binder: unsafe<> (NotCopy, NotCopy) = wrap_binder!((NotCopy, NotCopy)); + | ^^^^^^^ + | + = note: can't use a type alias as a constructor + +error[E0423]: expected value, found type alias `NotCopy` + --> $DIR/moves.rs:32:74 + | +LL | let binder: unsafe<> (NotCopy, NotCopy) = wrap_binder!((NotCopy, NotCopy)); + | ^^^^^^^ + | + = note: can't use a type alias as a constructor + +warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/moves.rs:3:12 + | +LL | #![feature(unsafe_binders)] + | ^^^^^^^^^^^^^^ + | + = note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: the trait bound `NotCopyInner: Copy` is not satisfied + --> $DIR/moves.rs:15:21 + | +LL | let binder: unsafe<> NotCopy = wrap_binder!(base); + | ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopyInner` + | + = note: required for `ManuallyDrop<NotCopyInner>` to implement `Copy` +help: consider annotating `NotCopyInner` with `#[derive(Copy)]` + | +LL + #[derive(Copy)] +LL | struct NotCopyInner; + | + +error[E0277]: the trait bound `NotCopyInner: Copy` is not satisfied + --> $DIR/moves.rs:23:21 + | +LL | let binder: unsafe<> NotCopy = wrap_binder!(NotCopy); + | ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopyInner` + | + = note: required for `ManuallyDrop<NotCopyInner>` to implement `Copy` +help: consider annotating `NotCopyInner` with `#[derive(Copy)]` + | +LL + #[derive(Copy)] +LL | struct NotCopyInner; + | + +error[E0277]: the trait bound `NotCopyInner: Copy` is not satisfied + --> $DIR/moves.rs:32:21 + | +LL | let binder: unsafe<> (NotCopy, NotCopy) = wrap_binder!((NotCopy, NotCopy)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopyInner` + | + = note: required for `ManuallyDrop<NotCopyInner>` to implement `Copy` + = note: required because it appears within the type `(ManuallyDrop<NotCopyInner>, ManuallyDrop<NotCopyInner>)` +help: consider annotating `NotCopyInner` with `#[derive(Copy)]` + | +LL + #[derive(Copy)] +LL | struct NotCopyInner; + | + +error: aborting due to 7 previous errors; 1 warning emitted + +Some errors have detailed explanations: E0277, E0423. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/wf/issue-87495.stderr b/tests/ui/wf/issue-87495.stderr index 7be327e61d1..0c293e3576d 100644 --- a/tests/ui/wf/issue-87495.stderr +++ b/tests/ui/wf/issue-87495.stderr @@ -5,7 +5,7 @@ LL | const CONST: (bool, dyn T); | ^^^^^ `T` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/issue-87495.rs:4:11 | LL | trait T { diff --git a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr index 0b7f4cd4362..f3e4f2a63e9 100644 --- a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr +++ b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr @@ -5,7 +5,7 @@ LL | let t_box: Box<dyn Trait> = Box::new(S); | ^^^^^^^^^^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:6:14 | LL | trait Trait: Sized {} @@ -22,7 +22,7 @@ LL | takes_box(Box::new(S)); | ^^^^^^^^^^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:6:14 | LL | trait Trait: Sized {} @@ -39,7 +39,7 @@ LL | Box::new(S) as Box<dyn Trait>; | ^^^^^^^^^^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:6:14 | LL | trait Trait: Sized {} diff --git a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr index 3f50e1192cf..716d0e78ff1 100644 --- a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr +++ b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr @@ -5,7 +5,7 @@ LL | let t: &dyn Trait = &S; | ^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:6:14 | LL | trait Trait: Sized {} @@ -22,7 +22,7 @@ LL | takes_trait(&S); | ^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:6:14 | LL | trait Trait: Sized {} @@ -39,7 +39,7 @@ LL | &S as &dyn Trait; | ^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:6:14 | LL | trait Trait: Sized {} diff --git a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr index 8f68f9c5b6b..a7405ce4caa 100644 --- a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr +++ b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr @@ -19,7 +19,7 @@ LL | Some(()) => &S, | ^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/wf-dyn-incompat-trait-obj-match.rs:6:14 | LL | trait Trait: Sized {} @@ -40,7 +40,7 @@ LL | None => &R, | ^^ `Trait` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/wf-dyn-incompat-trait-obj-match.rs:6:14 | LL | trait Trait: Sized {} diff --git a/tests/ui/wf/wf-dyn-incompatible.stderr b/tests/ui/wf/wf-dyn-incompatible.stderr index 1803376aaa1..e61b37d9293 100644 --- a/tests/ui/wf/wf-dyn-incompatible.stderr +++ b/tests/ui/wf/wf-dyn-incompatible.stderr @@ -5,7 +5,7 @@ LL | let _x: &dyn A; | ^^^^^^ `A` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> --> $DIR/wf-dyn-incompatible.rs:5:23 | LL | trait A { diff --git a/tests/ui/wf/wf-fn-where-clause.stderr b/tests/ui/wf/wf-fn-where-clause.stderr index d73376e9861..b419bc8347f 100644 --- a/tests/ui/wf/wf-fn-where-clause.stderr +++ b/tests/ui/wf/wf-fn-where-clause.stderr @@ -22,7 +22,7 @@ LL | fn bar() where Vec<dyn Copy>:, {} | = note: the trait is not dyn compatible because it requires `Self: Sized` = note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> error[E0277]: the size for values of type `(dyn Copy + 'static)` cannot be known at compilation time --> $DIR/wf-fn-where-clause.rs:12:16 diff --git a/tests/ui/wf/wf-normalization-sized.next.stderr b/tests/ui/wf/wf-normalization-sized.next.stderr index 1e898fb7b78..83b56bb6b19 100644 --- a/tests/ui/wf/wf-normalization-sized.next.stderr +++ b/tests/ui/wf/wf-normalization-sized.next.stderr @@ -5,6 +5,7 @@ LL | const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = (); | ^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[[[[[u8]]]]]` + = note: slice and array elements must have `Sized` type error[E0277]: the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time --> $DIR/wf-normalization-sized.rs:19:11 @@ -13,6 +14,7 @@ LL | const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = (); | ^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[[[[[u8]]]]]` + = note: slice and array elements must have `Sized` type = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -22,6 +24,8 @@ LL | const _: <Vec<str> as WellUnformed>::RequestNormalize = (); | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` +note: required by an implicit `Sized` bound in `Vec` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/wf-normalization-sized.rs:22:11 @@ -30,6 +34,8 @@ LL | const _: <Vec<str> as WellUnformed>::RequestNormalize = (); | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` +note: required by an implicit `Sized` bound in `Vec` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 4 previous errors diff --git a/tests/ui/wf/wf-trait-default-fn-ret.rs b/tests/ui/wf/wf-trait-default-fn-ret.rs index 2103dae8d23..a7f83dcf678 100644 --- a/tests/ui/wf/wf-trait-default-fn-ret.rs +++ b/tests/ui/wf/wf-trait-default-fn-ret.rs @@ -1,5 +1,4 @@ -// Check that we test WF conditions for fn arguments. Because the -// current code is so goofy, this is only a warning for now. +// Check that we test WF conditions for fn arguments. #![feature(rustc_attrs)] #![allow(dead_code)] diff --git a/tests/ui/wf/wf-trait-default-fn-ret.stderr b/tests/ui/wf/wf-trait-default-fn-ret.stderr index f749ac7b1b3..f0d1b55edc4 100644 --- a/tests/ui/wf/wf-trait-default-fn-ret.stderr +++ b/tests/ui/wf/wf-trait-default-fn-ret.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `Self: Eq` is not satisfied - --> $DIR/wf-trait-default-fn-ret.rs:11:22 + --> $DIR/wf-trait-default-fn-ret.rs:10:22 | LL | fn bar(&self) -> Bar<Self> { | ^^^^^^^^^ the trait `Eq` is not implemented for `Self` | note: required by a bound in `Bar` - --> $DIR/wf-trait-default-fn-ret.rs:8:14 + --> $DIR/wf-trait-default-fn-ret.rs:7:14 | LL | struct Bar<T:Eq+?Sized> { value: Box<T> } | ^^ required by this bound in `Bar` diff --git a/tests/ui/wf/wf-trait-fn-arg.next.stderr b/tests/ui/wf/wf-trait-fn-arg.next.stderr index c55dc5c8a12..d5dd36fad6d 100644 --- a/tests/ui/wf/wf-trait-fn-arg.next.stderr +++ b/tests/ui/wf/wf-trait-fn-arg.next.stderr @@ -4,6 +4,11 @@ error[E0277]: the trait bound `Self: Eq` is not satisfied LL | fn bar(&self, x: &Bar<Self>); | ^^^^^^^^^ the trait `Eq` is not implemented for `Self` | +note: required by a bound in `Bar` + --> $DIR/wf-trait-fn-arg.rs:11:15 + | +LL | struct Bar<T: Eq + ?Sized> { + | ^^ required by this bound in `Bar` help: consider further restricting `Self` | LL | fn bar(&self, x: &Bar<Self>) where Self: Eq; diff --git a/tests/ui/wf/wf-trait-fn-ret.next.stderr b/tests/ui/wf/wf-trait-fn-ret.next.stderr index b3dca17672d..0ad786c2fd5 100644 --- a/tests/ui/wf/wf-trait-fn-ret.next.stderr +++ b/tests/ui/wf/wf-trait-fn-ret.next.stderr @@ -4,6 +4,11 @@ error[E0277]: the trait bound `Self: Eq` is not satisfied LL | fn bar(&self) -> &Bar<Self>; | ^^^^^^^^^ the trait `Eq` is not implemented for `Self` | +note: required by a bound in `Bar` + --> $DIR/wf-trait-fn-ret.rs:10:15 + | +LL | struct Bar<T: Eq + ?Sized> { + | ^^ required by this bound in `Bar` help: consider further restricting `Self` | LL | fn bar(&self) -> &Bar<Self> where Self: Eq; diff --git a/tests/ui/wf/wf-trait-fn-where-clause.next.stderr b/tests/ui/wf/wf-trait-fn-where-clause.next.stderr index 8c8a5fa3e70..db5454d0f3c 100644 --- a/tests/ui/wf/wf-trait-fn-where-clause.next.stderr +++ b/tests/ui/wf/wf-trait-fn-where-clause.next.stderr @@ -4,6 +4,11 @@ error[E0277]: the trait bound `Self: Eq` is not satisfied LL | Bar<Self>: Copy; | ^^^^ the trait `Eq` is not implemented for `Self` | +note: required by a bound in `Bar` + --> $DIR/wf-trait-fn-where-clause.rs:10:15 + | +LL | struct Bar<T: Eq + ?Sized> { + | ^^ required by this bound in `Bar` help: consider further restricting `Self` | LL | Bar<Self>: Copy, Self: Eq; diff --git a/triagebot.toml b/triagebot.toml index 29c84e19c56..49cf1213987 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1025,7 +1025,6 @@ users_on_vacation = [ "nnethercote", "workingjubilee", "kobzol", - "jieyouxu", ] [[assign.warn_non_default_branch.exceptions]] |
