diff options
| author | The Miri Conjob Bot <miri@cron.bot> | 2023-12-08 05:02:11 +0000 |
|---|---|---|
| committer | The Miri Conjob Bot <miri@cron.bot> | 2023-12-08 05:02:11 +0000 |
| commit | 120b97cac1bf3e169d7bcfb8299f273c49a86b56 (patch) | |
| tree | ed8b832ae19d23665f8dc58c339bebfda0409c6d | |
| parent | a77f22047a21996e1d85b57b0a6bf57016dbb464 (diff) | |
| parent | 32e48fc36bcfc507d2e83fddc7f18d1c35605078 (diff) | |
| download | rust-120b97cac1bf3e169d7bcfb8299f273c49a86b56.tar.gz rust-120b97cac1bf3e169d7bcfb8299f273c49a86b56.zip | |
Merge from rustc
441 files changed, 6640 insertions, 2535 deletions
diff --git a/Cargo.lock b/Cargo.lock index e1b5ea30f50..7f627e2ce6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5892,6 +5892,18 @@ dependencies = [ "compiler_builtins", "core", "libc", + "unwinding", +] + +[[package]] +name = "unwinding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a19a21a537f635c16c7576f22d0f2f7d63353c1337ad4ce0d8001c7952a25b" +dependencies = [ + "compiler_builtins", + "gimli", + "rustc-std-workspace-core", ] [[package]] diff --git a/README.md b/README.md index a88ee4b8bf0..5d5beaf1b7a 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ If you wish to _contribute_ to the compiler, you should read [CONTRIBUTING.md](CONTRIBUTING.md) instead. <details> -<summary>Table of content</summary> +<summary>Table of Contents</summary> - [Quick Start](#quick-start) - [Installing from Source](#installing-from-source) diff --git a/RELEASES.md b/RELEASES.md index 5bc302305c7..9eb8755dad9 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -89,7 +89,6 @@ Rustdoc ------- - [Add warning block support in rustdoc](https://github.com/rust-lang/rust/pull/106561/) -- [Accept additional user-defined syntax classes in fenced code blocks](https://github.com/rust-lang/rust/pull/110800/) - [rustdoc-search: add support for type parameters](https://github.com/rust-lang/rust/pull/112725/) - [rustdoc: show inner enum and struct in type definition for concrete type](https://github.com/rust-lang/rust/pull/114855/) diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 756af7269f2..621516af9c0 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -484,6 +484,20 @@ impl DroplessArena { } } + /// Allocates a string slice that is copied into the `DroplessArena`, returning a + /// reference to it. Will panic if passed an empty string. + /// + /// Panics: + /// + /// - Zero-length string + #[inline] + pub fn alloc_str(&self, string: &str) -> &str { + let slice = self.alloc_slice(string.as_bytes()); + + // SAFETY: the result has a copy of the same valid UTF-8 bytes. + unsafe { std::str::from_utf8_unchecked(slice) } + } + /// # Safety /// /// The caller must ensure that `mem` is valid for writes up to `size_of::<T>() * len`, and that @@ -655,6 +669,14 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { self.dropless.alloc_slice(value) } + #[inline] + pub fn alloc_str(&self, string: &str) -> &str { + if string.is_empty() { + return ""; + } + self.dropless.alloc_str(string) + } + #[allow(clippy::mut_from_ref)] pub fn alloc_from_iter<T: ArenaAllocatable<'tcx, C>, C>( &self, diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e8731cf20f2..d6c2bfacf66 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1311,7 +1311,7 @@ pub struct Closure { pub binder: ClosureBinder, pub capture_clause: CaptureBy, pub constness: Const, - pub asyncness: Async, + pub coro_kind: Option<CoroutineKind>, pub movability: Movability, pub fn_decl: P<FnDecl>, pub body: P<Expr>, @@ -2406,28 +2406,34 @@ pub enum Unsafe { No, } +/// Describes what kind of coroutine markers, if any, a function has. +/// +/// Coroutine markers are things that cause the function to generate a coroutine, such as `async`, +/// which makes the function return `impl Future`, or `gen`, which makes the function return `impl +/// Iterator`. #[derive(Copy, Clone, Encodable, Decodable, Debug)] -pub enum Async { - Yes { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId }, - No, +pub enum CoroutineKind { + /// `async`, which evaluates to `impl Future` + Async { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId }, + /// `gen`, which evaluates to `impl Iterator` + Gen { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId }, } -#[derive(Copy, Clone, Encodable, Decodable, Debug)] -pub enum Gen { - Yes { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId }, - No, -} - -impl Async { +impl CoroutineKind { pub fn is_async(self) -> bool { - matches!(self, Async::Yes { .. }) + matches!(self, CoroutineKind::Async { .. }) + } + + pub fn is_gen(self) -> bool { + matches!(self, CoroutineKind::Gen { .. }) } - /// In this case this is an `async` return, the `NodeId` for the generated `impl Trait` item. - pub fn opt_return_id(self) -> Option<(NodeId, Span)> { + /// In this case this is an `async` or `gen` return, the `NodeId` for the generated `impl Trait` + /// item. + pub fn return_id(self) -> (NodeId, Span) { match self { - Async::Yes { return_impl_trait_id, span, .. } => Some((return_impl_trait_id, span)), - Async::No => None, + CoroutineKind::Async { return_impl_trait_id, span, .. } + | CoroutineKind::Gen { return_impl_trait_id, span, .. } => (return_impl_trait_id, span), } } } @@ -2831,8 +2837,8 @@ impl Extern { pub struct FnHeader { /// The `unsafe` keyword, if any pub unsafety: Unsafe, - /// The `async` keyword, if any - pub asyncness: Async, + /// Whether this is `async`, `gen`, or nothing. + pub coro_kind: Option<CoroutineKind>, /// The `const` keyword, if any pub constness: Const, /// The `extern` keyword and corresponding ABI string, if any @@ -2842,9 +2848,9 @@ pub struct FnHeader { impl FnHeader { /// Does this function header have any qualifiers or is it empty? pub fn has_qualifiers(&self) -> bool { - let Self { unsafety, asyncness, constness, ext } = self; + let Self { unsafety, coro_kind, constness, ext } = self; matches!(unsafety, Unsafe::Yes(_)) - || asyncness.is_async() + || coro_kind.is_some() || matches!(constness, Const::Yes(_)) || !matches!(ext, Extern::None) } @@ -2852,12 +2858,7 @@ impl FnHeader { impl Default for FnHeader { fn default() -> FnHeader { - FnHeader { - unsafety: Unsafe::No, - asyncness: Async::No, - constness: Const::No, - ext: Extern::None, - } + FnHeader { unsafety: Unsafe::No, coro_kind: None, constness: Const::No, ext: Extern::None } } } @@ -3177,7 +3178,7 @@ mod size_asserts { static_assert_size!(Block, 32); static_assert_size!(Expr, 72); static_assert_size!(ExprKind, 40); - static_assert_size!(Fn, 152); + static_assert_size!(Fn, 160); static_assert_size!(ForeignItem, 96); static_assert_size!(ForeignItemKind, 24); static_assert_size!(GenericArg, 24); diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 8ce86bf9ecf..c6a31fbdbc3 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -121,8 +121,8 @@ pub trait MutVisitor: Sized { noop_visit_fn_decl(d, self); } - fn visit_asyncness(&mut self, a: &mut Async) { - noop_visit_asyncness(a, self); + fn visit_coro_kind(&mut self, a: &mut CoroutineKind) { + noop_visit_coro_kind(a, self); } fn visit_closure_binder(&mut self, b: &mut ClosureBinder) { @@ -871,13 +871,14 @@ pub fn noop_visit_closure_binder<T: MutVisitor>(binder: &mut ClosureBinder, vis: } } -pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut Async, vis: &mut T) { - match asyncness { - Async::Yes { span: _, closure_id, return_impl_trait_id } => { +pub fn noop_visit_coro_kind<T: MutVisitor>(coro_kind: &mut CoroutineKind, vis: &mut T) { + match coro_kind { + CoroutineKind::Async { span, closure_id, return_impl_trait_id } + | CoroutineKind::Gen { span, closure_id, return_impl_trait_id } => { + vis.visit_span(span); vis.visit_id(closure_id); vis.visit_id(return_impl_trait_id); } - Async::No => {} } } @@ -1170,9 +1171,9 @@ fn visit_const_item<T: MutVisitor>( } pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) { - let FnHeader { unsafety, asyncness, constness, ext: _ } = header; + let FnHeader { unsafety, coro_kind, constness, ext: _ } = header; visit_constness(constness, vis); - vis.visit_asyncness(asyncness); + coro_kind.as_mut().map(|coro_kind| vis.visit_coro_kind(coro_kind)); visit_unsafety(unsafety, vis); } @@ -1406,7 +1407,7 @@ pub fn noop_visit_expr<T: MutVisitor>( binder, capture_clause, constness, - asyncness, + coro_kind, movability: _, fn_decl, body, @@ -1415,7 +1416,7 @@ pub fn noop_visit_expr<T: MutVisitor>( }) => { vis.visit_closure_binder(binder); visit_constness(constness, vis); - vis.visit_asyncness(asyncness); + coro_kind.as_mut().map(|coro_kind| vis.visit_coro_kind(coro_kind)); vis.visit_capture_by(capture_clause); vis.visit_fn_decl(fn_decl); vis.visit_expr(body); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 9dbadcb49d3..a303d6584f4 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -861,7 +861,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::Closure(box Closure { binder, capture_clause, - asyncness: _, + coro_kind: _, constness: _, movability: _, fn_decl, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index eb1a1d15027..3556ee02bd7 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -195,39 +195,39 @@ impl<'hir> LoweringContext<'_, 'hir> { binder, capture_clause, constness, - asyncness, + coro_kind, movability, fn_decl, body, fn_decl_span, fn_arg_span, - }) => { - if let Async::Yes { closure_id, .. } = asyncness { - self.lower_expr_async_closure( - binder, - *capture_clause, - e.id, - hir_id, - *closure_id, - fn_decl, - body, - *fn_decl_span, - *fn_arg_span, - ) - } else { - self.lower_expr_closure( - binder, - *capture_clause, - e.id, - *constness, - *movability, - fn_decl, - body, - *fn_decl_span, - *fn_arg_span, - ) - } - } + }) => match coro_kind { + Some( + CoroutineKind::Async { closure_id, .. } + | CoroutineKind::Gen { closure_id, .. }, + ) => self.lower_expr_async_closure( + binder, + *capture_clause, + e.id, + hir_id, + *closure_id, + fn_decl, + body, + *fn_decl_span, + *fn_arg_span, + ), + None => self.lower_expr_closure( + binder, + *capture_clause, + e.id, + *constness, + *movability, + fn_decl, + body, + *fn_decl_span, + *fn_arg_span, + ), + }, ExprKind::Block(blk, opt_label) => { let opt_label = self.lower_label(*opt_label); hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index f0f3e2c3c74..80854c8a6c0 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -206,15 +206,19 @@ impl<'hir> LoweringContext<'_, 'hir> { // `impl Future<Output = T>` here because lower_body // only cares about the input argument patterns in the function // declaration (decl), not the return types. - let asyncness = header.asyncness; - let body_id = - this.lower_maybe_async_body(span, hir_id, decl, asyncness, body.as_deref()); + let coro_kind = header.coro_kind; + let body_id = this.lower_maybe_coroutine_body( + span, + hir_id, + decl, + coro_kind, + body.as_deref(), + ); let itctx = ImplTraitContext::Universal; let (generics, decl) = this.lower_generics(generics, header.constness, id, &itctx, |this| { - let ret_id = asyncness.opt_return_id(); - this.lower_fn_decl(decl, id, *fn_sig_span, FnDeclKind::Fn, ret_id) + this.lower_fn_decl(decl, id, *fn_sig_span, FnDeclKind::Fn, coro_kind) }); let sig = hir::FnSig { decl, @@ -561,11 +565,10 @@ impl<'hir> LoweringContext<'_, 'hir> { .params .iter() .find(|param| { - parent_hir - .attrs - .get(param.hir_id.local_id) - .iter() - .any(|attr| attr.has_name(sym::rustc_host)) + matches!( + param.kind, + hir::GenericParamKind::Const { is_host_effect: true, .. } + ) }) .map(|param| param.def_id); } @@ -725,27 +728,30 @@ impl<'hir> LoweringContext<'_, 'hir> { (generics, kind, expr.is_some()) } AssocItemKind::Fn(box Fn { sig, generics, body: None, .. }) => { - let asyncness = sig.header.asyncness; let names = self.lower_fn_params_to_names(&sig.decl); let (generics, sig) = self.lower_method_sig( generics, sig, i.id, FnDeclKind::Trait, - asyncness.opt_return_id(), + sig.header.coro_kind, ); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false) } AssocItemKind::Fn(box Fn { sig, generics, body: Some(body), .. }) => { - let asyncness = sig.header.asyncness; - let body_id = - self.lower_maybe_async_body(i.span, hir_id, &sig.decl, asyncness, Some(body)); + let body_id = self.lower_maybe_coroutine_body( + i.span, + hir_id, + &sig.decl, + sig.header.coro_kind, + Some(body), + ); let (generics, sig) = self.lower_method_sig( generics, sig, i.id, FnDeclKind::Trait, - asyncness.opt_return_id(), + sig.header.coro_kind, ); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true) } @@ -834,12 +840,11 @@ impl<'hir> LoweringContext<'_, 'hir> { }, ), AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => { - let asyncness = sig.header.asyncness; - let body_id = self.lower_maybe_async_body( + let body_id = self.lower_maybe_coroutine_body( i.span, hir_id, &sig.decl, - asyncness, + sig.header.coro_kind, body.as_deref(), ); let (generics, sig) = self.lower_method_sig( @@ -847,7 +852,7 @@ impl<'hir> LoweringContext<'_, 'hir> { sig, i.id, if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent }, - asyncness.opt_return_id(), + sig.header.coro_kind, ); (generics, hir::ImplItemKind::Fn(sig, body_id)) @@ -1011,17 +1016,23 @@ impl<'hir> LoweringContext<'_, 'hir> { }) } - fn lower_maybe_async_body( + /// Takes what may be the body of an `async fn` or a `gen fn` and wraps it in an `async {}` or + /// `gen {}` block as appropriate. + fn lower_maybe_coroutine_body( &mut self, span: Span, fn_id: hir::HirId, decl: &FnDecl, - asyncness: Async, + coro_kind: Option<CoroutineKind>, body: Option<&Block>, ) -> hir::BodyId { - let (closure_id, body) = match (asyncness, body) { - (Async::Yes { closure_id, .. }, Some(body)) => (closure_id, body), - _ => return self.lower_fn_body_block(span, decl, body), + let (Some(coro_kind), Some(body)) = (coro_kind, body) else { + return self.lower_fn_body_block(span, decl, body); + }; + let closure_id = match coro_kind { + CoroutineKind::Async { closure_id, .. } | CoroutineKind::Gen { closure_id, .. } => { + closure_id + } }; self.lower_body(|this| { @@ -1163,44 +1174,54 @@ impl<'hir> LoweringContext<'_, 'hir> { parameters.push(new_parameter); } - let async_expr = this.make_async_expr( - CaptureBy::Value { move_kw: rustc_span::DUMMY_SP }, - closure_id, - None, - body.span, - hir::CoroutineSource::Fn, - |this| { - // Create a block from the user's function body: - let user_body = this.lower_block_expr(body); + let mkbody = |this: &mut LoweringContext<'_, 'hir>| { + // Create a block from the user's function body: + let user_body = this.lower_block_expr(body); - // Transform into `drop-temps { <user-body> }`, an expression: - let desugared_span = - this.mark_span_with_reason(DesugaringKind::Async, user_body.span, None); - let user_body = - this.expr_drop_temps(desugared_span, this.arena.alloc(user_body)); + // Transform into `drop-temps { <user-body> }`, an expression: + let desugared_span = + this.mark_span_with_reason(DesugaringKind::Async, user_body.span, None); + let user_body = this.expr_drop_temps(desugared_span, this.arena.alloc(user_body)); - // As noted above, create the final block like - // - // ``` - // { - // let $param_pattern = $raw_param; - // ... - // drop-temps { <user-body> } - // } - // ``` - let body = this.block_all( - desugared_span, - this.arena.alloc_from_iter(statements), - Some(user_body), - ); + // As noted above, create the final block like + // + // ``` + // { + // let $param_pattern = $raw_param; + // ... + // drop-temps { <user-body> } + // } + // ``` + let body = this.block_all( + desugared_span, + this.arena.alloc_from_iter(statements), + Some(user_body), + ); - this.expr_block(body) - }, - ); + this.expr_block(body) + }; + let coroutine_expr = match coro_kind { + CoroutineKind::Async { .. } => this.make_async_expr( + CaptureBy::Value { move_kw: rustc_span::DUMMY_SP }, + closure_id, + None, + body.span, + hir::CoroutineSource::Fn, + mkbody, + ), + CoroutineKind::Gen { .. } => this.make_gen_expr( + CaptureBy::Value { move_kw: rustc_span::DUMMY_SP }, + closure_id, + None, + body.span, + hir::CoroutineSource::Fn, + mkbody, + ), + }; let hir_id = this.lower_node_id(closure_id); this.maybe_forward_track_caller(body.span, fn_id, hir_id); - let expr = hir::Expr { hir_id, kind: async_expr, span: this.lower_span(body.span) }; + let expr = hir::Expr { hir_id, kind: coroutine_expr, span: this.lower_span(body.span) }; (this.arena.alloc_from_iter(parameters), expr) }) @@ -1212,21 +1233,26 @@ impl<'hir> LoweringContext<'_, 'hir> { sig: &FnSig, id: NodeId, kind: FnDeclKind, - is_async: Option<(NodeId, Span)>, + coro_kind: Option<CoroutineKind>, ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) { let header = self.lower_fn_header(sig.header); let itctx = ImplTraitContext::Universal; let (generics, decl) = self.lower_generics(generics, sig.header.constness, id, &itctx, |this| { - this.lower_fn_decl(&sig.decl, id, sig.span, kind, is_async) + this.lower_fn_decl(&sig.decl, id, sig.span, kind, coro_kind) }); (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) } fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader { + let asyncness = if let Some(CoroutineKind::Async { span, .. }) = h.coro_kind { + hir::IsAsync::Async(span) + } else { + hir::IsAsync::NotAsync + }; hir::FnHeader { unsafety: self.lower_unsafety(h.unsafety), - asyncness: self.lower_asyncness(h.asyncness), + asyncness: asyncness, constness: self.lower_constness(h.constness), abi: self.lower_extern(h.ext), } @@ -1268,13 +1294,6 @@ impl<'hir> LoweringContext<'_, 'hir> { }); } - fn lower_asyncness(&mut self, a: Async) -> hir::IsAsync { - match a { - Async::Yes { span, .. } => hir::IsAsync::Async(span), - Async::No => hir::IsAsync::NotAsync, - } - } - pub(super) fn lower_constness(&mut self, c: Const) -> hir::Constness { match c { Const::Yes(_) => hir::Constness::Const, @@ -1352,27 +1371,17 @@ impl<'hir> LoweringContext<'_, 'hir> { let host_param_parts = if let Const::Yes(span) = constness && self.tcx.features().effects { - if let Some(param) = - generics.params.iter().find(|x| x.attrs.iter().any(|x| x.has_name(sym::rustc_host))) - { - // user has manually specified a `rustc_host` param, in this case, we set - // the param id so that lowering logic can use that. But we don't create - // another host param, so this gives `None`. - self.host_param_id = Some(self.local_def_id(param.id)); - None - } else { - let param_node_id = self.next_node_id(); - let hir_id = self.next_id(); - let def_id = self.create_def( - self.local_def_id(parent_node_id), - param_node_id, - sym::host, - DefKind::ConstParam, - span, - ); - self.host_param_id = Some(def_id); - Some((span, hir_id, def_id)) - } + let param_node_id = self.next_node_id(); + let hir_id = self.next_id(); + let def_id = self.create_def( + self.local_def_id(parent_node_id), + param_node_id, + sym::host, + DefKind::ConstParam, + span, + ); + self.host_param_id = Some(def_id); + Some((span, hir_id, def_id)) } else { None }; @@ -1436,19 +1445,6 @@ impl<'hir> LoweringContext<'_, 'hir> { self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); self.children.push((anon_const, hir::MaybeOwner::NonOwner(const_id))); - let attr_id = self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id(); - - let attrs = self.arena.alloc_from_iter([Attribute { - kind: AttrKind::Normal(P(NormalAttr::from_ident(Ident::new( - sym::rustc_host, - span, - )))), - span, - id: attr_id, - style: AttrStyle::Outer, - }]); - self.attrs.insert(hir_id.local_id, attrs); - let const_body = self.lower_body(|this| { ( &[], @@ -1490,6 +1486,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir_id: const_id, body: const_body, }), + is_host_effect: true, }, colon_span: None, pure_wrt_drop: false, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index aa8ad978451..5dda8f5a6a3 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1778,13 +1778,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { })) } - // Lowers a function declaration. - // - // `decl`: the unlowered (AST) function declaration. - // `fn_node_id`: `impl Trait` arguments are lowered into generic parameters on the given `NodeId`. - // `make_ret_async`: if `Some`, converts `-> T` into `-> impl Future<Output = T>` in the - // return type. This is used for `async fn` declarations. The `NodeId` is the ID of the - // return type `impl Trait` item, and the `Span` points to the `async` keyword. + /// Lowers a function declaration. + /// + /// `decl`: the unlowered (AST) function declaration. + /// + /// `fn_node_id`: `impl Trait` arguments are lowered into generic parameters on the given + /// `NodeId`. + /// + /// `transform_return_type`: if `Some`, applies some conversion to the return type, such as is + /// needed for `async fn` and `gen fn`. See [`CoroutineKind`] for more details. #[instrument(level = "debug", skip(self))] fn lower_fn_decl( &mut self, @@ -1792,7 +1794,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn_node_id: NodeId, fn_span: Span, kind: FnDeclKind, - make_ret_async: Option<(NodeId, Span)>, + coro: Option<CoroutineKind>, ) -> &'hir hir::FnDecl<'hir> { let c_variadic = decl.c_variadic(); @@ -1821,11 +1823,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_ty_direct(¶m.ty, &itctx) })); - let output = if let Some((ret_id, _span)) = make_ret_async { - let fn_def_id = self.local_def_id(fn_node_id); - self.lower_async_fn_ret_ty(&decl.output, fn_def_id, ret_id, kind, fn_span) - } else { - match &decl.output { + let output = match coro { + Some(coro) => { + let fn_def_id = self.local_def_id(fn_node_id); + self.lower_coroutine_fn_ret_ty(&decl.output, fn_def_id, coro, kind, fn_span) + } + None => match &decl.output { FnRetTy::Ty(ty) => { let context = if kind.return_impl_trait_allowed() { let fn_def_id = self.local_def_id(fn_node_id); @@ -1849,7 +1852,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::FnRetTy::Return(self.lower_ty(ty, &context)) } FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(*span)), - } + }, }; self.arena.alloc(hir::FnDecl { @@ -1888,17 +1891,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // `fn_node_id`: `NodeId` of the parent function (used to create child impl trait definition) // `opaque_ty_node_id`: `NodeId` of the opaque `impl Trait` type that should be created #[instrument(level = "debug", skip(self))] - fn lower_async_fn_ret_ty( + fn lower_coroutine_fn_ret_ty( &mut self, output: &FnRetTy, fn_def_id: LocalDefId, - opaque_ty_node_id: NodeId, + coro: CoroutineKind, fn_kind: FnDeclKind, fn_span: Span, ) -> hir::FnRetTy<'hir> { let span = self.lower_span(fn_span); let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None); + let opaque_ty_node_id = match coro { + CoroutineKind::Async { return_impl_trait_id, .. } + | CoroutineKind::Gen { return_impl_trait_id, .. } => return_impl_trait_id, + }; + let captured_lifetimes: Vec<_> = self .resolver .take_extra_lifetime_params(opaque_ty_node_id) @@ -1914,15 +1922,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span, opaque_ty_span, |this| { - let future_bound = this.lower_async_fn_output_type_to_future_bound( + let bound = this.lower_coroutine_fn_output_type_to_bound( output, + coro, span, ImplTraitContext::ReturnPositionOpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), fn_kind, }, ); - arena_vec![this; future_bound] + arena_vec![this; bound] }, ); @@ -1931,9 +1940,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } /// Transforms `-> T` into `Future<Output = T>`. - fn lower_async_fn_output_type_to_future_bound( + fn lower_coroutine_fn_output_type_to_bound( &mut self, output: &FnRetTy, + coro: CoroutineKind, span: Span, nested_impl_trait_context: ImplTraitContext, ) -> hir::GenericBound<'hir> { @@ -1948,17 +1958,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])), }; - // "<Output = T>" + // "<$assoc_ty_name = T>" + let (assoc_ty_name, trait_lang_item) = match coro { + CoroutineKind::Async { .. } => (hir::FN_OUTPUT_NAME, hir::LangItem::Future), + CoroutineKind::Gen { .. } => (hir::ITERATOR_ITEM_NAME, hir::LangItem::Iterator), + }; + let future_args = self.arena.alloc(hir::GenericArgs { args: &[], - bindings: arena_vec![self; self.output_ty_binding(span, output_ty)], + bindings: arena_vec![self; self.assoc_ty_binding(assoc_ty_name, span, output_ty)], parenthesized: hir::GenericArgsParentheses::No, span_ext: DUMMY_SP, }); hir::GenericBound::LangItemTrait( - // ::std::future::Future<future_params> - hir::LangItem::Future, + trait_lang_item, self.lower_span(span), self.next_id(), future_args, @@ -2108,7 +2122,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let default = default.as_ref().map(|def| self.lower_anon_const(def)); ( hir::ParamName::Plain(self.lower_ident(param.ident)), - hir::GenericParamKind::Const { ty, default }, + hir::GenericParamKind::Const { ty, default, is_host_effect: false }, ) } } @@ -2536,15 +2550,6 @@ impl<'hir> GenericArgsCtor<'hir> { }) }); - let attr_id = lcx.tcx.sess.parse_sess.attr_id_generator.mk_attr_id(); - let attr = lcx.arena.alloc(Attribute { - kind: AttrKind::Normal(P(NormalAttr::from_ident(Ident::new(sym::rustc_host, span)))), - span, - id: attr_id, - style: AttrStyle::Outer, - }); - lcx.attrs.insert(hir_id.local_id, std::slice::from_ref(attr)); - let def_id = lcx.create_def( lcx.current_hir_id_owner.def_id, id, @@ -2552,6 +2557,7 @@ impl<'hir> GenericArgsCtor<'hir> { DefKind::AnonConst, span, ); + lcx.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); self.args.push(hir::GenericArg::Const(hir::ConstArg { value: hir::AnonConst { def_id, hir_id, body }, diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index db8ca7c3643..7ab0805d086 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -389,7 +389,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])), }; let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))]; - let binding = self.output_ty_binding(output_ty.span, output_ty); + let binding = self.assoc_ty_binding(hir::FN_OUTPUT_NAME, output_ty.span, output_ty); ( GenericArgsCtor { args, @@ -401,13 +401,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) } - /// An associated type binding `Output = $ty`. - pub(crate) fn output_ty_binding( + /// An associated type binding `$assoc_ty_name = $ty`. + pub(crate) fn assoc_ty_binding( &mut self, + assoc_ty_name: rustc_span::Symbol, span: Span, ty: &'hir hir::Ty<'hir>, ) -> hir::TypeBinding<'hir> { - let ident = Ident::with_dummy_span(hir::FN_OUTPUT_NAME); + let ident = Ident::with_dummy_span(assoc_ty_name); let kind = hir::TypeBindingKind::Equality { term: ty.into() }; let args = arena_vec![self;]; let bindings = arena_vec![self;]; diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 45b5e63bd1b..554ed36b814 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1268,13 +1268,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_c_variadic_type(fk); - // Functions cannot both be `const async` + // Functions cannot both be `const async` or `const gen` if let Some(&FnHeader { constness: Const::Yes(cspan), - asyncness: Async::Yes { span: aspan, .. }, + coro_kind: + Some( + CoroutineKind::Async { span: aspan, .. } + | CoroutineKind::Gen { span: aspan, .. }, + ), .. }) = fk.header() { + // FIXME(gen_blocks): Report a different error for `const gen` self.err_handler().emit_err(errors::ConstAndAsync { spans: vec![cspan, aspan], cspan, diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index cbdcc683b56..1ad28ffbf2b 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1490,9 +1490,14 @@ impl<'a> State<'a> { } } - fn print_asyncness(&mut self, asyncness: ast::Async) { - if asyncness.is_async() { - self.word_nbsp("async"); + fn print_coro_kind(&mut self, coro_kind: ast::CoroutineKind) { + match coro_kind { + ast::CoroutineKind::Gen { .. } => { + self.word_nbsp("gen"); + } + ast::CoroutineKind::Async { .. } => { + self.word_nbsp("async"); + } } } @@ -1685,7 +1690,7 @@ impl<'a> State<'a> { fn print_fn_header_info(&mut self, header: ast::FnHeader) { self.print_constness(header.constness); - self.print_asyncness(header.asyncness); + header.coro_kind.map(|coro_kind| self.print_coro_kind(coro_kind)); self.print_unsafety(header.unsafety); match header.ext { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 45a55e20ca7..0082d6e350e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -413,7 +413,7 @@ impl<'a> State<'a> { binder, capture_clause, constness, - asyncness, + coro_kind, movability, fn_decl, body, @@ -423,7 +423,7 @@ impl<'a> State<'a> { self.print_closure_binder(binder); self.print_constness(*constness); self.print_movability(*movability); - self.print_asyncness(*asyncness); + coro_kind.map(|coro_kind| self.print_coro_kind(coro_kind)); self.print_capture_clause(*capture_clause); self.print_fn_params_and_ret(fn_decl, true); diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 4deed98d002..1844e766a82 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -11,6 +11,7 @@ use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::CoroutineKind; use rustc_index::IndexSlice; use rustc_infer::infer::BoundRegionConversionTime; +use rustc_infer::traits::{FulfillmentErrorCode, SelectionError}; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ AggregateKind, CallSource, ConstOperand, FakeReadCause, Local, LocalInfo, LocalKind, Location, @@ -24,10 +25,9 @@ use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult}; use rustc_span::def_id::LocalDefId; use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; use rustc_target::abi::{FieldIdx, VariantIdx}; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; -use rustc_trait_selection::traits::{ - type_known_to_meet_bound_modulo_regions, Obligation, ObligationCause, -}; +use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _; +use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions; use super::borrow_set::BorrowData; use super::MirBorrowckCtxt; @@ -1043,7 +1043,38 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } CallKind::Normal { self_arg, desugaring, method_did, method_args } => { let self_arg = self_arg.unwrap(); + let mut has_sugg = false; let tcx = self.infcx.tcx; + // Avoid pointing to the same function in multiple different + // error messages. + if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) { + self.explain_iterator_advancement_in_for_loop_if_applicable( + err, + span, + &move_spans, + ); + + let func = tcx.def_path_str(method_did); + err.subdiagnostic(CaptureReasonNote::FuncTakeSelf { + func, + place_name: place_name.clone(), + span: self_arg.span, + }); + } + let parent_did = tcx.parent(method_did); + let parent_self_ty = + matches!(tcx.def_kind(parent_did), rustc_hir::def::DefKind::Impl { .. }) + .then_some(parent_did) + .and_then(|did| match tcx.type_of(did).instantiate_identity().kind() { + ty::Adt(def, ..) => Some(def.did()), + _ => None, + }); + let is_option_or_result = parent_self_ty.is_some_and(|def_id| { + matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result)) + }); + if is_option_or_result && maybe_reinitialized_locations_is_empty { + err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span }); + } if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring { let ty = moved_place.ty(self.body, tcx).ty; let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) { @@ -1108,7 +1139,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Erase and shadow everything that could be passed to the new infcx. let ty = moved_place.ty(self.body, tcx).ty; - if let ty::Adt(def, args) = ty.kind() + if let ty::Adt(def, args) = ty.peel_refs().kind() && Some(def.did()) == tcx.lang_items().pin_type() && let ty::Ref(_, _, hir::Mutability::Mut) = args.type_at(0).kind() && let self_ty = self.infcx.instantiate_binder_with_fresh_vars( @@ -1124,56 +1155,76 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { span: move_span.shrink_to_hi(), }, ); + has_sugg = true; } - if let Some(clone_trait) = tcx.lang_items().clone_trait() - && let trait_ref = ty::TraitRef::new(tcx, clone_trait, [ty]) - && let o = Obligation::new( - tcx, - ObligationCause::dummy(), - self.param_env, - ty::Binder::dummy(trait_ref), - ) - && self.infcx.predicate_must_hold_modulo_regions(&o) - { - err.span_suggestion_verbose( - move_span.shrink_to_hi(), - "you can `clone` the value and consume it, but this might not be \ - your desired behavior", - ".clone()".to_string(), - Applicability::MaybeIncorrect, - ); + if let Some(clone_trait) = tcx.lang_items().clone_trait() { + let sugg = if moved_place + .iter_projections() + .any(|(_, elem)| matches!(elem, ProjectionElem::Deref)) + { + vec![ + // We use the fully-qualified path because `.clone()` can + // sometimes choose `<&T as Clone>` instead of `<T as Clone>` + // when going through auto-deref, so this ensures that doesn't + // happen, causing suggestions for `.clone().clone()`. + (move_span.shrink_to_lo(), format!("<{ty} as Clone>::clone(&")), + (move_span.shrink_to_hi(), ")".to_string()), + ] + } else { + vec![(move_span.shrink_to_hi(), ".clone()".to_string())] + }; + if let Some(errors) = + self.infcx.could_impl_trait(clone_trait, ty, self.param_env) + && !has_sugg + { + let msg = match &errors[..] { + [] => "you can `clone` the value and consume it, but this \ + might not be your desired behavior" + .to_string(), + [error] => { + format!( + "you could `clone` the value and consume it, if \ + the `{}` trait bound could be satisfied", + 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, + ) + } + }; + err.multipart_suggestion_verbose( + msg, + sugg.clone(), + Applicability::MaybeIncorrect, + ); + for error in errors { + if let FulfillmentErrorCode::CodeSelectionError( + SelectionError::Unimplemented, + ) = error.code + && let ty::PredicateKind::Clause(ty::ClauseKind::Trait( + pred, + )) = error.obligation.predicate.kind().skip_binder() + { + self.infcx.err_ctxt().suggest_derive( + &error.obligation, + err, + error.obligation.predicate.kind().rebind(pred), + ); + } + } + } } } - // Avoid pointing to the same function in multiple different - // error messages. - if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) { - self.explain_iterator_advancement_in_for_loop_if_applicable( - err, - span, - &move_spans, - ); - - let func = tcx.def_path_str(method_did); - err.subdiagnostic(CaptureReasonNote::FuncTakeSelf { - func, - place_name, - span: self_arg.span, - }); - } - let parent_did = tcx.parent(method_did); - let parent_self_ty = - matches!(tcx.def_kind(parent_did), rustc_hir::def::DefKind::Impl { .. }) - .then_some(parent_did) - .and_then(|did| match tcx.type_of(did).instantiate_identity().kind() { - ty::Adt(def, ..) => Some(def.did()), - _ => None, - }); - let is_option_or_result = parent_self_ty.is_some_and(|def_id| { - matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result)) - }); - if is_option_or_result && maybe_reinitialized_locations_is_empty { - err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span }); - } } // Other desugarings takes &self, which cannot cause a move _ => {} diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index d9ec2860962..8fe552708ed 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -3,8 +3,9 @@ use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed use rustc_hir as hir; use rustc_hir::intravisit::Visitor; use rustc_hir::Node; +use rustc_infer::traits; use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem}; -use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt}; +use rustc_middle::ty::{self, InstanceDef, ToPredicate, Ty, TyCtxt}; use rustc_middle::{ hir::place::PlaceBase, mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location}, @@ -12,6 +13,8 @@ use rustc_middle::{ use rustc_span::symbol::{kw, Symbol}; use rustc_span::{sym, BytePos, DesugaringKind, Span}; use rustc_target::abi::FieldIdx; +use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; use crate::diagnostics::BorrowedContentSource; use crate::util::FindAssignments; @@ -1212,6 +1215,103 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let Some(hir_id) = hir_id && let Some(hir::Node::Local(local)) = hir_map.find(hir_id) { + let tables = self.infcx.tcx.typeck(def_id.as_local().unwrap()); + if let Some(clone_trait) = self.infcx.tcx.lang_items().clone_trait() + && let Some(expr) = local.init + && let ty = tables.node_type_opt(expr.hir_id) + && let Some(ty) = ty + && let ty::Ref(..) = ty.kind() + { + match self + .infcx + .could_impl_trait(clone_trait, ty.peel_refs(), self.param_env) + .as_deref() + { + Some([]) => { + // The type implements Clone. + err.span_help( + expr.span, + format!( + "you can `clone` the `{}` value and consume it, but this \ + might not be your desired behavior", + ty.peel_refs(), + ), + ); + } + None => { + if let hir::ExprKind::MethodCall(segment, _rcvr, [], span) = + expr.kind + && segment.ident.name == sym::clone + { + err.span_help( + span, + format!( + "`{}` doesn't implement `Clone`, so this call clones \ + the reference `{ty}`", + ty.peel_refs(), + ), + ); + } + // The type doesn't implement Clone. + let trait_ref = ty::Binder::dummy(ty::TraitRef::new( + self.infcx.tcx, + clone_trait, + [ty.peel_refs()], + )); + let obligation = traits::Obligation::new( + self.infcx.tcx, + traits::ObligationCause::dummy(), + self.param_env, + trait_ref, + ); + self.infcx.err_ctxt().suggest_derive( + &obligation, + err, + trait_ref.to_predicate(self.infcx.tcx), + ); + } + Some(errors) => { + if let hir::ExprKind::MethodCall(segment, _rcvr, [], span) = + expr.kind + && segment.ident.name == sym::clone + { + err.span_help( + span, + format!( + "`{}` doesn't implement `Clone` because its \ + implementations trait bounds could not be met, so \ + this call clones the reference `{ty}`", + ty.peel_refs(), + ), + ); + err.note(format!( + "the following trait bounds weren't met: {}", + errors + .iter() + .map(|e| e.obligation.predicate.to_string()) + .collect::<Vec<_>>() + .join("\n"), + )); + } + // The type doesn't implement Clone because of unmet obligations. + for error in errors { + if let traits::FulfillmentErrorCode::CodeSelectionError( + traits::SelectionError::Unimplemented, + ) = error.code + && let ty::PredicateKind::Clause(ty::ClauseKind::Trait( + pred, + )) = error.obligation.predicate.kind().skip_binder() + { + self.infcx.err_ctxt().suggest_derive( + &error.obligation, + err, + error.obligation.predicate.kind().rebind(pred), + ); + } + } + } + } + } let (changing, span, sugg) = match local.ty { Some(ty) => ("changing", ty.span, message), None => { diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index fde4270334b..0a3af2c2e13 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -1,5 +1,5 @@ use rustc_errors::{ - AddToDiagnostic, DiagnosticBuilder, EmissionGuarantee, Handler, IntoDiagnostic, MultiSpan, + AddToDiagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, MultiSpan, SingleLabelManySpans, }; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -446,9 +446,9 @@ pub(crate) struct EnvNotDefinedWithUserMessage { } // Hand-written implementation to support custom user messages. -impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefinedWithUserMessage { +impl<'a> IntoDiagnostic<'a> for EnvNotDefinedWithUserMessage { #[track_caller] - fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G> { + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> { #[expect( rustc::untranslatable_diagnostic, reason = "cannot translate user-provided messages" @@ -801,8 +801,8 @@ pub(crate) struct AsmClobberNoReg { pub(crate) clobbers: Vec<Span>, } -impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for AsmClobberNoReg { - fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G> { +impl<'a> IntoDiagnostic<'a> for AsmClobberNoReg { + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> { let mut diag = handler.struct_diagnostic(crate::fluent_generated::builtin_macros_asm_clobber_no_reg); diag.set_span(self.spans.clone()); diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index bf1e1ebf5dd..81433155ecf 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -541,10 +541,14 @@ fn check_test_signature( return Err(sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" })); } - if let ast::Async::Yes { span, .. } = f.sig.header.asyncness { + if let Some(ast::CoroutineKind::Async { span, .. }) = f.sig.header.coro_kind { return Err(sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "async" })); } + if let Some(ast::CoroutineKind::Gen { span, .. }) = f.sig.header.coro_kind { + return Err(sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "gen" })); + } + // If the termination trait is active, the compiler will check that the output // type implements the `Termination` trait as `libtest` enforces that. let has_output = match &f.sig.decl.output { diff --git a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs index 20f2ee4c76a..978891f2b0d 100644 --- a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs +++ b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs @@ -64,7 +64,7 @@ impl ConcurrencyLimiter { // Make sure to drop the mutex guard first to prevent poisoning the mutex. drop(state); if let Some(err) = err { - handler.fatal(err).raise(); + handler.fatal(err); } else { // The error was already emitted, but compilation continued. Raise a silent // fatal error. diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index cf68a3857c5..65f7ee6999a 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -126,7 +126,8 @@ pub(crate) fn codegen_const_value<'tcx>( } } Scalar::Ptr(ptr, _size) => { - let (alloc_id, offset) = ptr.into_parts(); // we know the `offset` is relative + let (prov, offset) = ptr.into_parts(); // we know the `offset` is relative + let alloc_id = prov.alloc_id(); let base_addr = match fx.tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => { let data_id = data_id_for_alloc_id( @@ -374,7 +375,8 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()).to_vec(); data.define(bytes.into_boxed_slice()); - for &(offset, alloc_id) in alloc.provenance().ptrs().iter() { + for &(offset, prov) in alloc.provenance().ptrs().iter() { + let alloc_id = prov.alloc_id(); let addend = { let endianness = tcx.data_layout.endian; let offset = offset.bytes() as usize; diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock index 7c186336927..ddfce5d59bd 100644 --- a/compiler/rustc_codegen_gcc/Cargo.lock +++ b/compiler/rustc_codegen_gcc/Cargo.lock @@ -120,9 +120,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.147" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "linux-raw-sys" diff --git a/compiler/rustc_codegen_gcc/example/std_example.rs b/compiler/rustc_codegen_gcc/example/std_example.rs index 0f6325c8980..ad69409eb65 100644 --- a/compiler/rustc_codegen_gcc/example/std_example.rs +++ b/compiler/rustc_codegen_gcc/example/std_example.rs @@ -1,3 +1,4 @@ +#![allow(internal_features)] #![feature(core_intrinsics, coroutines, coroutine_trait, is_sorted)] #[cfg(feature="master")] diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 93fe27e547a..b7ddc410315 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -199,7 +199,8 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } } Scalar::Ptr(ptr, _size) => { - let (alloc_id, offset) = ptr.into_parts(); + let (prov, offset) = ptr.into_parts(); // we know the `offset` is relative + let alloc_id = prov.alloc_id(); let base_addr = match self.tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => { diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index d8a1fd315c0..f06416b9bb5 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -285,7 +285,8 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl let pointer_size = dl.pointer_size.bytes() as usize; let mut next_offset = 0; - for &(offset, alloc_id) in alloc.provenance().ptrs().iter() { + for &(offset, prov) in alloc.provenance().ptrs().iter() { + let alloc_id = prov.alloc_id(); let offset = offset.bytes(); assert_eq!(offset as usize as u64, offset); let offset = offset as usize; @@ -313,7 +314,7 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl llvals.push(cx.scalar_to_backend( InterpScalar::from_pointer( - interpret::Pointer::new(alloc_id, Size::from_bytes(ptr_offset)), + interpret::Pointer::new(prov, Size::from_bytes(ptr_offset)), &cx.tcx, ), abi::Scalar::Initialized { value: Primitive::Pointer(address_space), valid_range: WrappingRange::full(dl.pointer_size) }, diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs index 4bf3b71f503..5fc4b12d7e6 100644 --- a/compiler/rustc_codegen_gcc/src/errors.rs +++ b/compiler/rustc_codegen_gcc/src/errors.rs @@ -111,8 +111,8 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> { pub(crate) struct MissingFeatures; impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> { - fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = sess.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable); + fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = handler.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable); if let Some(span) = self.span { diag.set_span(span); }; diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index db297425b03..abc33a04598 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -60,7 +60,7 @@ fn prepare_lto( }; let symbol_filter = &|&(ref name, info): &(String, SymbolExportInfo)| { - if info.level.is_below_threshold(export_threshold) || info.used { + if info.level.is_below_threshold(export_threshold) || info.used || info.used_compiler { Some(CString::new(name.as_str()).unwrap()) } else { None diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index d1b643f4967..8173e41aff4 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -246,8 +246,8 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } Scalar::Ptr(ptr, _size) => { - let (alloc_id, offset) = ptr.into_parts(); - let (base_addr, base_addr_space) = match self.tcx.global_alloc(alloc_id) { + let (prov, offset) = ptr.into_parts(); + let (base_addr, base_addr_space) = match self.tcx.global_alloc(prov.alloc_id()) { GlobalAlloc::Memory(alloc) => { let init = const_alloc_to_llvm(self, alloc); let alloc = alloc.inner(); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index b6bc5395bf6..21ff267ca67 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -72,7 +72,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation< } let mut next_offset = 0; - for &(offset, alloc_id) in alloc.provenance().ptrs().iter() { + for &(offset, prov) in alloc.provenance().ptrs().iter() { let offset = offset.bytes(); assert_eq!(offset as usize as u64, offset); let offset = offset as usize; @@ -92,13 +92,10 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation< .expect("const_alloc_to_llvm: could not read relocation pointer") as u64; - let address_space = cx.tcx.global_alloc(alloc_id).address_space(cx); + let address_space = cx.tcx.global_alloc(prov.alloc_id()).address_space(cx); llvals.push(cx.scalar_to_backend( - InterpScalar::from_pointer( - Pointer::new(alloc_id, Size::from_bytes(ptr_offset)), - &cx.tcx, - ), + InterpScalar::from_pointer(Pointer::new(prov, Size::from_bytes(ptr_offset)), &cx.tcx), Scalar::Initialized { value: Primitive::Pointer(address_space), valid_range: WrappingRange::full(dl.pointer_size), diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 10ca5ad802a..57ea13ddcd6 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -5,7 +5,7 @@ use std::path::Path; use crate::fluent_generated as fluent; use rustc_data_structures::small_c_str::SmallCStr; use rustc_errors::{ - DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed, Handler, IntoDiagnostic, + DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed, FatalError, Handler, IntoDiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; @@ -101,13 +101,13 @@ pub(crate) struct DynamicLinkingWithLTO; pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>); -impl<EM: EmissionGuarantee> IntoDiagnostic<'_, EM> for ParseTargetMachineConfig<'_> { - fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, EM> { - let diag: DiagnosticBuilder<'_, EM> = self.0.into_diagnostic(sess); +impl IntoDiagnostic<'_, FatalError> for ParseTargetMachineConfig<'_> { + fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, FatalError> { + let diag: DiagnosticBuilder<'_, FatalError> = self.0.into_diagnostic(handler); let (message, _) = diag.styled_message().first().expect("`LlvmError` with no message"); - let message = sess.eagerly_translate_to_string(message.clone(), diag.args()); + let message = handler.eagerly_translate_to_string(message.clone(), diag.args()); - let mut diag = sess.struct_diagnostic(fluent::codegen_llvm_parse_target_machine_config); + let mut diag = handler.struct_diagnostic(fluent::codegen_llvm_parse_target_machine_config); diag.set_arg("error", message); diag } @@ -124,8 +124,8 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> { pub(crate) struct MissingFeatures; impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> { - fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = sess.struct_err(fluent::codegen_llvm_target_feature_disable_or_enable); + fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = handler.struct_err(fluent::codegen_llvm_target_feature_disable_or_enable); if let Some(span) = self.span { diag.set_span(span); }; @@ -183,8 +183,8 @@ pub enum LlvmError<'a> { pub(crate) struct WithLlvmError<'a>(pub LlvmError<'a>, pub String); -impl<EM: EmissionGuarantee> IntoDiagnostic<'_, EM> for WithLlvmError<'_> { - fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, EM> { +impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for WithLlvmError<'_> { + fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, G> { use LlvmError::*; let msg_with_llvm_err = match &self.0 { WriteOutput { .. } => fluent::codegen_llvm_write_output_with_llvm_err, @@ -201,7 +201,7 @@ impl<EM: EmissionGuarantee> IntoDiagnostic<'_, EM> for WithLlvmError<'_> { PrepareThinLtoModule => fluent::codegen_llvm_prepare_thin_lto_module_with_llvm_err, ParseBitcode => fluent::codegen_llvm_parse_bitcode_with_llvm_err, }; - let mut diag = self.0.into_diagnostic(sess); + let mut diag = self.0.into_diagnostic(handler); diag.set_primary_message(msg_with_llvm_err); diag.set_arg("llvm_err", self.1); diag diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 5f2fad0536b..f9ad8ca9563 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -105,20 +105,21 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S } }) .map(|def_id| { + let codegen_attrs = tcx.codegen_fn_attrs(def_id.to_def_id()); // We won't link right if this symbol is stripped during LTO. let name = tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())).name; // We have to preserve the symbols of the built-in functions during LTO. let is_builtin_fn = is_compiler_builtins && symbol_export_level(tcx, def_id.to_def_id()) - .is_below_threshold(SymbolExportLevel::C); - let used = is_builtin_fn || name == "rust_eh_personality"; + .is_below_threshold(SymbolExportLevel::C) + && codegen_attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE); + let used = name == "rust_eh_personality"; let export_level = if special_runtime_crate { SymbolExportLevel::Rust } else { symbol_export_level(tcx, def_id.to_def_id()) }; - let codegen_attrs = tcx.codegen_fn_attrs(def_id.to_def_id()); debug!( "EXPORTED SYMBOL (local): {} ({:?})", tcx.symbol_name(Instance::mono(tcx, def_id.to_def_id())), @@ -138,6 +139,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S used: codegen_attrs.flags.contains(CodegenFnAttrFlags::USED) || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) || used, + used_compiler: is_builtin_fn, }; (def_id.to_def_id(), info) }) @@ -150,6 +152,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S level: SymbolExportLevel::C, kind: SymbolExportKind::Data, used: false, + used_compiler: false, }, ); } @@ -198,6 +201,7 @@ fn exported_symbols_provider_local( level: info.level, kind: SymbolExportKind::Text, used: info.used, + used_compiler: false, }, ) }) @@ -214,6 +218,7 @@ fn exported_symbols_provider_local( level: SymbolExportLevel::C, kind: SymbolExportKind::Text, used: false, + used_compiler: false, }, )); } @@ -233,6 +238,7 @@ fn exported_symbols_provider_local( level: SymbolExportLevel::Rust, kind: SymbolExportKind::Text, used: false, + used_compiler: false, }, )); } @@ -245,6 +251,7 @@ fn exported_symbols_provider_local( level: SymbolExportLevel::Rust, kind: SymbolExportKind::Data, used: false, + used_compiler: false, }, )) } @@ -264,6 +271,7 @@ fn exported_symbols_provider_local( level: SymbolExportLevel::C, kind: SymbolExportKind::Data, used: false, + used_compiler: false, }, ) })); @@ -289,6 +297,7 @@ fn exported_symbols_provider_local( level: SymbolExportLevel::C, kind: SymbolExportKind::Data, used: false, + used_compiler: false, }, ) })); @@ -306,6 +315,7 @@ fn exported_symbols_provider_local( level: SymbolExportLevel::C, kind: SymbolExportKind::Data, used: true, + used_compiler: false, }, )); } @@ -346,6 +356,7 @@ fn exported_symbols_provider_local( level: SymbolExportLevel::Rust, kind: SymbolExportKind::Text, used: false, + used_compiler: false, }, )); } @@ -362,6 +373,7 @@ fn exported_symbols_provider_local( level: SymbolExportLevel::Rust, kind: SymbolExportKind::Text, used: false, + used_compiler: false, }, )); } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 6661f1f81e6..d724f9503bb 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -105,7 +105,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { bug!("from_const: invalid ScalarPair layout: {:#?}", layout); }; let a = Scalar::from_pointer( - Pointer::new(bx.tcx().reserve_and_set_memory_alloc(data), Size::ZERO), + Pointer::new(bx.tcx().reserve_and_set_memory_alloc(data).into(), Size::ZERO), &bx.tcx(), ); let a_llval = bx.scalar_to_backend( diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index f926da464e1..4a426ed16e5 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -461,6 +461,9 @@ const_eval_validation_uninhabited_val = {$front_matter}: encountered a value of const_eval_validation_uninit = {$front_matter}: encountered uninitialized memory, but {$expected} const_eval_validation_unsafe_cell = {$front_matter}: encountered `UnsafeCell` in a `const` +const_eval_write_through_immutable_pointer = + writing through a pointer that was derived from a shared (immutable) reference + const_eval_write_to_read_only = writing to {$allocation} which is read-only const_eval_zst_pointer_out_of_bounds = diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 4934fcc75ec..26cf3b3f2b0 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -1,14 +1,16 @@ use std::mem; use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, IntoDiagnostic, IntoDiagnosticArg}; +use rustc_hir::CRATE_HIR_ID; use rustc_middle::mir::AssertKind; +use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::{layout::LayoutError, ConstInt}; use rustc_span::{ErrorGuaranteed, Span, Symbol, DUMMY_SP}; -use super::InterpCx; +use super::{CompileTimeInterpreter, InterpCx}; use crate::errors::{self, FrameNote, ReportErrorExt}; -use crate::interpret::{ErrorHandled, InterpError, InterpErrorInfo, Machine, MachineStopType}; +use crate::interpret::{ErrorHandled, InterpError, InterpErrorInfo, MachineStopType}; /// The CTFE machine has some custom error kinds. #[derive(Clone, Debug)] @@ -57,16 +59,20 @@ impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalErrKind { } } -pub fn get_span_and_frames<'tcx, 'mir, M: Machine<'mir, 'tcx>>( - ecx: &InterpCx<'mir, 'tcx, M>, +pub fn get_span_and_frames<'tcx, 'mir>( + tcx: TyCtxtAt<'tcx>, + machine: &CompileTimeInterpreter<'mir, 'tcx>, ) -> (Span, Vec<errors::FrameNote>) where 'tcx: 'mir, { - let mut stacktrace = ecx.generate_stacktrace(); + let mut stacktrace = + InterpCx::<CompileTimeInterpreter<'mir, 'tcx>>::generate_stacktrace_from_stack( + &machine.stack, + ); // Filter out `requires_caller_location` frames. - stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*ecx.tcx)); - let span = stacktrace.first().map(|f| f.span).unwrap_or(ecx.tcx.span); + stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*tcx)); + let span = stacktrace.first().map(|f| f.span).unwrap_or(tcx.span); let mut frames = Vec::new(); @@ -87,7 +93,7 @@ where let mut last_frame: Option<errors::FrameNote> = None; for frame_info in &stacktrace { - let frame = frame_info.as_note(*ecx.tcx); + let frame = frame_info.as_note(*tcx); match last_frame.as_mut() { Some(last_frame) if last_frame.span == frame.span @@ -156,3 +162,25 @@ where } } } + +/// Emit a lint from a const-eval situation. +// Even if this is unused, please don't remove it -- chances are we will need to emit a lint during const-eval again in the future! +pub(super) fn lint<'tcx, 'mir, L>( + tcx: TyCtxtAt<'tcx>, + machine: &CompileTimeInterpreter<'mir, 'tcx>, + lint: &'static rustc_session::lint::Lint, + decorator: impl FnOnce(Vec<errors::FrameNote>) -> L, +) where + L: for<'a> rustc_errors::DecorateLint<'a, ()>, +{ + let (span, frames) = get_span_and_frames(tcx, machine); + + tcx.emit_spanned_lint( + lint, + // We use the root frame for this so the crate that defines the const defines whether the + // lint is emitted. + machine.stack.first().and_then(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID), + span, + decorator(frames), + ); +} diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index edfece07d19..9d22df50d4f 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -155,8 +155,8 @@ pub(super) fn op_to_const<'tcx>( match immediate { Left(ref mplace) => { // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (alloc_id, offset) = mplace.ptr().into_parts(); - let alloc_id = alloc_id.expect("cannot have `fake` place fot non-ZST type"); + let (prov, offset) = mplace.ptr().into_parts(); + let alloc_id = prov.expect("cannot have `fake` place for non-ZST type").alloc_id(); ConstValue::Indirect { alloc_id, offset } } // see comment on `let force_as_immediate` above @@ -178,8 +178,8 @@ pub(super) fn op_to_const<'tcx>( ); let msg = "`op_to_const` on an immediate scalar pair must only be used on slice references to the beginning of an actual allocation"; // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (alloc_id, offset) = a.to_pointer(ecx).expect(msg).into_parts(); - let alloc_id = alloc_id.expect(msg); + let (prov, offset) = a.to_pointer(ecx).expect(msg).into_parts(); + let alloc_id = prov.expect(msg).alloc_id(); let data = ecx.tcx.global_alloc(alloc_id).unwrap_memory(); assert!(offset == abi::Size::ZERO, "{}", msg); let meta = b.to_target_usize(ecx).expect(msg); @@ -338,7 +338,7 @@ pub fn eval_in_interpreter<'mir, 'tcx>( *ecx.tcx, error, None, - || super::get_span_and_frames(&ecx), + || super::get_span_and_frames(ecx.tcx, &ecx.machine), |span, frames| ConstEvalError { span, error_kind: kind, @@ -353,7 +353,7 @@ pub fn eval_in_interpreter<'mir, 'tcx>( let validation = const_validate_mplace(&ecx, &mplace, is_static, cid.promoted.is_some()); - let alloc_id = mplace.ptr().provenance.unwrap(); + let alloc_id = mplace.ptr().provenance.unwrap().alloc_id(); // Validation failed, report an error. if let Err(error) = validation { @@ -419,7 +419,7 @@ pub fn const_report_error<'mir, 'tcx>( *ecx.tcx, error, None, - || crate::const_eval::get_span_and_frames(ecx), + || crate::const_eval::get_span_and_frames(ecx.tcx, &ecx.machine), move |span, frames| errors::UndefinedBehavior { span, ub_note, frames, raw_bytes }, ) } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 2d8ca67c3a5..9aaf6c510d5 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -1,30 +1,30 @@ -use rustc_hir::def::DefKind; -use rustc_hir::LangItem; -use rustc_middle::mir; -use rustc_middle::mir::interpret::PointerArithmetic; -use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout}; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::Span; use std::borrow::Borrow; +use std::fmt; use std::hash::Hash; use std::ops::ControlFlow; +use rustc_ast::Mutability; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::IndexEntry; -use std::fmt; - -use rustc_ast::Mutability; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; +use rustc_hir::LangItem; +use rustc_middle::mir; use rustc_middle::mir::AssertMessage; +use rustc_middle::query::TyCtxtAt; +use rustc_middle::ty; +use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout}; +use rustc_session::lint::builtin::WRITES_THROUGH_IMMUTABLE_POINTER; use rustc_span::symbol::{sym, Symbol}; +use rustc_span::Span; use rustc_target::abi::{Align, Size}; use rustc_target::spec::abi::Abi as CallAbi; use crate::errors::{LongRunning, LongRunningWarn}; use crate::fluent_generated as fluent; use crate::interpret::{ - self, compile_time_machine, AllocId, ConstAllocation, FnArg, FnVal, Frame, ImmTy, InterpCx, - InterpResult, OpTy, PlaceTy, Pointer, Scalar, + self, compile_time_machine, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, FnVal, + Frame, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, PointerArithmetic, Scalar, }; use super::error::*; @@ -49,7 +49,7 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> { pub(super) num_evaluated_steps: usize, /// The virtual call stack. - pub(super) stack: Vec<Frame<'mir, 'tcx, AllocId, ()>>, + pub(super) stack: Vec<Frame<'mir, 'tcx>>, /// We need to make sure consts never point to anything mutable, even recursively. That is /// relied on for pattern matching on consts with references. @@ -638,10 +638,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } #[inline(always)] - fn expose_ptr( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _ptr: Pointer<AllocId>, - ) -> InterpResult<'tcx> { + fn expose_ptr(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx> { // This is only reachable with -Zunleash-the-miri-inside-of-you. throw_unsup_format!("exposing pointers is not possible at compile-time") } @@ -674,7 +671,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } fn before_access_global( - _tcx: TyCtxt<'tcx>, + _tcx: TyCtxtAt<'tcx>, machine: &Self, alloc_id: AllocId, alloc: ConstAllocation<'tcx>, @@ -711,6 +708,48 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, } } } + + fn retag_ptr_value( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + _kind: mir::RetagKind, + val: &ImmTy<'tcx, CtfeProvenance>, + ) -> InterpResult<'tcx, ImmTy<'tcx, CtfeProvenance>> { + // If it's a frozen shared reference that's not already immutable, make it immutable. + // (Do nothing on `None` provenance, that cannot store immutability anyway.) + if let ty::Ref(_, ty, mutbl) = val.layout.ty.kind() + && *mutbl == Mutability::Not + && val.to_scalar_and_meta().0.to_pointer(ecx)?.provenance.is_some_and(|p| !p.immutable()) + // That next check is expensive, that's why we have all the guards above. + && ty.is_freeze(*ecx.tcx, ecx.param_env) + { + let place = ecx.ref_to_mplace(val)?; + let new_place = place.map_provenance(|p| p.map(CtfeProvenance::as_immutable)); + Ok(ImmTy::from_immediate(new_place.to_ref(ecx), val.layout)) + } else { + Ok(val.clone()) + } + } + + fn before_memory_write( + tcx: TyCtxtAt<'tcx>, + machine: &mut Self, + _alloc_extra: &mut Self::AllocExtra, + (_alloc_id, immutable): (AllocId, bool), + range: AllocRange, + ) -> InterpResult<'tcx> { + if range.size == Size::ZERO { + // Nothing to check. + return Ok(()); + } + // Reject writes through immutable pointers. + if immutable { + super::lint(tcx, machine, WRITES_THROUGH_IMMUTABLE_POINTER, |frames| { + crate::errors::WriteThroughImmutablePointer { frames } + }); + } + // Everything else is fine. + Ok(()) + } } // Please do not add any code below the above `Machine` trait impl. I (oli-obk) plan more cleanups diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 8343dc2dd35..46fb64fd5b3 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -402,6 +402,13 @@ pub struct ConstEvalError { pub frame_notes: Vec<FrameNote>, } +#[derive(LintDiagnostic)] +#[diag(const_eval_write_through_immutable_pointer)] +pub struct WriteThroughImmutablePointer { + #[subdiagnostic] + pub frames: Vec<FrameNote>, +} + #[derive(Diagnostic)] #[diag(const_eval_nullary_intrinsic_fail)] pub struct NullaryIntrinsicError { diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 04e5b550d6d..bbebf329d26 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -7,7 +7,9 @@ use hir::CRATE_HIR_ID; use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; use rustc_index::IndexVec; use rustc_middle::mir; -use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo}; +use rustc_middle::mir::interpret::{ + CtfeProvenance, ErrorHandled, InvalidMetaKind, ReportedErrorInfo, +}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{ self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers, @@ -20,9 +22,9 @@ use rustc_span::Span; use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayout}; use super::{ - AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace, - MemPlaceMeta, Memory, MemoryKind, OpTy, Operand, Place, PlaceTy, Pointer, PointerArithmetic, - Projectable, Provenance, Scalar, StackPopJump, + GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, + Memory, MemoryKind, OpTy, Operand, Place, PlaceTy, Pointer, PointerArithmetic, Projectable, + Provenance, Scalar, StackPopJump, }; use crate::errors; use crate::util; @@ -84,7 +86,7 @@ impl Drop for SpanGuard { } /// A stack frame. -pub struct Frame<'mir, 'tcx, Prov: Provenance = AllocId, Extra = ()> { +pub struct Frame<'mir, 'tcx, Prov: Provenance = CtfeProvenance, Extra = ()> { //////////////////////////////////////////////////////////////////////////////// // Function and callsite information //////////////////////////////////////////////////////////////////////////////// @@ -156,7 +158,7 @@ pub enum StackPopCleanup { /// State of a local variable including a memoized layout #[derive(Clone)] -pub struct LocalState<'tcx, Prov: Provenance = AllocId> { +pub struct LocalState<'tcx, Prov: Provenance = CtfeProvenance> { value: LocalValue<Prov>, /// Don't modify if `Some`, this is only used to prevent computing the layout twice. /// Avoids computing the layout of locals that are never actually initialized. @@ -177,7 +179,7 @@ impl<Prov: Provenance> std::fmt::Debug for LocalState<'_, Prov> { /// This does not store the type of the local; the type is given by `body.local_decls` and can never /// change, so by not storing here we avoid having to maintain that as an invariant. #[derive(Copy, Clone, Debug)] // Miri debug-prints these -pub(super) enum LocalValue<Prov: Provenance = AllocId> { +pub(super) enum LocalValue<Prov: Provenance = CtfeProvenance> { /// This local is not currently alive, and cannot be used at all. Dead, /// A normal, live local. diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 881df9b04ab..7931789e436 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -18,7 +18,7 @@ use super::validity::RefTracking; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; -use rustc_middle::mir::interpret::InterpResult; +use rustc_middle::mir::interpret::{CtfeProvenance, InterpResult}; use rustc_middle::ty::{self, layout::TyAndLayout, Ty}; use rustc_ast::Mutability; @@ -34,7 +34,7 @@ pub trait CompileTimeMachine<'mir, 'tcx: 'mir, T> = Machine< 'mir, 'tcx, MemoryKind = T, - Provenance = AllocId, + Provenance = CtfeProvenance, ExtraFnVal = !, FrameExtra = (), AllocExtra = (), @@ -135,7 +135,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval: alloc.mutability = Mutability::Not; }; // link the alloc id to the actual allocation - leftover_allocations.extend(alloc.provenance().ptrs().iter().map(|&(_, alloc_id)| alloc_id)); + leftover_allocations.extend(alloc.provenance().ptrs().iter().map(|&(_, prov)| prov.alloc_id())); let alloc = tcx.mk_const_alloc(alloc); tcx.set_alloc_id_memory(alloc_id, alloc); None @@ -178,10 +178,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind() { let ptr = mplace.meta().unwrap_meta().to_pointer(&tcx)?; - if let Some(alloc_id) = ptr.provenance { + if let Some(prov) = ptr.provenance { // Explicitly choose const mode here, since vtables are immutable, even // if the reference of the fat pointer is mutable. - self.intern_shallow(alloc_id, InternMode::Const, None); + self.intern_shallow(prov.alloc_id(), InternMode::Const, None); } else { // Validation will error (with a better message) on an invalid vtable pointer. // Let validation show the error message, but make sure it *does* error. @@ -191,7 +191,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory } // Check if we have encountered this pointer+layout combination before. // Only recurse for allocation-backed pointers. - if let Some(alloc_id) = mplace.ptr().provenance { + if let Some(prov) = mplace.ptr().provenance { // Compute the mode with which we intern this. Our goal here is to make as many // statics as we can immutable so they can be placed in read-only memory by LLVM. let ref_mode = match self.mode { @@ -234,7 +234,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory InternMode::Const } }; - match self.intern_shallow(alloc_id, ref_mode, Some(referenced_ty)) { + match self.intern_shallow(prov.alloc_id(), ref_mode, Some(referenced_ty)) { // No need to recurse, these are interned already and statics may have // cycles, so we don't want to recurse there Some(IsStaticOrFn) => {} @@ -353,7 +353,7 @@ pub fn intern_const_alloc_recursive< leftover_allocations, // The outermost allocation must exist, because we allocated it with // `Memory::allocate`. - ret.ptr().provenance.unwrap(), + ret.ptr().provenance.unwrap().alloc_id(), base_intern_mode, Some(ret.layout.ty), ); @@ -431,7 +431,8 @@ pub fn intern_const_alloc_recursive< } let alloc = tcx.mk_const_alloc(alloc); tcx.set_alloc_id_memory(alloc_id, alloc); - for &(_, alloc_id) in alloc.inner().provenance().ptrs().iter() { + for &(_, prov) in alloc.inner().provenance().ptrs().iter() { + let alloc_id = prov.alloc_id(); if leftover_allocations.insert(alloc_id) { todo.push(alloc_id); } @@ -503,10 +504,11 @@ impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>> // `allocate` picks a fresh AllocId that we will associate with its data below. let dest = self.allocate(layout, MemoryKind::Stack)?; f(self, &dest.clone().into())?; - let mut alloc = self.memory.alloc_map.remove(&dest.ptr().provenance.unwrap()).unwrap().1; + let mut alloc = + self.memory.alloc_map.remove(&dest.ptr().provenance.unwrap().alloc_id()).unwrap().1; alloc.mutability = Mutability::Not; let alloc = self.tcx.mk_const_alloc(alloc); - let alloc_id = dest.ptr().provenance.unwrap(); // this was just allocated, it must have provenance + let alloc_id = dest.ptr().provenance.unwrap().alloc_id(); // this was just allocated, it must have provenance self.tcx.set_alloc_id_memory(alloc_id, alloc); Ok(alloc_id) } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 221ff2b60e9..5e69965512b 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -9,15 +9,17 @@ use std::hash::Hash; use rustc_apfloat::{Float, FloatConvert}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_middle::mir; +use rustc_middle::query::TyCtxtAt; +use rustc_middle::ty; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{self, TyCtxt}; use rustc_span::def_id::DefId; use rustc_target::abi::{Align, Size}; use rustc_target::spec::abi::Abi as CallAbi; use super::{ - AllocBytes, AllocId, AllocKind, AllocRange, Allocation, ConstAllocation, FnArg, Frame, ImmTy, - InterpCx, InterpResult, MPlaceTy, MemoryKind, Misalignment, OpTy, PlaceTy, Pointer, Provenance, + AllocBytes, AllocId, AllocKind, AllocRange, Allocation, ConstAllocation, CtfeProvenance, FnArg, + Frame, ImmTy, InterpCx, InterpResult, MPlaceTy, MemoryKind, Misalignment, OpTy, PlaceTy, + Pointer, Provenance, }; /// Data returned by Machine::stack_pop, @@ -292,7 +294,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { /// `def_id` is `Some` if this is the "lazy" allocation of a static. #[inline] fn before_access_global( - _tcx: TyCtxt<'tcx>, + _tcx: TyCtxtAt<'tcx>, _machine: &Self, _alloc_id: AllocId, _allocation: ConstAllocation<'tcx>, @@ -387,7 +389,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { /// need to mutate. #[inline(always)] fn before_memory_read( - _tcx: TyCtxt<'tcx>, + _tcx: TyCtxtAt<'tcx>, _machine: &Self, _alloc_extra: &Self::AllocExtra, _prov: (AllocId, Self::ProvenanceExtra), @@ -399,7 +401,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { /// Hook for performing extra checks on a memory write access. #[inline(always)] fn before_memory_write( - _tcx: TyCtxt<'tcx>, + _tcx: TyCtxtAt<'tcx>, _machine: &mut Self, _alloc_extra: &mut Self::AllocExtra, _prov: (AllocId, Self::ProvenanceExtra), @@ -411,7 +413,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { /// Hook for performing extra operations on a memory deallocation. #[inline(always)] fn before_memory_deallocation( - _tcx: TyCtxt<'tcx>, + _tcx: TyCtxtAt<'tcx>, _machine: &mut Self, _alloc_extra: &mut Self::AllocExtra, _prov: (AllocId, Self::ProvenanceExtra), @@ -513,8 +515,8 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { /// A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines /// (CTFE and ConstProp) use the same instance. Here, we share that code. pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { - type Provenance = AllocId; - type ProvenanceExtra = (); + type Provenance = CtfeProvenance; + type ProvenanceExtra = bool; // the "immutable" flag type ExtraFnVal = !; @@ -567,14 +569,14 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { def_id: DefId, ) -> InterpResult<$tcx, Pointer> { // Use the `AllocId` associated with the `DefId`. Any actual *access* will fail. - Ok(Pointer::new(ecx.tcx.reserve_and_set_static_alloc(def_id), Size::ZERO)) + Ok(Pointer::new(ecx.tcx.reserve_and_set_static_alloc(def_id).into(), Size::ZERO)) } #[inline(always)] fn adjust_alloc_base_pointer( _ecx: &InterpCx<$mir, $tcx, Self>, - ptr: Pointer<AllocId>, - ) -> InterpResult<$tcx, Pointer<AllocId>> { + ptr: Pointer<CtfeProvenance>, + ) -> InterpResult<$tcx, Pointer<CtfeProvenance>> { Ok(ptr) } @@ -582,7 +584,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { fn ptr_from_addr_cast( _ecx: &InterpCx<$mir, $tcx, Self>, addr: u64, - ) -> InterpResult<$tcx, Pointer<Option<AllocId>>> { + ) -> InterpResult<$tcx, Pointer<Option<CtfeProvenance>>> { // Allow these casts, but make the pointer not dereferenceable. // (I.e., they behave like transmutation.) // This is correct because no pointers can ever be exposed in compile-time evaluation. @@ -592,10 +594,10 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { #[inline(always)] fn ptr_get_alloc( _ecx: &InterpCx<$mir, $tcx, Self>, - ptr: Pointer<AllocId>, + ptr: Pointer<CtfeProvenance>, ) -> Option<(AllocId, Size, Self::ProvenanceExtra)> { // We know `offset` is relative to the allocation, so we can use `into_parts`. - let (alloc_id, offset) = ptr.into_parts(); - Some((alloc_id, offset, ())) + let (prov, offset) = ptr.into_parts(); + Some((prov.alloc_id(), offset, prov.immutable())) } } diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index f865c0cc5fa..3fde6ae9b8e 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -22,8 +22,8 @@ use crate::fluent_generated as fluent; use super::{ alloc_range, AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckAlignMsg, - CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Misalignment, Pointer, - PointerArithmetic, Provenance, Scalar, + CheckInAllocMsg, CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, + Misalignment, Pointer, PointerArithmetic, Provenance, Scalar, }; #[derive(Debug, PartialEq, Copy, Clone)] @@ -159,9 +159,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[inline] pub fn global_base_pointer( &self, - ptr: Pointer<AllocId>, + ptr: Pointer<CtfeProvenance>, ) -> InterpResult<'tcx, Pointer<M::Provenance>> { - let alloc_id = ptr.provenance; + let alloc_id = ptr.provenance.alloc_id(); // We need to handle `extern static`. match self.tcx.try_get_global_alloc(alloc_id) { Some(GlobalAlloc::Static(def_id)) if self.tcx.is_thread_local_static(def_id) => { @@ -339,7 +339,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Let the machine take some extra action let size = alloc.size(); M::before_memory_deallocation( - *self.tcx, + self.tcx, &mut self.machine, &mut alloc.extra, (alloc_id, prov), @@ -561,7 +561,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (val, Some(def_id)) } }; - M::before_access_global(*self.tcx, &self.machine, id, alloc, def_id, is_write)?; + M::before_access_global(self.tcx, &self.machine, id, alloc, def_id, is_write)?; // We got tcx memory. Let the machine initialize its "extra" stuff. M::adjust_allocation( self, @@ -626,7 +626,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { )?; if let Some((alloc_id, offset, prov, alloc)) = ptr_and_alloc { let range = alloc_range(offset, size); - M::before_memory_read(*self.tcx, &self.machine, &alloc.extra, (alloc_id, prov), range)?; + M::before_memory_read(self.tcx, &self.machine, &alloc.extra, (alloc_id, prov), range)?; Ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id })) } else { // Even in this branch we have to be sure that we actually access the allocation, in @@ -687,13 +687,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { { let parts = self.get_ptr_access(ptr, size)?; if let Some((alloc_id, offset, prov)) = parts { - let tcx = *self.tcx; + let tcx = self.tcx; // FIXME: can we somehow avoid looking up the allocation twice here? // We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`. let (alloc, machine) = self.get_alloc_raw_mut(alloc_id)?; let range = alloc_range(offset, size); M::before_memory_write(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?; - Ok(Some(AllocRefMut { alloc, range, tcx, alloc_id })) + Ok(Some(AllocRefMut { alloc, range, tcx: *tcx, alloc_id })) } else { Ok(None) } @@ -1133,7 +1133,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let src_alloc = self.get_alloc_raw(src_alloc_id)?; let src_range = alloc_range(src_offset, size); M::before_memory_read( - *tcx, + tcx, &self.machine, &src_alloc.extra, (src_alloc_id, src_prov), @@ -1163,7 +1163,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (dest_alloc, extra) = self.get_alloc_raw_mut(dest_alloc_id)?; let dest_range = alloc_range(dest_offset, size * num_copies); M::before_memory_write( - *tcx, + tcx, extra, &mut dest_alloc.extra, (dest_alloc_id, dest_prov), diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 255dd1eba97..b39b219b46a 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -13,9 +13,9 @@ use rustc_middle::{mir, ty}; use rustc_target::abi::{self, Abi, HasDataLayout, Size}; use super::{ - alloc_range, from_known_layout, mir_assign_valid_types, AllocId, Frame, InterpCx, InterpResult, - MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode, PlaceTy, Pointer, Projectable, - Provenance, Scalar, + alloc_range, from_known_layout, mir_assign_valid_types, CtfeProvenance, Frame, InterpCx, + InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode, PlaceTy, Pointer, + Projectable, Provenance, Scalar, }; /// An `Immediate` represents a single immediate self-contained Rust value. @@ -26,7 +26,7 @@ use super::{ /// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely /// defined on `Immediate`, and do not have to work with a `Place`. #[derive(Copy, Clone, Debug)] -pub enum Immediate<Prov: Provenance = AllocId> { +pub enum Immediate<Prov: Provenance = CtfeProvenance> { /// A single scalar value (must have *initialized* `Scalar` ABI). Scalar(Scalar<Prov>), /// A pair of two scalar value (must have `ScalarPair` ABI where both fields are @@ -93,12 +93,23 @@ impl<Prov: Provenance> Immediate<Prov> { Immediate::Uninit => bug!("Got uninit where a scalar pair was expected"), } } + + /// Returns the scalar from the first component and optionally the 2nd component as metadata. + #[inline] + #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) + pub fn to_scalar_and_meta(self) -> (Scalar<Prov>, MemPlaceMeta<Prov>) { + match self { + Immediate::ScalarPair(val1, val2) => (val1, MemPlaceMeta::Meta(val2)), + Immediate::Scalar(val) => (val, MemPlaceMeta::None), + Immediate::Uninit => bug!("Got uninit where a scalar or scalar pair was expected"), + } + } } // ScalarPair needs a type to interpret, so we often have an immediate and a type together // as input for binary and cast operations. #[derive(Clone)] -pub struct ImmTy<'tcx, Prov: Provenance = AllocId> { +pub struct ImmTy<'tcx, Prov: Provenance = CtfeProvenance> { imm: Immediate<Prov>, pub layout: TyAndLayout<'tcx>, } @@ -334,13 +345,13 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> { /// or still in memory. The latter is an optimization, to delay reading that chunk of /// memory and to avoid having to store arbitrary-sized data here. #[derive(Copy, Clone, Debug)] -pub(super) enum Operand<Prov: Provenance = AllocId> { +pub(super) enum Operand<Prov: Provenance = CtfeProvenance> { Immediate(Immediate<Prov>), Indirect(MemPlace<Prov>), } #[derive(Clone)] -pub struct OpTy<'tcx, Prov: Provenance = AllocId> { +pub struct OpTy<'tcx, Prov: Provenance = CtfeProvenance> { op: Operand<Prov>, // Keep this private; it helps enforce invariants. pub layout: TyAndLayout<'tcx>, } @@ -750,17 +761,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let layout = from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty))?; let imm = match val_val { mir::ConstValue::Indirect { alloc_id, offset } => { - // We rely on mutability being set correctly in that allocation to prevent writes - // where none should happen. - let ptr = self.global_base_pointer(Pointer::new(alloc_id, offset))?; + // This is const data, no mutation allowed. + let ptr = self.global_base_pointer(Pointer::new( + CtfeProvenance::from(alloc_id).as_immutable(), + offset, + ))?; return Ok(self.ptr_to_mplace(ptr.into(), layout).into()); } mir::ConstValue::Scalar(x) => adjust_scalar(x)?.into(), mir::ConstValue::ZeroSized => Immediate::Uninit, mir::ConstValue::Slice { data, meta } => { - // We rely on mutability being set correctly in `data` to prevent writes - // where none should happen. - let ptr = Pointer::new(self.tcx.reserve_and_set_memory_alloc(data), Size::ZERO); + // This is const data, no mutation allowed. + let alloc_id = self.tcx.reserve_and_set_memory_alloc(data); + let ptr = Pointer::new(CtfeProvenance::from(alloc_id).as_immutable(), Size::ZERO); Immediate::new_slice(self.global_base_pointer(ptr)?.into(), meta, self) } }; diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 04f0cdb326e..639b269ac25 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -14,14 +14,14 @@ use rustc_middle::ty::Ty; use rustc_target::abi::{Abi, Align, HasDataLayout, Size}; use super::{ - alloc_range, mir_assign_valid_types, AllocId, AllocRef, AllocRefMut, CheckAlignMsg, ImmTy, - Immediate, InterpCx, InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy, + alloc_range, mir_assign_valid_types, AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance, + ImmTy, Immediate, InterpCx, InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer, PointerArithmetic, Projectable, Provenance, Readable, Scalar, }; #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] /// Information required for the sound usage of a `MemPlace`. -pub enum MemPlaceMeta<Prov: Provenance = AllocId> { +pub enum MemPlaceMeta<Prov: Provenance = CtfeProvenance> { /// The unsized payload (e.g. length for slices or vtable pointer for trait objects). Meta(Scalar<Prov>), /// `Sized` types or unsized `extern type` @@ -49,7 +49,7 @@ impl<Prov: Provenance> MemPlaceMeta<Prov> { } #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] -pub(super) struct MemPlace<Prov: Provenance = AllocId> { +pub(super) struct MemPlace<Prov: Provenance = CtfeProvenance> { /// The pointer can be a pure integer, with the `None` provenance. pub ptr: Pointer<Option<Prov>>, /// Metadata for unsized places. Interpretation is up to the type. @@ -100,7 +100,7 @@ impl<Prov: Provenance> MemPlace<Prov> { /// A MemPlace with its layout. Constructing it is only possible in this module. #[derive(Clone, Hash, Eq, PartialEq)] -pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> { +pub struct MPlaceTy<'tcx, Prov: Provenance = CtfeProvenance> { mplace: MemPlace<Prov>, pub layout: TyAndLayout<'tcx>, } @@ -179,7 +179,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { } #[derive(Copy, Clone, Debug)] -pub(super) enum Place<Prov: Provenance = AllocId> { +pub(super) enum Place<Prov: Provenance = CtfeProvenance> { /// A place referring to a value allocated in the `Memory` system. Ptr(MemPlace<Prov>), @@ -195,7 +195,7 @@ pub(super) enum Place<Prov: Provenance = AllocId> { } #[derive(Clone)] -pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> { +pub struct PlaceTy<'tcx, Prov: Provenance = CtfeProvenance> { place: Place<Prov>, // Keep this private; it helps enforce invariants. pub layout: TyAndLayout<'tcx>, } @@ -406,11 +406,7 @@ where let pointee_type = val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty; let layout = self.layout_of(pointee_type)?; - let (ptr, meta) = match **val { - Immediate::Scalar(ptr) => (ptr, MemPlaceMeta::None), - Immediate::ScalarPair(ptr, meta) => (ptr, MemPlaceMeta::Meta(meta)), - Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), - }; + let (ptr, meta) = val.to_scalar_and_meta(); // `ref_to_mplace` is called on raw pointers even if they don't actually get dereferenced; // we hence can't call `size_and_align_of` since that asserts more validity than we want. diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index debae6c8902..e48506bd083 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -18,14 +18,14 @@ use rustc_target::abi::{ use rustc_target::spec::abi::Abi; use super::{ - AllocId, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, Projectable, - Provenance, Scalar, StackPopCleanup, + CtfeProvenance, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, + Projectable, Provenance, Scalar, StackPopCleanup, }; use crate::fluent_generated as fluent; /// An argment passed to a function. #[derive(Clone, Debug)] -pub enum FnArg<'tcx, Prov: Provenance = AllocId> { +pub enum FnArg<'tcx, Prov: Provenance = CtfeProvenance> { /// Pass a copy of the given operand. Copy(OpTy<'tcx, Prov>), /// Allow for the argument to be passed in-place: destroy the value originally stored at that place and diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 450e1ead0b2..1f60400b513 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -13,7 +13,6 @@ #![feature(let_chains)] #![feature(panic_update_hook)] #![recursion_limit = "256"] -#![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 0aaa8ae69e1..6aaf4a0f5cf 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -239,7 +239,7 @@ impl Diagnostic { } #[track_caller] - pub fn new_with_code<M: Into<DiagnosticMessage>>( + pub(crate) fn new_with_code<M: Into<DiagnosticMessage>>( level: Level, code: Option<DiagnosticId>, message: M, @@ -281,7 +281,7 @@ impl Diagnostic { } } - pub fn update_unstable_expectation_id( + pub(crate) fn update_unstable_expectation_id( &mut self, unstable_to_stable: &FxHashMap<LintExpectationId, LintExpectationId>, ) { @@ -307,14 +307,14 @@ impl Diagnostic { } /// Indicates whether this diagnostic should show up in cargo's future breakage report. - pub fn has_future_breakage(&self) -> bool { + pub(crate) fn has_future_breakage(&self) -> bool { match self.code { Some(DiagnosticId::Lint { has_future_breakage, .. }) => has_future_breakage, _ => false, } } - pub fn is_force_warn(&self) -> bool { + pub(crate) fn is_force_warn(&self) -> bool { match self.code { Some(DiagnosticId::Lint { is_force_warn, .. }) => is_force_warn, _ => false, @@ -391,29 +391,6 @@ impl Diagnostic { self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"") } - pub fn note_unsuccessful_coercion( - &mut self, - expected: DiagnosticStyledString, - found: DiagnosticStyledString, - ) -> &mut Self { - let mut msg: Vec<_> = - vec![(Cow::from("required when trying to coerce from type `"), Style::NoStyle)]; - msg.extend(expected.0.iter().map(|x| match *x { - StringPart::Normal(ref s) => (Cow::from(s.clone()), Style::NoStyle), - StringPart::Highlighted(ref s) => (Cow::from(s.clone()), Style::Highlight), - })); - msg.push((Cow::from("` to type '"), Style::NoStyle)); - msg.extend(found.0.iter().map(|x| match *x { - StringPart::Normal(ref s) => (Cow::from(s.clone()), Style::NoStyle), - StringPart::Highlighted(ref s) => (Cow::from(s.clone()), Style::Highlight), - })); - msg.push((Cow::from("`"), Style::NoStyle)); - - // For now, just attach these as notes - self.highlighted_note(msg); - self - } - pub fn note_expected_found_extra( &mut self, expected_label: &dyn fmt::Display, @@ -475,7 +452,7 @@ impl Diagnostic { self } - pub fn highlighted_note<M: Into<SubdiagnosticMessage>>( + fn highlighted_note<M: Into<SubdiagnosticMessage>>( &mut self, msg: Vec<(M, Style)>, ) -> &mut Self { @@ -572,14 +549,6 @@ impl Diagnostic { self } - /// Clear any existing suggestions. - pub fn clear_suggestions(&mut self) -> &mut Self { - if let Ok(suggestions) = &mut self.suggestions { - suggestions.clear(); - } - self - } - /// Helper for pushing to `self.suggestions`, if available (not disable). fn push_suggestion(&mut self, suggestion: CodeSuggestion) { if let Ok(suggestions) = &mut self.suggestions { @@ -992,7 +961,7 @@ impl Diagnostic { /// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by /// combining it with the primary message of the diagnostic (if translatable, otherwise it just /// passes the user's string along). - pub(crate) fn subdiagnostic_message_to_diagnostic_message( + fn subdiagnostic_message_to_diagnostic_message( &self, attr: impl Into<SubdiagnosticMessage>, ) -> DiagnosticMessage { diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 3823a1707ec..b8bd86a72e4 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -18,18 +18,18 @@ use std::thread::panicking; /// Trait implemented by error types. This should not be implemented manually. Instead, use /// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic]. #[rustc_diagnostic_item = "IntoDiagnostic"] -pub trait IntoDiagnostic<'a, T: EmissionGuarantee = ErrorGuaranteed> { +pub trait IntoDiagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> { /// Write out as a diagnostic out of `Handler`. #[must_use] - fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, T>; + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G>; } -impl<'a, T, E> IntoDiagnostic<'a, E> for Spanned<T> +impl<'a, T, G> IntoDiagnostic<'a, G> for Spanned<T> where - T: IntoDiagnostic<'a, E>, - E: EmissionGuarantee, + T: IntoDiagnostic<'a, G>, + G: EmissionGuarantee, { - fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, E> { + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G> { let mut diag = self.node.into_diagnostic(handler); diag.set_span(self.span); diag @@ -116,26 +116,6 @@ pub trait EmissionGuarantee: Sized { } impl<'a> DiagnosticBuilder<'a, ErrorGuaranteed> { - /// Convenience function for internal use, clients should use one of the - /// `struct_*` methods on [`Handler`]. - #[track_caller] - pub(crate) fn new_guaranteeing_error<M: Into<DiagnosticMessage>>( - handler: &'a Handler, - message: M, - ) -> Self { - Self { - inner: DiagnosticBuilderInner { - state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(Diagnostic::new_with_code( - Level::Error { lint: false }, - None, - message, - )), - }, - _marker: PhantomData, - } - } - /// Discard the guarantee `.emit()` would return, in favor of having the /// type `DiagnosticBuilder<'a, ()>`. This may be necessary whenever there /// is a common codepath handling both errors and warnings. @@ -189,35 +169,7 @@ impl EmissionGuarantee for ErrorGuaranteed { handler: &Handler, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder::new_guaranteeing_error(handler, msg) - } -} - -impl<'a> DiagnosticBuilder<'a, ()> { - /// Convenience function for internal use, clients should use one of the - /// `struct_*` methods on [`Handler`]. - #[track_caller] - pub(crate) fn new<M: Into<DiagnosticMessage>>( - handler: &'a Handler, - level: Level, - message: M, - ) -> Self { - let diagnostic = Diagnostic::new_with_code(level, None, message); - Self::new_diagnostic(handler, diagnostic) - } - - /// Creates a new `DiagnosticBuilder` with an already constructed - /// diagnostic. - #[track_caller] - pub(crate) fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> Self { - debug!("Created new diagnostic"); - Self { - inner: DiagnosticBuilderInner { - state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(diagnostic), - }, - _marker: PhantomData, - } + DiagnosticBuilder::new(handler, Level::Error { lint: false }, msg) } } @@ -249,28 +201,6 @@ impl EmissionGuarantee for () { #[derive(Copy, Clone)] pub struct Noted; -impl<'a> DiagnosticBuilder<'a, Noted> { - /// Convenience function for internal use, clients should use one of the - /// `struct_*` methods on [`Handler`]. - pub(crate) fn new_note(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self { - let diagnostic = Diagnostic::new_with_code(Level::Note, None, message); - Self::new_diagnostic_note(handler, diagnostic) - } - - /// Creates a new `DiagnosticBuilder` with an already constructed - /// diagnostic. - pub(crate) fn new_diagnostic_note(handler: &'a Handler, diagnostic: Diagnostic) -> Self { - debug!("Created new diagnostic"); - Self { - inner: DiagnosticBuilderInner { - state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(diagnostic), - }, - _marker: PhantomData, - } - } -} - impl EmissionGuarantee for Noted { fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self { match db.inner.state { @@ -290,7 +220,7 @@ impl EmissionGuarantee for Noted { handler: &Handler, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder::new_note(handler, msg) + DiagnosticBuilder::new(handler, Level::Note, msg) } } @@ -299,29 +229,6 @@ impl EmissionGuarantee for Noted { #[derive(Copy, Clone)] pub struct Bug; -impl<'a> DiagnosticBuilder<'a, Bug> { - /// Convenience function for internal use, clients should use one of the - /// `struct_*` methods on [`Handler`]. - #[track_caller] - pub(crate) fn new_bug(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self { - let diagnostic = Diagnostic::new_with_code(Level::Bug, None, message); - Self::new_diagnostic_bug(handler, diagnostic) - } - - /// Creates a new `DiagnosticBuilder` with an already constructed - /// diagnostic. - pub(crate) fn new_diagnostic_bug(handler: &'a Handler, diagnostic: Diagnostic) -> Self { - debug!("Created new diagnostic bug"); - Self { - inner: DiagnosticBuilderInner { - state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(diagnostic), - }, - _marker: PhantomData, - } - } -} - impl EmissionGuarantee for Bug { fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self { match db.inner.state { @@ -342,22 +249,7 @@ impl EmissionGuarantee for Bug { handler: &Handler, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder::new_bug(handler, msg) - } -} - -impl<'a> DiagnosticBuilder<'a, !> { - /// Convenience function for internal use, clients should use one of the - /// `struct_*` methods on [`Handler`]. - #[track_caller] - pub(crate) fn new_fatal(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self { - Self { - inner: DiagnosticBuilderInner { - state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(Diagnostic::new_with_code(Level::Fatal, None, message)), - }, - _marker: PhantomData, - } + DiagnosticBuilder::new(handler, Level::Bug, msg) } } @@ -381,36 +273,7 @@ impl EmissionGuarantee for ! { handler: &Handler, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder::new_fatal(handler, msg) - } -} - -impl<'a> DiagnosticBuilder<'a, rustc_span::fatal_error::FatalError> { - /// Convenience function for internal use, clients should use one of the - /// `struct_*` methods on [`Handler`]. - #[track_caller] - pub(crate) fn new_almost_fatal( - handler: &'a Handler, - message: impl Into<DiagnosticMessage>, - ) -> Self { - let diagnostic = Diagnostic::new_with_code(Level::Fatal, None, message); - Self::new_diagnostic_almost_fatal(handler, diagnostic) - } - - /// Creates a new `DiagnosticBuilder` with an already constructed - /// diagnostic. - pub(crate) fn new_diagnostic_almost_fatal( - handler: &'a Handler, - diagnostic: Diagnostic, - ) -> Self { - debug!("Created new diagnostic"); - Self { - inner: DiagnosticBuilderInner { - state: DiagnosticBuilderState::Emittable(handler), - diagnostic: Box::new(diagnostic), - }, - _marker: PhantomData, - } + DiagnosticBuilder::new(handler, Level::Fatal, msg) } } @@ -434,7 +297,7 @@ impl EmissionGuarantee for rustc_span::fatal_error::FatalError { handler: &Handler, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, Self> { - DiagnosticBuilder::new_almost_fatal(handler, msg) + DiagnosticBuilder::new(handler, Level::Fatal, msg) } } @@ -476,6 +339,32 @@ impl<G: EmissionGuarantee> DerefMut for DiagnosticBuilder<'_, G> { } impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { + /// Convenience function for internal use, clients should use one of the + /// `struct_*` methods on [`Handler`]. + #[track_caller] + pub(crate) fn new<M: Into<DiagnosticMessage>>( + handler: &'a Handler, + level: Level, + message: M, + ) -> Self { + let diagnostic = Diagnostic::new(level, message); + Self::new_diagnostic(handler, diagnostic) + } + + /// Creates a new `DiagnosticBuilder` with an already constructed + /// diagnostic. + #[track_caller] + pub(crate) fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> Self { + debug!("Created new diagnostic"); + Self { + inner: DiagnosticBuilderInner { + state: DiagnosticBuilderState::Emittable(handler), + diagnostic: Box::new(diagnostic), + }, + _marker: PhantomData, + } + } + /// Emit the diagnostic. #[track_caller] pub fn emit(&mut self) -> G { @@ -626,12 +515,6 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { found_extra: &dyn fmt::Display, ) -> &mut Self); - forward!(pub fn note_unsuccessful_coercion( - &mut self, - expected: DiagnosticStyledString, - found: DiagnosticStyledString, - ) -> &mut Self); - forward!(pub fn note(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self); forward!(pub fn note_once(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self); forward!(pub fn span_note( @@ -660,7 +543,6 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { forward!(pub fn set_is_lint(&mut self,) -> &mut Self); forward!(pub fn disable_suggestions(&mut self,) -> &mut Self); - forward!(pub fn clear_suggestions(&mut self,) -> &mut Self); forward!(pub fn multipart_suggestion( &mut self, diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index ba9cd02a9ec..3f257fdd9cf 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -2674,6 +2674,14 @@ fn from_stderr(color: ColorConfig) -> Destination { } } +/// On Windows, BRIGHT_BLUE is hard to read on black. Use cyan instead. +/// +/// See #36178. +#[cfg(windows)] +const BRIGHT_BLUE: Color = Color::Cyan; +#[cfg(not(windows))] +const BRIGHT_BLUE: Color = Color::Blue; + impl Style { fn color_spec(&self, lvl: Level) -> ColorSpec { let mut spec = ColorSpec::new(); @@ -2688,11 +2696,7 @@ impl Style { Style::LineNumber => { spec.set_bold(true); spec.set_intense(true); - if cfg!(windows) { - spec.set_fg(Some(Color::Cyan)); - } else { - spec.set_fg(Some(Color::Blue)); - } + spec.set_fg(Some(BRIGHT_BLUE)); } Style::Quotation => {} Style::MainHeaderMsg => { @@ -2707,11 +2711,7 @@ impl Style { } Style::UnderlineSecondary | Style::LabelSecondary => { spec.set_bold(true).set_intense(true); - if cfg!(windows) { - spec.set_fg(Some(Color::Cyan)); - } else { - spec.set_fg(Some(Color::Blue)); - } + spec.set_fg(Some(BRIGHT_BLUE)); } Style::HeaderMsg | Style::NoStyle => {} Style::Level(lvl) => { @@ -2719,7 +2719,7 @@ impl Style { spec.set_bold(true); } Style::Highlight => { - spec.set_bold(true); + spec.set_bold(true).set_fg(Some(Color::Magenta)); } } spec diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 5966fd80f97..daa8a7706eb 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -554,7 +554,8 @@ impl Drop for HandlerInner { // instead of "require some error happened". Sadly that isn't ideal, as // lints can be `#[allow]`'d, potentially leading to this triggering. // Also, "good path" should be replaced with a better naming. - if !self.has_any_message() && !self.suppressed_expected_diag && !std::thread::panicking() { + let has_any_message = self.err_count > 0 || self.lint_err_count > 0 || self.warn_count > 0; + if !has_any_message && !self.suppressed_expected_diag && !std::thread::panicking() { let bugs = std::mem::replace(&mut self.good_path_delayed_bugs, Vec::new()); self.flush_delayed( bugs, @@ -675,15 +676,46 @@ impl Handler { /// Stash a given diagnostic with the given `Span` and [`StashKey`] as the key. /// Retrieve a stashed diagnostic with `steal_diagnostic`. pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) { - self.inner.borrow_mut().stash((span.with_parent(None), key), diag); + let mut inner = self.inner.borrow_mut(); + + let key = (span.with_parent(None), key); + + if diag.is_error() { + if matches!(diag.level, Level::Error { lint: true }) { + inner.lint_err_count += 1; + } else { + inner.err_count += 1; + } + } else { + // Warnings are only automatically flushed if they're forced. + if diag.is_force_warn() { + inner.warn_count += 1; + } + } + + // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic + // if/when we have a more robust macro-friendly replacement for `(span, key)` as a key. + // See the PR for a discussion. + inner.stashed_diagnostics.insert(key, diag); } /// Steal a previously stashed diagnostic with the given `Span` and [`StashKey`] as the key. pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_, ()>> { - self.inner - .borrow_mut() - .steal((span.with_parent(None), key)) - .map(|diag| DiagnosticBuilder::new_diagnostic(self, diag)) + let mut inner = self.inner.borrow_mut(); + let key = (span.with_parent(None), key); + let diag = inner.stashed_diagnostics.remove(&key)?; + if diag.is_error() { + if matches!(diag.level, Level::Error { lint: true }) { + inner.lint_err_count -= 1; + } else { + inner.err_count -= 1; + } + } else { + if diag.is_force_warn() { + inner.warn_count -= 1; + } + } + Some(DiagnosticBuilder::new_diagnostic(self, diag)) } pub fn has_stashed_diagnostic(&self, span: Span, key: StashKey) -> bool { @@ -847,7 +879,7 @@ impl Handler { &self, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - DiagnosticBuilder::new_guaranteeing_error(self, msg) + DiagnosticBuilder::new(self, Level::Error { lint: false }, msg) } /// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors. @@ -914,7 +946,7 @@ impl Handler { #[rustc_lint_diagnostics] #[track_caller] pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> { - DiagnosticBuilder::new_fatal(self, msg) + DiagnosticBuilder::new(self, Level::Fatal, msg) } /// Construct a builder at the `Help` level with the `msg`. @@ -996,19 +1028,42 @@ impl Handler { } /// For documentation on this, see `Session::span_delayed_bug`. + /// + /// Note: this function used to be called `delay_span_bug`. It was renamed + /// to match similar functions like `span_bug`, `span_err`, etc. #[track_caller] pub fn span_delayed_bug( &self, - span: impl Into<MultiSpan>, + sp: impl Into<MultiSpan>, msg: impl Into<String>, ) -> ErrorGuaranteed { - self.inner.borrow_mut().span_delayed_bug(span, msg) + let mut inner = self.inner.borrow_mut(); + + // This is technically `self.treat_err_as_bug()` but `span_delayed_bug` is called before + // incrementing `err_count` by one, so we need to +1 the comparing. + // FIXME: Would be nice to increment err_count in a more coherent way. + if inner.flags.treat_err_as_bug.is_some_and(|c| { + inner.err_count + inner.lint_err_count + inner.delayed_bug_count() + 1 >= c.get() + }) { + // FIXME: don't abort here if report_delayed_bugs is off + inner.span_bug(sp, msg.into()); + } + let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg.into()); + diagnostic.set_span(sp.into()); + inner.emit_diagnostic(&mut diagnostic).unwrap() } // FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's // where the explanation of what "good path" is (also, it should be renamed). pub fn good_path_delayed_bug(&self, msg: impl Into<DiagnosticMessage>) { - self.inner.borrow_mut().good_path_delayed_bug(msg) + let mut inner = self.inner.borrow_mut(); + + let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg); + if inner.flags.report_delayed_bugs { + inner.emit_diagnostic(&mut diagnostic); + } + let backtrace = std::backtrace::Backtrace::capture(); + inner.good_path_delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); } #[track_caller] @@ -1034,34 +1089,34 @@ impl Handler { db } - // NOTE: intentionally doesn't raise an error so rustc_codegen_ssa only reports fatal errors in the main thread #[rustc_lint_diagnostics] - pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> FatalError { - self.inner.borrow_mut().fatal(msg) + pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! { + DiagnosticBuilder::<FatalError>::new(self, Fatal, msg).emit().raise() } #[rustc_lint_diagnostics] pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed { - self.inner.borrow_mut().err(msg) + DiagnosticBuilder::<ErrorGuaranteed>::new(self, Error { lint: false }, msg).emit() } #[rustc_lint_diagnostics] pub fn warn(&self, msg: impl Into<DiagnosticMessage>) { - DiagnosticBuilder::new(self, Warning(None), msg).emit(); + DiagnosticBuilder::<()>::new(self, Warning(None), msg).emit(); } #[rustc_lint_diagnostics] pub fn note(&self, msg: impl Into<DiagnosticMessage>) { - DiagnosticBuilder::new(self, Note, msg).emit(); + DiagnosticBuilder::<()>::new(self, Note, msg).emit(); } pub fn bug(&self, msg: impl Into<DiagnosticMessage>) -> ! { - self.inner.borrow_mut().bug(msg) + DiagnosticBuilder::<diagnostic_builder::Bug>::new(self, Bug, msg).emit(); + panic::panic_any(ExplicitBug); } #[inline] pub fn err_count(&self) -> usize { - self.inner.borrow().err_count() + self.inner.borrow().err_count } pub fn has_errors(&self) -> Option<ErrorGuaranteed> { @@ -1072,26 +1127,103 @@ impl Handler { } pub fn has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed> { - self.inner.borrow().has_errors_or_lint_errors().then(|| { + let inner = self.inner.borrow(); + let has_errors_or_lint_errors = inner.has_errors() || inner.lint_err_count > 0; + has_errors_or_lint_errors.then(|| { #[allow(deprecated)] ErrorGuaranteed::unchecked_claim_error_was_emitted() }) } + pub fn has_errors_or_span_delayed_bugs(&self) -> Option<ErrorGuaranteed> { - self.inner.borrow().has_errors_or_span_delayed_bugs().then(|| { + let inner = self.inner.borrow(); + let has_errors_or_span_delayed_bugs = + inner.has_errors() || !inner.span_delayed_bugs.is_empty(); + has_errors_or_span_delayed_bugs.then(|| { #[allow(deprecated)] ErrorGuaranteed::unchecked_claim_error_was_emitted() }) } + pub fn is_compilation_going_to_fail(&self) -> Option<ErrorGuaranteed> { - self.inner.borrow().is_compilation_going_to_fail().then(|| { + let inner = self.inner.borrow(); + let will_fail = + inner.has_errors() || inner.lint_err_count > 0 || !inner.span_delayed_bugs.is_empty(); + will_fail.then(|| { #[allow(deprecated)] ErrorGuaranteed::unchecked_claim_error_was_emitted() }) } pub fn print_error_count(&self, registry: &Registry) { - self.inner.borrow_mut().print_error_count(registry) + let mut inner = self.inner.borrow_mut(); + + inner.emit_stashed_diagnostics(); + + let warnings = match inner.deduplicated_warn_count { + 0 => Cow::from(""), + 1 => Cow::from("1 warning emitted"), + count => Cow::from(format!("{count} warnings emitted")), + }; + let errors = match inner.deduplicated_err_count { + 0 => Cow::from(""), + 1 => Cow::from("aborting due to 1 previous error"), + count => Cow::from(format!("aborting due to {count} previous errors")), + }; + if inner.treat_err_as_bug() { + return; + } + + match (errors.len(), warnings.len()) { + (0, 0) => return, + (0, _) => inner.emitter.emit_diagnostic(&Diagnostic::new( + Level::Warning(None), + DiagnosticMessage::Str(warnings), + )), + (_, 0) => { + inner.emit_diagnostic(&mut Diagnostic::new(Fatal, errors)); + } + (_, _) => { + inner.emit_diagnostic(&mut Diagnostic::new(Fatal, format!("{errors}; {warnings}"))); + } + } + + let can_show_explain = inner.emitter.should_show_explain(); + let are_there_diagnostics = !inner.emitted_diagnostic_codes.is_empty(); + if can_show_explain && are_there_diagnostics { + let mut error_codes = inner + .emitted_diagnostic_codes + .iter() + .filter_map(|x| match &x { + DiagnosticId::Error(s) if registry.try_find_description(s).is_ok() => { + Some(s.clone()) + } + _ => None, + }) + .collect::<Vec<_>>(); + if !error_codes.is_empty() { + error_codes.sort(); + if error_codes.len() > 1 { + let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() }; + inner.failure_note(format!( + "Some errors have detailed explanations: {}{}", + error_codes[..limit].join(", "), + if error_codes.len() > 9 { "..." } else { "." } + )); + inner.failure_note(format!( + "For more information about an error, try \ + `rustc --explain {}`.", + &error_codes[0] + )); + } else { + inner.failure_note(format!( + "For more information about this error, try \ + `rustc --explain {}`.", + &error_codes[0] + )); + } + } + } } pub fn take_future_breakage_diagnostics(&self) -> Vec<Diagnostic> { @@ -1099,7 +1231,11 @@ impl Handler { } pub fn abort_if_errors(&self) { - self.inner.borrow_mut().abort_if_errors() + let mut inner = self.inner.borrow_mut(); + inner.emit_stashed_diagnostics(); + if inner.has_errors() { + FatalError.raise(); + } } /// `true` if we haven't taught a diagnostic with this code already. @@ -1108,11 +1244,11 @@ impl Handler { /// Used to suppress emitting the same error multiple times with extended explanation when /// calling `-Zteach`. pub fn must_teach(&self, code: &DiagnosticId) -> bool { - self.inner.borrow_mut().must_teach(code) + self.inner.borrow_mut().taught_diagnostics.insert(code.clone()) } pub fn force_print_diagnostic(&self, db: Diagnostic) { - self.inner.borrow_mut().force_print_diagnostic(db) + self.inner.borrow_mut().emitter.emit_diagnostic(&db); } pub fn emit_diagnostic(&self, diagnostic: &mut Diagnostic) -> Option<ErrorGuaranteed> { @@ -1196,11 +1332,11 @@ impl Handler { mut diag: Diagnostic, sp: impl Into<MultiSpan>, ) -> Option<ErrorGuaranteed> { - self.inner.borrow_mut().emit_diagnostic(diag.set_span(sp)) + self.emit_diagnostic(diag.set_span(sp)) } pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) { - self.inner.borrow_mut().emit_artifact_notification(path, artifact_type) + self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type); } pub fn emit_future_breakage_report(&self, diags: Vec<Diagnostic>) { @@ -1219,7 +1355,7 @@ impl Handler { inner.bump_err_count(); } - inner.emit_unused_externs(lint_level, unused_externs) + inner.emitter.emit_unused_externs(lint_level, unused_externs) } pub fn update_unstable_expectation_id( @@ -1270,15 +1406,11 @@ impl Handler { } } +// Note: we prefer implementing operations on `Handler`, rather than +// `HandlerInner`, whenever possible. This minimizes functions where +// `Handler::foo()` just borrows `inner` and forwards a call to +// `HanderInner::foo`. impl HandlerInner { - fn must_teach(&mut self, code: &DiagnosticId) -> bool { - self.taught_diagnostics.insert(code.clone()) - } - - fn force_print_diagnostic(&mut self, db: Diagnostic) { - self.emitter.emit_diagnostic(&db); - } - /// Emit all stashed diagnostics. fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> { let has_errors = self.has_errors(); @@ -1312,6 +1444,11 @@ impl HandlerInner { // FIXME(eddyb) this should ideally take `diagnostic` by value. fn emit_diagnostic(&mut self, diagnostic: &mut Diagnostic) -> Option<ErrorGuaranteed> { + if matches!(diagnostic.level, Level::Error { .. } | Level::Fatal) && self.treat_err_as_bug() + { + diagnostic.level = Level::Bug; + } + // The `LintExpectationId` can be stable or unstable depending on when it was created. // Diagnostics created before the definition of `HirId`s are unstable and can not yet // be stored. Instead, they are buffered until the `LintExpectationId` is replaced by @@ -1427,17 +1564,9 @@ impl HandlerInner { guaranteed } - fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) { - self.emitter.emit_artifact_notification(path, artifact_type); - } - - fn emit_unused_externs(&mut self, lint_level: rustc_lint_defs::Level, unused_externs: &[&str]) { - self.emitter.emit_unused_externs(lint_level, unused_externs); - } - fn treat_err_as_bug(&self) -> bool { self.flags.treat_err_as_bug.is_some_and(|c| { - self.err_count() + self.lint_err_count + self.delayed_bug_count() >= c.get() + self.err_count + self.lint_err_count + self.delayed_bug_count() >= c.get() }) } @@ -1445,141 +1574,8 @@ impl HandlerInner { self.span_delayed_bugs.len() + self.good_path_delayed_bugs.len() } - fn print_error_count(&mut self, registry: &Registry) { - self.emit_stashed_diagnostics(); - - let warnings = match self.deduplicated_warn_count { - 0 => Cow::from(""), - 1 => Cow::from("1 warning emitted"), - count => Cow::from(format!("{count} warnings emitted")), - }; - let errors = match self.deduplicated_err_count { - 0 => Cow::from(""), - 1 => Cow::from("aborting due to 1 previous error"), - count => Cow::from(format!("aborting due to {count} previous errors")), - }; - if self.treat_err_as_bug() { - return; - } - - match (errors.len(), warnings.len()) { - (0, 0) => return, - (0, _) => self.emitter.emit_diagnostic(&Diagnostic::new( - Level::Warning(None), - DiagnosticMessage::Str(warnings), - )), - (_, 0) => { - let _ = self.fatal(errors); - } - (_, _) => { - let _ = self.fatal(format!("{errors}; {warnings}")); - } - } - - let can_show_explain = self.emitter.should_show_explain(); - let are_there_diagnostics = !self.emitted_diagnostic_codes.is_empty(); - if can_show_explain && are_there_diagnostics { - let mut error_codes = self - .emitted_diagnostic_codes - .iter() - .filter_map(|x| match &x { - DiagnosticId::Error(s) if registry.try_find_description(s).is_ok() => { - Some(s.clone()) - } - _ => None, - }) - .collect::<Vec<_>>(); - if !error_codes.is_empty() { - error_codes.sort(); - if error_codes.len() > 1 { - let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() }; - self.failure_note(format!( - "Some errors have detailed explanations: {}{}", - error_codes[..limit].join(", "), - if error_codes.len() > 9 { "..." } else { "." } - )); - self.failure_note(format!( - "For more information about an error, try \ - `rustc --explain {}`.", - &error_codes[0] - )); - } else { - self.failure_note(format!( - "For more information about this error, try \ - `rustc --explain {}`.", - &error_codes[0] - )); - } - } - } - } - - fn stash(&mut self, key: (Span, StashKey), diagnostic: Diagnostic) { - // Track the diagnostic for counts, but don't panic-if-treat-err-as-bug - // yet; that happens when we actually emit the diagnostic. - if diagnostic.is_error() { - if matches!(diagnostic.level, Level::Error { lint: true }) { - self.lint_err_count += 1; - } else { - self.err_count += 1; - } - } else { - // Warnings are only automatically flushed if they're forced. - if diagnostic.is_force_warn() { - self.warn_count += 1; - } - } - - // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic - // if/when we have a more robust macro-friendly replacement for `(span, key)` as a key. - // See the PR for a discussion. - self.stashed_diagnostics.insert(key, diagnostic); - } - - fn steal(&mut self, key: (Span, StashKey)) -> Option<Diagnostic> { - let diagnostic = self.stashed_diagnostics.remove(&key)?; - if diagnostic.is_error() { - if matches!(diagnostic.level, Level::Error { lint: true }) { - self.lint_err_count -= 1; - } else { - self.err_count -= 1; - } - } else { - if diagnostic.is_force_warn() { - self.warn_count -= 1; - } - } - Some(diagnostic) - } - - #[inline] - fn err_count(&self) -> usize { - self.err_count - } - fn has_errors(&self) -> bool { - self.err_count() > 0 - } - fn has_errors_or_lint_errors(&self) -> bool { - self.has_errors() || self.lint_err_count > 0 - } - fn has_errors_or_span_delayed_bugs(&self) -> bool { - self.has_errors() || !self.span_delayed_bugs.is_empty() - } - fn has_any_message(&self) -> bool { - self.err_count() > 0 || self.lint_err_count > 0 || self.warn_count > 0 - } - - fn is_compilation_going_to_fail(&self) -> bool { - self.has_errors() || self.lint_err_count > 0 || !self.span_delayed_bugs.is_empty() - } - - fn abort_if_errors(&mut self) { - self.emit_stashed_diagnostics(); - - if self.has_errors() { - FatalError.raise(); - } + self.err_count > 0 } #[track_caller] @@ -1592,67 +1588,10 @@ impl HandlerInner { self.emit_diagnostic(diag.set_span(sp)); } - /// For documentation on this, see `Session::span_delayed_bug`. - /// - /// Note: this function used to be called `delay_span_bug`. It was renamed - /// to match similar functions like `span_bug`, `span_err`, etc. - #[track_caller] - fn span_delayed_bug( - &mut self, - sp: impl Into<MultiSpan>, - msg: impl Into<String>, - ) -> ErrorGuaranteed { - // This is technically `self.treat_err_as_bug()` but `span_delayed_bug` is called before - // incrementing `err_count` by one, so we need to +1 the comparing. - // FIXME: Would be nice to increment err_count in a more coherent way. - if self.flags.treat_err_as_bug.is_some_and(|c| { - self.err_count() + self.lint_err_count + self.delayed_bug_count() + 1 >= c.get() - }) { - // FIXME: don't abort here if report_delayed_bugs is off - self.span_bug(sp, msg.into()); - } - let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg.into()); - diagnostic.set_span(sp.into()); - self.emit_diagnostic(&mut diagnostic).unwrap() - } - - // FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's - // where the explanation of what "good path" is (also, it should be renamed). - fn good_path_delayed_bug(&mut self, msg: impl Into<DiagnosticMessage>) { - let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg); - if self.flags.report_delayed_bugs { - self.emit_diagnostic(&mut diagnostic); - } - let backtrace = std::backtrace::Backtrace::capture(); - self.good_path_delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); - } - fn failure_note(&mut self, msg: impl Into<DiagnosticMessage>) { self.emit_diagnostic(&mut Diagnostic::new(FailureNote, msg)); } - fn fatal(&mut self, msg: impl Into<DiagnosticMessage>) -> FatalError { - self.emit(Fatal, msg); - FatalError - } - - fn err(&mut self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed { - self.emit(Error { lint: false }, msg) - } - - /// Emit an error; level should be `Error` or `Fatal`. - fn emit(&mut self, level: Level, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed { - if self.treat_err_as_bug() { - self.bug(msg); - } - self.emit_diagnostic(&mut Diagnostic::new(level, msg)).unwrap() - } - - fn bug(&mut self, msg: impl Into<DiagnosticMessage>) -> ! { - self.emit_diagnostic(&mut Diagnostic::new(Bug, msg)); - panic::panic_any(ExplicitBug); - } - fn flush_delayed( &mut self, bugs: impl IntoIterator<Item = DelayedDiagnostic>, @@ -1723,7 +1662,7 @@ impl HandlerInner { fn panic_if_treat_err_as_bug(&self) { if self.treat_err_as_bug() { match ( - self.err_count() + self.lint_err_count, + self.err_count + self.lint_err_count, self.delayed_bug_count(), self.flags.treat_err_as_bug.map(|c| c.get()).unwrap(), ) { diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 91f3ca1d115..74f46efb365 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1145,11 +1145,6 @@ impl<'a> ExtCtxt<'a> { pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) { self.sess.diagnostic().span_err(sp, msg); } - #[rustc_lint_diagnostics] - #[track_caller] - pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) { - self.sess.diagnostic().span_warn(sp, msg); - } pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<String>) -> ! { self.sess.diagnostic().span_bug(sp, msg); } diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 9a8d0d691f0..794e11d87d1 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -547,7 +547,7 @@ impl<'a> ExtCtxt<'a> { binder: ast::ClosureBinder::NotPresent, capture_clause: ast::CaptureBy::Ref, constness: ast::Const::No, - asyncness: ast::Async::No, + coro_kind: None, movability: ast::Movability::Movable, fn_decl, body, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 9754f7acaae..5523543cd4f 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -719,12 +719,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ and it is only intended to be used in `alloc`." ), - rustc_attr!( - rustc_host, AttributeType::Normal, template!(Word), ErrorFollowing, - "#[rustc_host] annotates const generic parameters as the `host` effect param, \ - and it is only intended for internal use and as a desugaring." - ), - BuiltinAttribute { name: sym::rustc_diagnostic_item, // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`. diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 4385e745bac..c0d3fc3fae0 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -158,6 +158,9 @@ declare_features! ( /// Allows using `#[plugin_registrar]` on functions. (removed, plugin_registrar, "1.54.0", Some(29597), None, Some("plugins are no longer supported")), + /// Allows exhaustive integer pattern matching with `usize::MAX`/`isize::MIN`/`isize::MAX`. + (removed, precise_pointer_size_matching, "1.32.0", Some(56354), None, + Some("removed in favor of half-open ranges")), (removed, proc_macro_expr, "1.27.0", Some(54727), None, Some("subsumed by `#![feature(proc_macro_hygiene)]`")), (removed, proc_macro_gen, "1.27.0", Some(54727), None, diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index dee68bff21d..e68ab017380 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -56,8 +56,10 @@ macro_rules! declare_features { #[derive(Clone, Default, Debug)] pub struct Features { /// `#![feature]` attrs for language features, for error reporting. + /// "declared" here means that the feature is actually enabled in the current crate. pub declared_lang_features: Vec<(Symbol, Span, Option<Symbol>)>, /// `#![feature]` attrs for non-language (library) features. + /// "declared" here means that the feature is actually enabled in the current crate. pub declared_lib_features: Vec<(Symbol, Span)>, /// `declared_lang_features` + `declared_lib_features`. pub declared_features: FxHashSet<Symbol>, @@ -133,9 +135,18 @@ macro_rules! declare_features { $( sym::$feature => status_to_enum!($status) == FeatureStatus::Internal, )* - // Accepted/removed features aren't in this file but are never internal - // (a removed feature might have been internal, but that's now irrelevant). - _ if self.declared_features.contains(&feature) => false, + _ if self.declared_features.contains(&feature) => { + // This could be accepted/removed, or a libs feature. + // Accepted/removed features aren't in this file but are never internal + // (a removed feature might have been internal, but that's now irrelevant). + // Libs features are internal if they end in `_internal` or `_internals`. + // As a special exception we also consider `core_intrinsics` internal; + // renaming that age-old feature is just not worth the hassle. + // We just always test the name; it's not a big deal if we accidentally hit + // an accepted/removed lang feature that way. + let name = feature.as_str(); + name == "core_intrinsics" || name.ends_with("_internal") || name.ends_with("_internals") + } _ => panic!("`{}` was not listed in `declare_features`", feature), } } @@ -215,9 +226,6 @@ declare_features! ( (internal, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)), /// Added for testing unstable lints; perma-unstable. (internal, test_unstable_lint, "1.60.0", None, None), - /// Allows non-`unsafe` —and thus, unsound— access to `Pin` constructions. - /// Marked `internal` since perma-unstable and unsound. - (internal, unsafe_pin_internals, "1.60.0", None, None), /// Use for stable + negative coherence and strict coherence depending on trait's /// rustc_strict_coherence value. (unstable, with_negative_coherence, "1.60.0", None, None), @@ -543,8 +551,6 @@ declare_features! ( (unstable, offset_of_enum, "1.75.0", Some(106655), None), /// Allows using `#[optimize(X)]`. (unstable, optimize_attribute, "1.34.0", Some(54882), None), - /// Allows exhaustive integer pattern matching on `usize` and `isize`. - (unstable, precise_pointer_size_matching, "1.32.0", Some(56354), None), /// Allows macro attributes on expressions, statements and non-inline modules. (unstable, proc_macro_hygiene, "1.30.0", Some(54727), None), /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 81733d8f64e..ee66ebc2554 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -487,6 +487,7 @@ pub enum GenericParamKind<'hir> { ty: &'hir Ty<'hir>, /// Optional default value for the const generic param default: Option<AnonConst>, + is_host_effect: bool, }, } @@ -2255,6 +2256,8 @@ pub enum ImplItemKind<'hir> { /// The name of the associated type for `Fn` return types. pub const FN_OUTPUT_NAME: Symbol = sym::Output; +/// The name of the associated type for `Iterator` item types. +pub const ITERATOR_ITEM_NAME: Symbol = sym::Item; /// Bind a type to an associated type (i.e., `A = Foo`). /// diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 963b324ca13..9cf1db166a5 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -874,7 +874,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Generi match param.kind { GenericParamKind::Lifetime { .. } => {} GenericParamKind::Type { ref default, .. } => walk_list!(visitor, visit_ty, default), - GenericParamKind::Const { ref ty, ref default } => { + GenericParamKind::Const { ref ty, ref default, is_host_effect: _ } => { visitor.visit_ty(ty); if let Some(ref default) = default { visitor.visit_const_param_default(param.hir_id, default); diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index b53ffb98bf4..eb12ec7a098 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -9,7 +9,7 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorG use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::traits::FulfillmentError; -use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt}; +use rustc_middle::ty::{self, suggest_constraining_type_param, AssocItem, AssocKind, Ty, TyCtxt}; use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::symbol::{sym, Ident}; @@ -509,6 +509,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if associated_types.values().all(|v| v.is_empty()) { return; } + let tcx = self.tcx(); // FIXME: Marked `mut` so that we can replace the spans further below with a more // appropriate one, but this should be handled earlier in the span assignment. @@ -581,6 +582,32 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } + // We get all the associated items that _are_ set, + // so that we can check if any of their names match one of the ones we are missing. + // This would mean that they are shadowing the associated type we are missing, + // and we can then use their span to indicate this to the user. + let bound_names = trait_bounds + .iter() + .filter_map(|poly_trait_ref| { + let path = poly_trait_ref.trait_ref.path.segments.last()?; + let args = path.args?; + + Some(args.bindings.iter().filter_map(|binding| { + let ident = binding.ident; + let trait_def = path.res.def_id(); + let assoc_item = tcx.associated_items(trait_def).find_by_name_and_kind( + tcx, + ident, + AssocKind::Type, + trait_def, + ); + + Some((ident.name, assoc_item?)) + })) + }) + .flatten() + .collect::<FxHashMap<Symbol, &AssocItem>>(); + let mut names = names .into_iter() .map(|(trait_, mut assocs)| { @@ -621,16 +648,42 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { *names.entry(item.name).or_insert(0) += 1; } let mut dupes = false; + let mut shadows = false; for item in assoc_items { let prefix = if names[&item.name] > 1 { let trait_def_id = item.container_id(tcx); dupes = true; format!("{}::", tcx.def_path_str(trait_def_id)) + } else if bound_names.get(&item.name).is_some_and(|x| x != &item) { + let trait_def_id = item.container_id(tcx); + shadows = true; + format!("{}::", tcx.def_path_str(trait_def_id)) } else { String::new() }; + + let mut is_shadowed = false; + + if let Some(assoc_item) = bound_names.get(&item.name) + && assoc_item != &item + { + is_shadowed = true; + + let rename_message = + if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" }; + err.span_label( + tcx.def_span(assoc_item.def_id), + format!("`{}{}` shadowed here{}", prefix, item.name, rename_message), + ); + } + + let rename_message = if is_shadowed { ", consider renaming it" } else { "" }; + if let Some(sp) = tcx.hir().span_if_local(item.def_id) { - err.span_label(sp, format!("`{}{}` defined here", prefix, item.name)); + err.span_label( + sp, + format!("`{}{}` defined here{}", prefix, item.name, rename_message), + ); } } if potential_assoc_types.len() == assoc_items.len() { @@ -638,8 +691,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // extra type arguments present. A suggesting to replace the generic args with // associated types is already emitted. already_has_generics_args_suggestion = true; - } else if let (Ok(snippet), false) = - (tcx.sess.source_map().span_to_snippet(*span), dupes) + } else if let (Ok(snippet), false, false) = + (tcx.sess.source_map().span_to_snippet(*span), dupes, shadows) { let types: Vec<_> = assoc_items.iter().map(|item| format!("{} = Type", item.name)).collect(); @@ -721,6 +774,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.span_help(where_constraints, where_msg); } } + err.emit(); } } diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index d29a27eced0..47fbed45b91 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -243,6 +243,31 @@ pub fn create_args_for_parent_generic_args<'tcx, 'a>( match (args_iter.peek(), params.peek()) { (Some(&arg), Some(¶m)) => { match (arg, ¶m.kind, arg_count.explicit_late_bound) { + ( + GenericArg::Const(hir::ConstArg { + is_desugared_from_effects: true, + .. + }), + GenericParamDefKind::Const { is_host_effect: false, .. } + | GenericParamDefKind::Type { .. } + | GenericParamDefKind::Lifetime, + _, + ) => { + // SPECIAL CASE FOR DESUGARED EFFECT PARAMS + // This comes from the following example: + // + // ``` + // #[const_trait] + // pub trait PartialEq<Rhs: ?Sized = Self> {} + // impl const PartialEq for () {} + // ``` + // + // Since this is a const impl, we need to insert `<false>` at the end of + // `PartialEq`'s generics, but this errors since `Rhs` isn't specified. + // To work around this, we infer all arguments until we reach the host param. + args.push(ctx.inferred_kind(Some(&args), param, infer_args)); + params.next(); + } (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _) | ( GenericArg::Type(_) | GenericArg::Infer(_), diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index fd3e6bd44e7..0f06407f445 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1182,10 +1182,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if let Some(bound_span) = bound_span { err.span_label( bound_span, - format!( - "ambiguous `{assoc_name}` from `{}`", - bound.print_only_trait_path(), - ), + format!("ambiguous `{assoc_name}` from `{}`", bound.print_trait_sugared(),), ); if let Some(constraint) = &is_equality { where_bounds.push(format!( diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs index 6cb38c741b7..ce5426b5142 100644 --- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs @@ -106,6 +106,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait here instead: `trait NewTrait: {} {{}}`", regular_traits .iter() + // FIXME: This should `print_sugared`, but also needs to integrate projection bounds... .map(|t| t.trait_ref().print_only_trait_path().to_string()) .collect::<Vec<_>>() .join(" + "), diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 92619ae417b..3e805ab00b9 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -859,7 +859,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => Ok(()), // Const parameters are well formed if their type is structural match. - hir::GenericParamKind::Const { ty: hir_ty, default: _ } => { + hir::GenericParamKind::Const { ty: hir_ty, default: _, is_host_effect: _ } => { let ty = tcx.type_of(param.def_id).instantiate_identity(); if tcx.features().adt_const_params { diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index 42e2818b63f..8a02bab92aa 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -23,7 +23,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { tcx.def_span(def_id), E0199, "implementing the trait `{}` is not unsafe", - trait_ref.print_only_trait_path() + trait_ref.print_trait_sugared() ) .span_suggestion_verbose( item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)), @@ -40,13 +40,13 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { tcx.def_span(def_id), E0200, "the trait `{}` requires an `unsafe impl` declaration", - trait_ref.print_only_trait_path() + trait_ref.print_trait_sugared() ) .note(format!( "the trait `{}` enforces invariants that the compiler can't check. \ Review the trait documentation and make sure this implementation \ upholds those invariants before adding the `unsafe` keyword", - trait_ref.print_only_trait_path() + trait_ref.print_trait_sugared() )) .span_suggestion_verbose( item.span.shrink_to_lo(), @@ -69,7 +69,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { "the trait `{}` enforces invariants that the compiler can't check. \ Review the trait documentation and make sure this implementation \ upholds those invariants before adding the `unsafe` keyword", - trait_ref.print_only_trait_path() + trait_ref.print_trait_sugared() )) .span_suggestion_verbose( item.span.shrink_to_lo(), diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 0a1b8c8eea5..ae35d6ebd75 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1383,7 +1383,7 @@ fn impl_trait_ref( let last_segment = path_segments.len() - 1; let mut args = *path_segments[last_segment].args(); let last_arg = args.args.len() - 1; - assert!(matches!(args.args[last_arg], hir::GenericArg::Const(anon_const) if tcx.has_attr(anon_const.value.def_id, sym::rustc_host))); + assert!(matches!(args.args[last_arg], hir::GenericArg::Const(anon_const) if anon_const.is_desugared_from_effects)); args.args = &args.args[..args.args.len() - 1]; path_segments[last_segment].args = Some(&args); let path = hir::Path { diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 9fc994dfe50..114c5147e11 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -9,7 +9,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{kw, Symbol}; -use rustc_span::{sym, Span}; +use rustc_span::Span; pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { use rustc_hir::*; @@ -298,13 +298,11 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { kind, }) } - GenericParamKind::Const { default, .. } => { - let is_host_param = tcx.has_attr(param.def_id, sym::rustc_host); - + GenericParamKind::Const { ty: _, default, is_host_effect } => { if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() - // `rustc_host` effect params are allowed to have defaults. - && !is_host_param + // `host` effect params are allowed to have defaults. + && !is_host_effect { tcx.sess.span_err( param.span, @@ -315,7 +313,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { let index = next_index(); - if is_host_param { + if is_host_effect { if let Some(idx) = host_effect_index { bug!("parent also has host effect param? index: {idx}, def: {def_id:?}"); } @@ -330,7 +328,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { pure_wrt_drop: param.pure_wrt_drop, kind: ty::GenericParamDefKind::Const { has_default: default.is_some(), - is_host_effect: is_host_param, + is_host_effect, }, }) } @@ -489,7 +487,7 @@ struct AnonConstInParamTyDetector { impl<'v> Visitor<'v> for AnonConstInParamTyDetector { fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) { - if let GenericParamKind::Const { ty, default: _ } = p.kind { + if let GenericParamKind::Const { ty, default: _, is_host_effect: _ } = p.kind { let prev = self.in_param_ty; self.in_param_ty = true; self.visit_ty(ty); 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 c6ea853b9ba..e939b7abd90 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -992,7 +992,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { self.visit_ty(ty); } } - GenericParamKind::Const { ty, default } => { + GenericParamKind::Const { ty, default, is_host_effect: _ } => { self.visit_ty(ty); if let Some(default) = default { self.visit_body(self.tcx.hir().body(default.body)); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index b7e7d258a90..1c4534287eb 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2126,7 +2126,7 @@ impl<'a> State<'a> { self.print_type(default); } } - GenericParamKind::Const { ty, ref default } => { + GenericParamKind::Const { ty, ref default, is_host_effect: _ } => { self.word_space(":"); self.print_type(ty); if let Some(default) = default { diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index cb36d510149..f0bb18df48c 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -651,9 +651,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, ) } - Some(hir::CoroutineKind::Gen(hir::CoroutineSource::Fn)) => { - todo!("gen closures do not exist yet") - } + // For a `gen {}` block created as a `gen fn` body, we need the return type to be + // (). + Some(hir::CoroutineKind::Gen(hir::CoroutineSource::Fn)) => self.tcx.types.unit, _ => astconv.ty_infer(None, decl.output.span()), }, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index a904b419a94..2c9942caab2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1619,6 +1619,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None, ); } else { + if let Some(errors) = + self.could_impl_trait(clone_trait_did, expected_ty, self.param_env) + { + match &errors[..] { + [] => {} + [error] => { + diag.help(format!( + "`Clone` is not implemented because the trait bound `{}` is \ + not satisfied", + 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, + )); + } + } + for error in errors { + if let traits::FulfillmentErrorCode::CodeSelectionError( + traits::SelectionError::Unimplemented, + ) = error.code + && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = + error.obligation.predicate.kind().skip_binder() + { + self.infcx.err_ctxt().suggest_derive( + &error.obligation, + diag, + error.obligation.predicate.kind().rebind(pred), + ); + } + } + } self.suggest_derive(diag, &[(trait_ref.to_predicate(self.tcx), None, None)]); } } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 858385246dd..143454c71e1 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2288,7 +2288,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Adt(def, _) if def.did().is_local() => { spans.push_span_label( self.tcx.def_span(def.did()), - format!("must implement `{}`", pred.trait_ref.print_only_trait_path()), + format!("must implement `{}`", pred.trait_ref.print_trait_sugared()), ); } _ => {} @@ -2299,7 +2299,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let msg = if preds.len() == 1 { format!( "an implementation of `{}` might be missing for `{}`", - preds[0].trait_ref.print_only_trait_path(), + preds[0].trait_ref.print_trait_sugared(), preds[0].self_ty() ) } else { diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 9cdf78484d4..ecaf9f4e169 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2219,8 +2219,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer::ExistentialProjection(exp_found) => self.expected_found_str(exp_found), infer::PolyTraitRefs(exp_found) => { let pretty_exp_found = ty::error::ExpectedFound { - expected: exp_found.expected.print_only_trait_path(), - found: exp_found.found.print_only_trait_path(), + expected: exp_found.expected.print_trait_sugared(), + found: exp_found.found.print_trait_sugared(), }; match self.expected_found_str(pretty_exp_found) { Some((expected, found, _, _)) if expected == found => { diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 8a6d8d3d42e..7831b251db4 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -10,8 +10,8 @@ use rustc_data_structures::sync::Lrc; use rustc_errors::registry::Registry; use rustc_errors::{ErrorGuaranteed, Handler}; use rustc_lint::LintStore; +use rustc_middle::ty; use rustc_middle::util::Providers; -use rustc_middle::{bug, ty}; use rustc_parse::maybe_new_parser_from_source_str; use rustc_query_impl::QueryCtxt; use rustc_query_system::query::print_query_stack; @@ -42,7 +42,7 @@ pub struct Compiler { } /// Converts strings provided as `--cfg [cfgspec]` into a `Cfg`. -pub(crate) fn parse_cfg(handler: &EarlyErrorHandler, cfgs: Vec<String>) -> Cfg { +pub(crate) fn parse_cfg(handler: &Handler, cfgs: Vec<String>) -> Cfg { cfgs.into_iter() .map(|s| { let sess = ParseSess::with_silent_emitter(Some(format!( @@ -52,10 +52,14 @@ pub(crate) fn parse_cfg(handler: &EarlyErrorHandler, cfgs: Vec<String>) -> Cfg { macro_rules! error { ($reason: expr) => { - handler.early_error(format!( - concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), - s - )); + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] + handler + .struct_fatal(format!( + concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), + s + )) + .emit(); }; } @@ -97,14 +101,13 @@ pub(crate) fn parse_cfg(handler: &EarlyErrorHandler, cfgs: Vec<String>) -> Cfg { } /// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`. -pub(crate) fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> CheckCfg { +pub(crate) fn parse_check_cfg(handler: &Handler, specs: Vec<String>) -> CheckCfg { // If any --check-cfg is passed then exhaustive_values and exhaustive_names // are enabled by default. let exhaustive_names = !specs.is_empty(); let exhaustive_values = !specs.is_empty(); let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg::default() }; - let mut old_syntax = None; for s in specs { let sess = ParseSess::with_silent_emitter(Some(format!( "this error occurred on the command line: `--check-cfg={s}`" @@ -113,10 +116,14 @@ pub(crate) fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) - macro_rules! error { ($reason:expr) => { - handler.early_error(format!( - concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"), - s - )) + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] + handler + .struct_fatal(format!( + concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"), + s + )) + .emit() }; } @@ -142,174 +149,101 @@ pub(crate) fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) - expected_error(); }; - let mut set_old_syntax = || { - // defaults are flipped for the old syntax - if old_syntax == None { - check_cfg.exhaustive_names = false; - check_cfg.exhaustive_values = false; - } - old_syntax = Some(true); - }; + if !meta_item.has_name(sym::cfg) { + expected_error(); + } - if meta_item.has_name(sym::names) { - set_old_syntax(); - - check_cfg.exhaustive_names = true; - for arg in args { - if arg.is_word() - && let Some(ident) = arg.ident() - { - check_cfg.expecteds.entry(ident.name).or_insert(ExpectedValues::Any); - } else { - error!("`names()` arguments must be simple identifiers"); - } - } - } else if meta_item.has_name(sym::values) { - set_old_syntax(); - - if let Some((name, values)) = args.split_first() { - if name.is_word() - && let Some(ident) = name.ident() - { - let expected_values = check_cfg - .expecteds - .entry(ident.name) - .and_modify(|expected_values| match expected_values { - ExpectedValues::Some(_) => {} - ExpectedValues::Any => { - // handle the case where names(...) was done - // before values by changing to a list - *expected_values = ExpectedValues::Some(FxHashSet::default()); - } - }) - .or_insert_with(|| ExpectedValues::Some(FxHashSet::default())); + let mut names = Vec::new(); + let mut values: FxHashSet<_> = Default::default(); - let ExpectedValues::Some(expected_values) = expected_values else { - bug!("`expected_values` should be a list a values") - }; + let mut any_specified = false; + let mut values_specified = false; + let mut values_any_specified = false; - for val in values { - if let Some(LitKind::Str(s, _)) = val.lit().map(|lit| &lit.kind) { - expected_values.insert(Some(*s)); - } else { - error!("`values()` arguments must be string literals"); - } - } - - if values.is_empty() { - expected_values.insert(None); - } - } else { - error!("`values()` first argument must be a simple identifier"); + for arg in args { + if arg.is_word() + && let Some(ident) = arg.ident() + { + if values_specified { + error!("`cfg()` names cannot be after values"); } - } else if args.is_empty() { - check_cfg.exhaustive_values = true; - } else { - expected_error(); - } - } else if meta_item.has_name(sym::cfg) { - old_syntax = Some(false); - - let mut names = Vec::new(); - let mut values: FxHashSet<_> = Default::default(); - - let mut any_specified = false; - let mut values_specified = false; - let mut values_any_specified = false; - - for arg in args { - if arg.is_word() - && let Some(ident) = arg.ident() - { - if values_specified { - error!("`cfg()` names cannot be after values"); - } - names.push(ident); - } else if arg.has_name(sym::any) - && let Some(args) = arg.meta_item_list() - { - if any_specified { - error!("`any()` cannot be specified multiple times"); - } - any_specified = true; - if !args.is_empty() { - error!("`any()` must be empty"); - } - } else if arg.has_name(sym::values) - && let Some(args) = arg.meta_item_list() - { - if names.is_empty() { - error!("`values()` cannot be specified before the names"); - } else if values_specified { - error!("`values()` cannot be specified multiple times"); - } - values_specified = true; - - for arg in args { - if let Some(LitKind::Str(s, _)) = arg.lit().map(|lit| &lit.kind) { - values.insert(Some(*s)); - } else if arg.has_name(sym::any) - && let Some(args) = arg.meta_item_list() - { - if values_any_specified { - error!("`any()` in `values()` cannot be specified multiple times"); - } - values_any_specified = true; - if !args.is_empty() { - error!("`any()` must be empty"); - } - } else { - error!("`values()` arguments must be string literals or `any()`"); + names.push(ident); + } else if arg.has_name(sym::any) + && let Some(args) = arg.meta_item_list() + { + if any_specified { + error!("`any()` cannot be specified multiple times"); + } + any_specified = true; + if !args.is_empty() { + error!("`any()` must be empty"); + } + } else if arg.has_name(sym::values) + && let Some(args) = arg.meta_item_list() + { + if names.is_empty() { + error!("`values()` cannot be specified before the names"); + } else if values_specified { + error!("`values()` cannot be specified multiple times"); + } + values_specified = true; + + for arg in args { + if let Some(LitKind::Str(s, _)) = arg.lit().map(|lit| &lit.kind) { + values.insert(Some(*s)); + } else if arg.has_name(sym::any) + && let Some(args) = arg.meta_item_list() + { + if values_any_specified { + error!("`any()` in `values()` cannot be specified multiple times"); + } + values_any_specified = true; + if !args.is_empty() { + error!("`any()` must be empty"); } + } else { + error!("`values()` arguments must be string literals or `any()`"); } - } else { - error!( - "`cfg()` arguments must be simple identifiers, `any()` or `values(...)`" - ); } + } else { + error!("`cfg()` arguments must be simple identifiers, `any()` or `values(...)`"); } + } - if values.is_empty() && !values_any_specified && !any_specified { - values.insert(None); - } else if !values.is_empty() && values_any_specified { - error!( - "`values()` arguments cannot specify string literals and `any()` at the same time" - ); - } + if values.is_empty() && !values_any_specified && !any_specified { + values.insert(None); + } else if !values.is_empty() && values_any_specified { + error!( + "`values()` arguments cannot specify string literals and `any()` at the same time" + ); + } - if any_specified { - if names.is_empty() - && values.is_empty() - && !values_specified - && !values_any_specified - { - check_cfg.exhaustive_names = false; - } else { - error!("`cfg(any())` can only be provided in isolation"); - } + if any_specified { + if names.is_empty() && values.is_empty() && !values_specified && !values_any_specified { + check_cfg.exhaustive_names = false; } else { - for name in names { - check_cfg - .expecteds - .entry(name.name) - .and_modify(|v| match v { - ExpectedValues::Some(v) if !values_any_specified => { - v.extend(values.clone()) - } - ExpectedValues::Some(_) => *v = ExpectedValues::Any, - ExpectedValues::Any => {} - }) - .or_insert_with(|| { - if values_any_specified { - ExpectedValues::Any - } else { - ExpectedValues::Some(values.clone()) - } - }); - } + error!("`cfg(any())` can only be provided in isolation"); } } else { - expected_error(); + for name in names { + check_cfg + .expecteds + .entry(name.name) + .and_modify(|v| match v { + ExpectedValues::Some(v) if !values_any_specified => { + v.extend(values.clone()) + } + ExpectedValues::Some(_) => *v = ExpectedValues::Any, + ExpectedValues::Any => {} + }) + .or_insert_with(|| { + if values_any_specified { + ExpectedValues::Any + } else { + ExpectedValues::Some(values.clone()) + } + }); + } } } @@ -388,13 +322,13 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se || { crate::callbacks::setup_callbacks(); - let handler = EarlyErrorHandler::new(config.opts.error_format); + let early_handler = EarlyErrorHandler::new(config.opts.error_format); let codegen_backend = if let Some(make_codegen_backend) = config.make_codegen_backend { make_codegen_backend(&config.opts) } else { util::get_codegen_backend( - &handler, + &early_handler, &config.opts.maybe_sysroot, config.opts.unstable_opts.codegen_backend.as_deref(), ) @@ -411,7 +345,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se ) { Ok(bundle) => bundle, Err(e) => { - handler.early_error(format!("failed to load fluent bundle: {e}")); + early_handler.early_error(format!("failed to load fluent bundle: {e}")); } }; @@ -422,7 +356,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se let target_override = codegen_backend.target_override(&config.opts); let mut sess = rustc_session::build_session( - &handler, + early_handler, config.opts, CompilerIO { input: config.input, @@ -444,12 +378,12 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se codegen_backend.init(&sess); - let cfg = parse_cfg(&handler, config.crate_cfg); + let cfg = parse_cfg(&sess.diagnostic(), config.crate_cfg); let mut cfg = config::build_configuration(&sess, cfg); util::add_configuration(&mut cfg, &mut sess, &*codegen_backend); sess.parse_sess.config = cfg; - let mut check_cfg = parse_check_cfg(&handler, config.crate_check_cfg); + let mut check_cfg = parse_check_cfg(&sess.diagnostic(), config.crate_check_cfg); check_cfg.fill_well_known(&sess.target); sess.parse_sess.check_config = check_cfg; diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 21d5b0f4169..cfa46447845 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -6,7 +6,6 @@ #![feature(let_chains)] #![feature(try_blocks)] #![recursion_limit = "256"] -#![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index fab8a18f2dc..09d92c2dfc0 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -306,6 +306,8 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { // Gate identifiers containing invalid Unicode codepoints that were recovered during lexing. sess.parse_sess.bad_unicode_identifiers.with_lock(|identifiers| { + // We will soon sort, so the initial order does not matter. + #[allow(rustc::potential_query_instability)] let mut identifiers: Vec<_> = identifiers.drain().collect(); identifiers.sort_by_key(|&(key, _)| key); for (ident, mut spans) in identifiers.into_iter() { @@ -431,6 +433,9 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P escape_dep_filename(&file.prefer_local().to_string()) }; + // The entries will be used to declare dependencies beween files in a + // Makefile-like output, so the iteration order does not matter. + #[allow(rustc::potential_query_instability)] let extra_tracked_files = file_depinfo.iter().map(|path_sym| normalize_path(PathBuf::from(path_sym.as_str()))); files.extend(extra_tracked_files); @@ -486,6 +491,8 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P // Emit special comments with information about accessed environment variables. let env_depinfo = sess.parse_sess.env_depinfo.borrow(); if !env_depinfo.is_empty() { + // We will soon sort, so the initial order does not matter. + #[allow(rustc::potential_query_instability)] let mut envs: Vec<_> = env_depinfo .iter() .map(|(k, v)| (escape_dep_env(*k), v.map(escape_dep_env))) diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 714af977fb5..f7b6ab331a5 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -25,10 +25,10 @@ use std::num::NonZeroUsize; use std::path::{Path, PathBuf}; use std::sync::Arc; -fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Session, Cfg) { +fn mk_session(matches: getopts::Matches) -> (Session, Cfg) { + let mut early_handler = EarlyErrorHandler::new(ErrorOutputType::default()); let registry = registry::Registry::new(&[]); - let sessopts = build_session_options(handler, &matches); - let cfg = parse_cfg(handler, matches.opt_strs("cfg")); + let sessopts = build_session_options(&mut early_handler, &matches); let temps_dir = sessopts.unstable_opts.temps_dir.as_deref().map(PathBuf::from); let io = CompilerIO { input: Input::Str { name: FileName::Custom(String::new()), input: String::new() }, @@ -37,7 +37,7 @@ fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Se temps_dir, }; let sess = build_session( - handler, + early_handler, sessopts, io, None, @@ -51,6 +51,7 @@ fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Se Arc::default(), Default::default(), ); + let cfg = parse_cfg(&sess.diagnostic(), matches.opt_strs("cfg")); (sess, cfg) } @@ -117,8 +118,7 @@ fn assert_non_crate_hash_different(x: &Options, y: &Options) { fn test_switch_implies_cfg_test() { rustc_span::create_default_session_globals_then(|| { let matches = optgroups().parse(&["--test".to_string()]).unwrap(); - let mut handler = EarlyErrorHandler::new(ErrorOutputType::default()); - let (sess, cfg) = mk_session(&mut handler, matches); + let (sess, cfg) = mk_session(matches); let cfg = build_configuration(&sess, cfg); assert!(cfg.contains(&(sym::test, None))); }); @@ -129,8 +129,7 @@ fn test_switch_implies_cfg_test() { fn test_switch_implies_cfg_test_unless_cfg_test() { rustc_span::create_default_session_globals_then(|| { let matches = optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]).unwrap(); - let mut handler = EarlyErrorHandler::new(ErrorOutputType::default()); - let (sess, cfg) = mk_session(&mut handler, matches); + let (sess, cfg) = mk_session(matches); let cfg = build_configuration(&sess, cfg); let mut test_items = cfg.iter().filter(|&&(name, _)| name == sym::test); assert!(test_items.next().is_some()); @@ -142,23 +141,20 @@ fn test_switch_implies_cfg_test_unless_cfg_test() { fn test_can_print_warnings() { rustc_span::create_default_session_globals_then(|| { let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap(); - let mut handler = EarlyErrorHandler::new(ErrorOutputType::default()); - let (sess, _) = mk_session(&mut handler, matches); + let (sess, _) = mk_session(matches); assert!(!sess.diagnostic().can_emit_warnings()); }); rustc_span::create_default_session_globals_then(|| { let matches = optgroups().parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()]).unwrap(); - let mut handler = EarlyErrorHandler::new(ErrorOutputType::default()); - let (sess, _) = mk_session(&mut handler, matches); + let (sess, _) = mk_session(matches); assert!(sess.diagnostic().can_emit_warnings()); }); rustc_span::create_default_session_globals_then(|| { let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap(); - let mut handler = EarlyErrorHandler::new(ErrorOutputType::default()); - let (sess, _) = mk_session(&mut handler, matches); + let (sess, _) = mk_session(matches); assert!(sess.diagnostic().can_emit_warnings()); }); } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 4cccaeeca84..7c4f81a4c39 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -162,7 +162,11 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> // Explicitly check for lints associated with 'closure_id', since // it does not have a corresponding AST node if let ast_visit::FnKind::Fn(_, _, sig, _, _, _) = fk { - if let ast::Async::Yes { closure_id, .. } = sig.header.asyncness { + if let Some( + ast::CoroutineKind::Async { closure_id, .. } + | ast::CoroutineKind::Gen { closure_id, .. }, + ) = sig.header.coro_kind + { self.check_id(closure_id); } } @@ -223,7 +227,11 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> // it does not have a corresponding AST node match e.kind { ast::ExprKind::Closure(box ast::Closure { - asyncness: ast::Async::Yes { closure_id, .. }, + coro_kind: + Some( + ast::CoroutineKind::Async { closure_id, .. } + | ast::CoroutineKind::Gen { closure_id, .. }, + ), .. }) => self.check_id(closure_id), _ => {} diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index d6ed0250efc..59f27a88aec 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -534,9 +534,9 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { } fn check_generic_param(&mut self, cx: &LateContext<'_>, param: &hir::GenericParam<'_>) { - if let GenericParamKind::Const { .. } = param.kind { - // `rustc_host` params are explicitly allowed to be lowercase. - if cx.tcx.has_attr(param.def_id, sym::rustc_host) { + if let GenericParamKind::Const { is_host_effect, .. } = param.kind { + // `host` params are explicitly allowed to be lowercase. + if is_host_effect { return; } NonUpperCaseGlobals::check_upper_case(cx, "const parameter", ¶m.name.ident()); diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 0a167b0893c..c492e7c6fbf 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -291,7 +291,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { .map(|inner| MustUsePath::Pinned(Box::new(inner))) } ty::Adt(def, _) => is_def_must_use(cx, def.did(), span), - ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { + ty::Alias(ty::Opaque | ty::Projection, ty::AliasTy { def_id: def, .. }) => { elaborate( cx.tcx, cx.tcx.explicit_item_bounds(def).instantiate_identity_iter_copied(), diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index a2243817df9..e6e445c54b1 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -8,6 +8,135 @@ use crate::{declare_lint, declare_lint_pass, FutureIncompatibilityReason}; use rustc_span::edition::Edition; use rustc_span::symbol::sym; +declare_lint_pass! { + /// Does nothing as a lint pass, but registers some `Lint`s + /// that are used by other parts of the compiler. + HardwiredLints => [ + // tidy-alphabetical-start + ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, + AMBIGUOUS_ASSOCIATED_ITEMS, + AMBIGUOUS_GLOB_IMPORTS, + AMBIGUOUS_GLOB_REEXPORTS, + ARITHMETIC_OVERFLOW, + ASM_SUB_REGISTER, + BAD_ASM_STYLE, + BARE_TRAIT_OBJECTS, + BINDINGS_WITH_VARIANT_NAME, + BREAK_WITH_LABEL_AND_LOOP, + BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, + CENUM_IMPL_DROP_CAST, + COHERENCE_LEAK_CHECK, + COINDUCTIVE_OVERLAP_IN_COHERENCE, + CONFLICTING_REPR_HINTS, + CONST_EVALUATABLE_UNCHECKED, + CONST_ITEM_MUTATION, + CONST_PATTERNS_WITHOUT_PARTIAL_EQ, + DEAD_CODE, + DEPRECATED, + DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, + DEPRECATED_IN_FUTURE, + DEPRECATED_WHERE_CLAUSE_LOCATION, + DUPLICATE_MACRO_ATTRIBUTES, + ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, + ELIDED_LIFETIMES_IN_PATHS, + EXPORTED_PRIVATE_DEPENDENCIES, + FFI_UNWIND_CALLS, + FORBIDDEN_LINT_GROUPS, + FUNCTION_ITEM_REFERENCES, + FUZZY_PROVENANCE_CASTS, + HIDDEN_GLOB_REEXPORTS, + ILL_FORMED_ATTRIBUTE_INPUT, + ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, + IMPLIED_BOUNDS_ENTAILMENT, + INCOMPLETE_INCLUDE, + INDIRECT_STRUCTURAL_MATCH, + INEFFECTIVE_UNSTABLE_TRAIT_IMPL, + INLINE_NO_SANITIZE, + INVALID_DOC_ATTRIBUTES, + INVALID_MACRO_EXPORT_ARGUMENTS, + INVALID_TYPE_PARAM_DEFAULT, + IRREFUTABLE_LET_PATTERNS, + LARGE_ASSIGNMENTS, + LATE_BOUND_LIFETIME_ARGUMENTS, + LEGACY_DERIVE_HELPERS, + LONG_RUNNING_CONST_EVAL, + LOSSY_PROVENANCE_CASTS, + MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, + MACRO_USE_EXTERN_CRATE, + META_VARIABLE_MISUSE, + MISSING_ABI, + MISSING_FRAGMENT_SPECIFIER, + MUST_NOT_SUSPEND, + NAMED_ARGUMENTS_USED_POSITIONALLY, + NON_EXHAUSTIVE_OMITTED_PATTERNS, + NONTRIVIAL_STRUCTURAL_MATCH, + ORDER_DEPENDENT_TRAIT_OBJECTS, + OVERLAPPING_RANGE_ENDPOINTS, + PATTERNS_IN_FNS_WITHOUT_BODY, + POINTER_STRUCTURAL_MATCH, + PRIVATE_BOUNDS, + PRIVATE_INTERFACES, + PROC_MACRO_BACK_COMPAT, + PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, + PUB_USE_OF_PRIVATE_EXTERN_CRATE, + REFINING_IMPL_TRAIT, + RENAMED_AND_REMOVED_LINTS, + REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, + RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, + RUST_2021_INCOMPATIBLE_OR_PATTERNS, + RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, + RUST_2021_PRELUDE_COLLISIONS, + SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, + SINGLE_USE_LIFETIMES, + SOFT_UNSTABLE, + STABLE_FEATURES, + SUSPICIOUS_AUTO_TRAIT_IMPLS, + TEST_UNSTABLE_LINT, + TEXT_DIRECTION_CODEPOINT_IN_COMMENT, + TRIVIAL_CASTS, + TRIVIAL_NUMERIC_CASTS, + TYVAR_BEHIND_RAW_POINTER, + UNCONDITIONAL_PANIC, + UNCONDITIONAL_RECURSION, + UNDEFINED_NAKED_FUNCTION_ABI, + UNEXPECTED_CFGS, + UNFULFILLED_LINT_EXPECTATIONS, + UNINHABITED_STATIC, + UNKNOWN_CRATE_TYPES, + UNKNOWN_LINTS, + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + UNNAMEABLE_TEST_ITEMS, + UNNAMEABLE_TYPES, + UNREACHABLE_CODE, + UNREACHABLE_PATTERNS, + UNSAFE_OP_IN_UNSAFE_FN, + UNSTABLE_NAME_COLLISIONS, + UNSTABLE_SYNTAX_PRE_EXPANSION, + UNSUPPORTED_CALLING_CONVENTIONS, + UNUSED_ASSIGNMENTS, + UNUSED_ASSOCIATED_TYPE_BOUNDS, + UNUSED_ATTRIBUTES, + UNUSED_CRATE_DEPENDENCIES, + UNUSED_EXTERN_CRATES, + UNUSED_FEATURES, + UNUSED_IMPORTS, + UNUSED_LABELS, + UNUSED_LIFETIMES, + UNUSED_MACRO_RULES, + UNUSED_MACROS, + UNUSED_MUT, + UNUSED_QUALIFICATIONS, + UNUSED_TUPLE_STRUCT_FIELDS, + UNUSED_UNSAFE, + UNUSED_VARIABLES, + USELESS_DEPRECATED, + WARNINGS, + WHERE_CLAUSES_OBJECT_SAFETY, + WRITES_THROUGH_IMMUTABLE_POINTER, + // tidy-alphabetical-end + ] +} + declare_lint! { /// The `forbidden_lint_groups` lint detects violations of /// `forbid` applied to a lint group. Due to a bug in the compiler, @@ -3135,7 +3264,7 @@ declare_lint! { /// ### Example /// /// ```text - /// rustc --check-cfg 'names()' + /// rustc --check-cfg 'cfg()' /// ``` /// /// ```rust,ignore (needs command line option) @@ -3146,7 +3275,7 @@ declare_lint! { /// This will produce: /// /// ```text - /// warning: unknown condition name used + /// warning: unexpected `cfg` condition name: `widnows` /// --> lint_example.rs:1:7 /// | /// 1 | #[cfg(widnows)] @@ -3157,9 +3286,10 @@ declare_lint! { /// /// ### Explanation /// - /// This lint is only active when a `--check-cfg='names(...)'` option has been passed - /// to the compiler and triggers whenever an unknown condition name or value is used. - /// The known condition include names or values passed in `--check-cfg`, `--cfg`, and some + /// This lint is only active when `--check-cfg` arguments are being passed + /// to the compiler and triggers whenever an unexpected condition name or value is used. + /// + /// The known condition include names or values passed in `--check-cfg`, and some /// well-knows names and values built into the compiler. pub UNEXPECTED_CFGS, Warn, @@ -3348,134 +3478,6 @@ declare_lint! { "name introduced by a private item shadows a name introduced by a public glob re-export", } -declare_lint_pass! { - /// Does nothing as a lint pass, but registers some `Lint`s - /// that are used by other parts of the compiler. - HardwiredLints => [ - // tidy-alphabetical-start - ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, - AMBIGUOUS_ASSOCIATED_ITEMS, - AMBIGUOUS_GLOB_IMPORTS, - AMBIGUOUS_GLOB_REEXPORTS, - ARITHMETIC_OVERFLOW, - ASM_SUB_REGISTER, - BAD_ASM_STYLE, - BARE_TRAIT_OBJECTS, - BINDINGS_WITH_VARIANT_NAME, - BREAK_WITH_LABEL_AND_LOOP, - BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, - CENUM_IMPL_DROP_CAST, - COHERENCE_LEAK_CHECK, - COINDUCTIVE_OVERLAP_IN_COHERENCE, - CONFLICTING_REPR_HINTS, - CONST_EVALUATABLE_UNCHECKED, - CONST_ITEM_MUTATION, - CONST_PATTERNS_WITHOUT_PARTIAL_EQ, - DEAD_CODE, - DEPRECATED, - DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, - DEPRECATED_IN_FUTURE, - DEPRECATED_WHERE_CLAUSE_LOCATION, - DUPLICATE_MACRO_ATTRIBUTES, - ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, - ELIDED_LIFETIMES_IN_PATHS, - EXPORTED_PRIVATE_DEPENDENCIES, - FFI_UNWIND_CALLS, - FORBIDDEN_LINT_GROUPS, - FUNCTION_ITEM_REFERENCES, - FUZZY_PROVENANCE_CASTS, - HIDDEN_GLOB_REEXPORTS, - ILL_FORMED_ATTRIBUTE_INPUT, - ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, - IMPLIED_BOUNDS_ENTAILMENT, - INCOMPLETE_INCLUDE, - INDIRECT_STRUCTURAL_MATCH, - INEFFECTIVE_UNSTABLE_TRAIT_IMPL, - INLINE_NO_SANITIZE, - INVALID_DOC_ATTRIBUTES, - INVALID_MACRO_EXPORT_ARGUMENTS, - INVALID_TYPE_PARAM_DEFAULT, - IRREFUTABLE_LET_PATTERNS, - LARGE_ASSIGNMENTS, - LATE_BOUND_LIFETIME_ARGUMENTS, - LEGACY_DERIVE_HELPERS, - LONG_RUNNING_CONST_EVAL, - LOSSY_PROVENANCE_CASTS, - MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, - MACRO_USE_EXTERN_CRATE, - META_VARIABLE_MISUSE, - MISSING_ABI, - MISSING_FRAGMENT_SPECIFIER, - MUST_NOT_SUSPEND, - NAMED_ARGUMENTS_USED_POSITIONALLY, - NON_EXHAUSTIVE_OMITTED_PATTERNS, - NONTRIVIAL_STRUCTURAL_MATCH, - ORDER_DEPENDENT_TRAIT_OBJECTS, - OVERLAPPING_RANGE_ENDPOINTS, - PATTERNS_IN_FNS_WITHOUT_BODY, - POINTER_STRUCTURAL_MATCH, - PRIVATE_BOUNDS, - PRIVATE_INTERFACES, - PROC_MACRO_BACK_COMPAT, - PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, - PUB_USE_OF_PRIVATE_EXTERN_CRATE, - REFINING_IMPL_TRAIT, - RENAMED_AND_REMOVED_LINTS, - REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, - RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, - RUST_2021_INCOMPATIBLE_OR_PATTERNS, - RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, - RUST_2021_PRELUDE_COLLISIONS, - SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, - SINGLE_USE_LIFETIMES, - SOFT_UNSTABLE, - STABLE_FEATURES, - SUSPICIOUS_AUTO_TRAIT_IMPLS, - TEST_UNSTABLE_LINT, - TEXT_DIRECTION_CODEPOINT_IN_COMMENT, - TRIVIAL_CASTS, - TRIVIAL_NUMERIC_CASTS, - TYVAR_BEHIND_RAW_POINTER, - UNCONDITIONAL_PANIC, - UNCONDITIONAL_RECURSION, - UNDEFINED_NAKED_FUNCTION_ABI, - UNEXPECTED_CFGS, - UNFULFILLED_LINT_EXPECTATIONS, - UNINHABITED_STATIC, - UNKNOWN_CRATE_TYPES, - UNKNOWN_LINTS, - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - UNNAMEABLE_TEST_ITEMS, - UNNAMEABLE_TYPES, - UNREACHABLE_CODE, - UNREACHABLE_PATTERNS, - UNSAFE_OP_IN_UNSAFE_FN, - UNSTABLE_NAME_COLLISIONS, - UNSTABLE_SYNTAX_PRE_EXPANSION, - UNSUPPORTED_CALLING_CONVENTIONS, - UNUSED_ASSIGNMENTS, - UNUSED_ASSOCIATED_TYPE_BOUNDS, - UNUSED_ATTRIBUTES, - UNUSED_CRATE_DEPENDENCIES, - UNUSED_EXTERN_CRATES, - UNUSED_FEATURES, - UNUSED_IMPORTS, - UNUSED_LABELS, - UNUSED_LIFETIMES, - UNUSED_MACRO_RULES, - UNUSED_MACROS, - UNUSED_MUT, - UNUSED_QUALIFICATIONS, - UNUSED_TUPLE_STRUCT_FIELDS, - UNUSED_UNSAFE, - UNUSED_VARIABLES, - USELESS_DEPRECATED, - WARNINGS, - WHERE_CLAUSES_OBJECT_SAFETY, - // tidy-alphabetical-end - ] -} - declare_lint! { /// The `long_running_const_eval` lint is emitted when const /// eval is running for a long time to ensure rustc terminates @@ -4620,3 +4622,37 @@ declare_lint! { reference: "issue #115010 <https://github.com/rust-lang/rust/issues/115010>", }; } + +declare_lint! { + /// The `writes_through_immutable_pointer` lint detects writes through pointers derived from + /// shared references. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![feature(const_mut_refs)] + /// const WRITE_AFTER_CAST: () = unsafe { + /// let mut x = 0; + /// let ptr = &x as *const i32 as *mut i32; + /// *ptr = 0; + /// }; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Shared references are immutable (when there is no `UnsafeCell` involved), + /// and writing through them or through pointers derived from them is Undefined Behavior. + /// The compiler recently learned to detect such Undefined Behavior during compile-time + /// evaluation, and in the future this will raise a hard error. + /// + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub WRITES_THROUGH_IMMUTABLE_POINTER, + Warn, + "shared references are immutable, and pointers derived from them must not be written to", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, + reference: "issue #X <https://github.com/rust-lang/rust/issues/X>", + }; +} diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index ed1e8771323..4b0c1229da1 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -102,7 +102,7 @@ fn output(cmd: &mut Command) -> String { fn main() { for component in REQUIRED_COMPONENTS.iter().chain(OPTIONAL_COMPONENTS.iter()) { - println!("cargo:rustc-check-cfg=values(llvm_component,\"{component}\")"); + println!("cargo:rustc-check-cfg=cfg(llvm_component,values(\"{component}\"))"); } if tracked_env_var_os("RUST_CHECK").is_some() { diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index 834120efa67..5bfffc5d911 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -1,3 +1,5 @@ +#include "SuppressLLVMWarnings.h" + #include "llvm-c/BitReader.h" #include "llvm-c/Core.h" #include "llvm-c/Object.h" diff --git a/compiler/rustc_llvm/llvm-wrapper/Linker.cpp b/compiler/rustc_llvm/llvm-wrapper/Linker.cpp index 8766e96f086..533df0f75f8 100644 --- a/compiler/rustc_llvm/llvm-wrapper/Linker.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/Linker.cpp @@ -1,3 +1,4 @@ +#include "SuppressLLVMWarnings.h" #include "llvm/Linker/Linker.h" #include "LLVMWrapper.h" diff --git a/compiler/rustc_llvm/llvm-wrapper/SuppressLLVMWarnings.h b/compiler/rustc_llvm/llvm-wrapper/SuppressLLVMWarnings.h new file mode 100644 index 00000000000..56964e4eaa7 --- /dev/null +++ b/compiler/rustc_llvm/llvm-wrapper/SuppressLLVMWarnings.h @@ -0,0 +1,13 @@ +#ifndef _rustc_llvm_SuppressLLVMWarnings_h +#define _rustc_llvm_SuppressLLVMWarnings_h + +// LLVM currently generates many warnings when compiled using MSVC. These warnings make it difficult +// to diagnose real problems when working on C++ code, so we suppress them. + +#ifdef _MSC_VER +#pragma warning(disable:4530) // C++ exception handler used, but unwind semantics are not enabled. +#pragma warning(disable:4624) // 'xxx': destructor was implicitly defined as deleted +#pragma warning(disable:4244) // conversion from 'xxx' to 'yyy', possible loss of data +#endif + +#endif // _rustc_llvm_SuppressLLVMWarnings_h diff --git a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp index bf00d11edf6..91f84692df8 100644 --- a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp @@ -7,6 +7,7 @@ // * https://github.com/llvm/llvm-project/blob/8ef3e895ad8ab1724e2b87cabad1dacdc7a397a3/llvm/include/llvm/Object/ArchiveWriter.h // * https://github.com/llvm/llvm-project/blob/8ef3e895ad8ab1724e2b87cabad1dacdc7a397a3/llvm/lib/Object/ArchiveWriter.cpp +#include "SuppressLLVMWarnings.h" #include "llvm/ADT/SmallString.h" #include "llvm/IR/LLVMContext.h" #include "llvm/Object/ObjectFile.h" diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 765bb7a362e..ffb2375a734 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -658,8 +658,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let debugger_visualizers = stat!("debugger-visualizers", || self.encode_debugger_visualizers()); - // Encode exported symbols info. This is prefetched in `encode_metadata` so we encode - // this as late as possible to give the prefetching as much time as possible to complete. + // Encode exported symbols info. This is prefetched in `encode_metadata`. let exported_symbols = stat!("exported-symbols", || { self.encode_exported_symbols(tcx.exported_symbols(LOCAL_CRATE)) }); @@ -2193,21 +2192,13 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) { // there's no need to do dep-graph tracking for any of it. tcx.dep_graph.assert_ignored(); - join( - || encode_metadata_impl(tcx, path), - || { - if tcx.sess.threads() == 1 { - return; - } - // Prefetch some queries used by metadata encoding. - // This is not necessary for correctness, but is only done for performance reasons. - // It can be removed if it turns out to cause trouble or be detrimental to performance. - join(|| prefetch_mir(tcx), || tcx.exported_symbols(LOCAL_CRATE)); - }, - ); -} + if tcx.sess.threads() != 1 { + // Prefetch some queries used by metadata encoding. + // This is not necessary for correctness, but is only done for performance reasons. + // It can be removed if it turns out to cause trouble or be detrimental to performance. + join(|| prefetch_mir(tcx), || tcx.exported_symbols(LOCAL_CRATE)); + } -fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) { let mut encoder = opaque::FileEncoder::new(path) .unwrap_or_else(|err| tcx.sess.emit_fatal(FailCreateFileEncoder { err })); encoder.emit_raw_bytes(METADATA_HEADER); diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index e30b6b203d7..59ce0a14b2a 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -35,7 +35,12 @@ pub enum SymbolExportKind { pub struct SymbolExportInfo { pub level: SymbolExportLevel, pub kind: SymbolExportKind, + /// Used to mark these symbols not to be internalized by LTO. These symbols + /// are also added to `symbols.o` to avoid circular dependencies when linking. pub used: bool, + /// Also used to mark these symbols not to be internalized by LTO. But will + /// not be added to `symbols.o`. Currently there are only builtin functions. + pub used_compiler: bool, } #[derive(Eq, PartialEq, Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)] diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index d38df1b7201..26138157b74 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -75,7 +75,7 @@ static_assert_size!(ConstValue<'_>, 24); impl<'tcx> ConstValue<'tcx> { #[inline] - pub fn try_to_scalar(&self) -> Option<Scalar<AllocId>> { + pub fn try_to_scalar(&self) -> Option<Scalar> { match *self { ConstValue::Indirect { .. } | ConstValue::Slice { .. } | ConstValue::ZeroSized => None, ConstValue::Scalar(val) => Some(val), @@ -161,8 +161,8 @@ impl<'tcx> ConstValue<'tcx> { return Some(&[]); } // Non-empty slice, must have memory. We know this is a relative pointer. - let (inner_alloc_id, offset) = ptr.into_parts(); - let data = tcx.global_alloc(inner_alloc_id?).unwrap_memory(); + let (inner_prov, offset) = ptr.into_parts(); + let data = tcx.global_alloc(inner_prov?.alloc_id()).unwrap_memory(); (data, offset.bytes(), offset.bytes() + len) } }; diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 09e56b2e4a8..2a9e0847f43 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -18,9 +18,9 @@ use rustc_span::DUMMY_SP; use rustc_target::abi::{Align, HasDataLayout, Size}; use super::{ - read_target_uint, write_target_uint, AllocId, BadBytesAccess, InterpError, InterpResult, - Pointer, PointerArithmetic, Provenance, ResourceExhaustionInfo, Scalar, ScalarSizeMismatch, - UndefinedBehaviorInfo, UnsupportedOpInfo, + read_target_uint, write_target_uint, AllocId, BadBytesAccess, CtfeProvenance, InterpError, + InterpResult, Pointer, PointerArithmetic, Provenance, ResourceExhaustionInfo, Scalar, + ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, }; use crate::ty; use init_mask::*; @@ -63,7 +63,7 @@ impl AllocBytes for Box<[u8]> { // hashed. (see the `Hash` impl below for more details), so the impl is not derived. #[derive(Clone, Eq, PartialEq, TyEncodable, TyDecodable)] #[derive(HashStable)] -pub struct Allocation<Prov: Provenance = AllocId, Extra = (), Bytes = Box<[u8]>> { +pub struct Allocation<Prov: Provenance = CtfeProvenance, Extra = (), Bytes = Box<[u8]>> { /// The actual bytes of the allocation. /// Note that the bytes of a pointer represent the offset of the pointer. bytes: Bytes, @@ -336,14 +336,14 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> { } } -impl<Bytes: AllocBytes> Allocation<AllocId, (), Bytes> { - /// Adjust allocation from the ones in tcx to a custom Machine instance - /// with a different Provenance and Extra type. +impl<Bytes: AllocBytes> Allocation<CtfeProvenance, (), Bytes> { + /// Adjust allocation from the ones in `tcx` to a custom Machine instance + /// with a different `Provenance` and `Extra` type. pub fn adjust_from_tcx<Prov: Provenance, Extra, Err>( self, cx: &impl HasDataLayout, extra: Extra, - mut adjust_ptr: impl FnMut(Pointer<AllocId>) -> Result<Pointer<Prov>, Err>, + mut adjust_ptr: impl FnMut(Pointer<CtfeProvenance>) -> Result<Pointer<Prov>, Err>, ) -> Result<Allocation<Prov, Extra, Bytes>, Err> { let mut bytes = self.bytes; // Adjust provenance of pointers stored in this allocation. diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs index d504af6b7ea..9459af490e3 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -6,14 +6,14 @@ use std::cmp; use rustc_data_structures::sorted_map::SortedMap; use rustc_target::abi::{HasDataLayout, Size}; -use super::{alloc_range, AllocError, AllocId, AllocRange, AllocResult, Provenance}; +use super::{alloc_range, AllocError, AllocRange, AllocResult, CtfeProvenance, Provenance}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; /// Stores the provenance information of pointers stored in memory. #[derive(Clone, PartialEq, Eq, Hash, Debug)] #[derive(HashStable)] -pub struct ProvenanceMap<Prov = AllocId> { - /// Provenance in this map applies from the given offset for an entire pointer-size worth of +pub struct ProvenanceMap<Prov = CtfeProvenance> { + /// `Provenance` in this map applies from the given offset for an entire pointer-size worth of /// bytes. Two entries in this map are always at least a pointer size apart. ptrs: SortedMap<Size, Prov>, /// Provenance in this map only applies to the given single byte. @@ -22,18 +22,19 @@ pub struct ProvenanceMap<Prov = AllocId> { bytes: Option<Box<SortedMap<Size, Prov>>>, } +// These impls are generic over `Prov` since `CtfeProvenance` is only decodable/encodable +// for some particular `D`/`S`. impl<D: Decoder, Prov: Provenance + Decodable<D>> Decodable<D> for ProvenanceMap<Prov> { fn decode(d: &mut D) -> Self { - assert!(!Prov::OFFSET_IS_ADDR); // only `AllocId` is ever serialized + assert!(!Prov::OFFSET_IS_ADDR); // only `CtfeProvenance` is ever serialized Self { ptrs: Decodable::decode(d), bytes: None } } } - impl<S: Encoder, Prov: Provenance + Encodable<S>> Encodable<S> for ProvenanceMap<Prov> { fn encode(&self, s: &mut S) { let Self { ptrs, bytes } = self; - assert!(!Prov::OFFSET_IS_ADDR); // only `AllocId` is ever serialized - debug_assert!(bytes.is_none()); + assert!(!Prov::OFFSET_IS_ADDR); // only `CtfeProvenance` is ever serialized + debug_assert!(bytes.is_none()); // without `OFFSET_IS_ADDR`, this is always empty ptrs.encode(s) } } @@ -54,10 +55,10 @@ impl ProvenanceMap { /// Give access to the ptr-sized provenances (which can also be thought of as relocations, and /// indeed that is how codegen treats them). /// - /// Only exposed with `AllocId` provenance, since it panics if there is bytewise provenance. + /// Only exposed with `CtfeProvenance` provenance, since it panics if there is bytewise provenance. #[inline] - pub fn ptrs(&self) -> &SortedMap<Size, AllocId> { - debug_assert!(self.bytes.is_none()); // `AllocId::OFFSET_IS_ADDR` is false so this cannot fail + pub fn ptrs(&self) -> &SortedMap<Size, CtfeProvenance> { + debug_assert!(self.bytes.is_none()); // `CtfeProvenance::OFFSET_IS_ADDR` is false so this cannot fail &self.ptrs } } diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 44b22e2d383..41386793987 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -290,7 +290,7 @@ macro_rules! impl_into_diagnostic_arg_through_debug { // These types have nice `Debug` output so we can just use them in diagnostics. impl_into_diagnostic_arg_through_debug! { AllocId, - Pointer, + Pointer<AllocId>, AllocRange, } @@ -323,7 +323,7 @@ pub enum UndefinedBehaviorInfo<'tcx> { /// Invalid metadata in a wide pointer InvalidMeta(InvalidMetaKind), /// Reading a C string that does not end within its allocation. - UnterminatedCString(Pointer), + UnterminatedCString(Pointer<AllocId>), /// Using a pointer after it got freed. PointerUseAfterFree(AllocId, CheckInAllocMsg), /// Used a pointer outside the bounds it is valid for. @@ -350,11 +350,11 @@ pub enum UndefinedBehaviorInfo<'tcx> { /// Using a non-character `u32` as character. InvalidChar(u32), /// The tag of an enum does not encode an actual discriminant. - InvalidTag(Scalar), + InvalidTag(Scalar<AllocId>), /// Using a pointer-not-to-a-function as function pointer. - InvalidFunctionPointer(Pointer), + InvalidFunctionPointer(Pointer<AllocId>), /// Using a pointer-not-to-a-vtable as vtable pointer. - InvalidVTablePointer(Pointer), + InvalidVTablePointer(Pointer<AllocId>), /// Using a string that is not valid UTF-8, InvalidStr(std::str::Utf8Error), /// Using uninitialized data where it is not allowed. diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index e5f891fcc91..2db56008553 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -157,7 +157,7 @@ pub use self::allocation::{ InitChunk, InitChunkIter, }; -pub use self::pointer::{Pointer, PointerArithmetic, Provenance}; +pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance}; /// Uniquely identifies one of the following: /// - A constant diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index 1c9ce1cb130..6893387736a 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -3,7 +3,7 @@ use super::{AllocId, InterpResult}; use rustc_macros::HashStable; use rustc_target::abi::{HasDataLayout, Size}; -use std::fmt; +use std::{fmt, num::NonZeroU64}; //////////////////////////////////////////////////////////////////////////////// // Pointer arithmetic @@ -114,22 +114,7 @@ pub trait Provenance: Copy + fmt::Debug + 'static { const OFFSET_IS_ADDR: bool; /// Determines how a pointer should be printed. - /// - /// Default impl is only good for when `OFFSET_IS_ADDR == true`. - fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result - where - Self: Sized, - { - assert!(Self::OFFSET_IS_ADDR); - let (prov, addr) = ptr.into_parts(); // address is absolute - write!(f, "{:#x}", addr.bytes())?; - if f.alternate() { - write!(f, "{prov:#?}")?; - } else { - write!(f, "{prov:?}")?; - } - Ok(()) - } + fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result; /// If `OFFSET_IS_ADDR == false`, provenance must always be able to /// identify the allocation this ptr points to (i.e., this must return `Some`). @@ -141,6 +126,80 @@ pub trait Provenance: Copy + fmt::Debug + 'static { fn join(left: Option<Self>, right: Option<Self>) -> Option<Self>; } +/// The type of provenance in the compile-time interpreter. +/// This is a packed representation of an `AllocId` and an `immutable: bool`. +#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct CtfeProvenance(NonZeroU64); + +impl From<AllocId> for CtfeProvenance { + fn from(value: AllocId) -> Self { + let prov = CtfeProvenance(value.0); + assert!(!prov.immutable(), "`AllocId` with the highest bit set cannot be used in CTFE"); + prov + } +} + +impl fmt::Debug for CtfeProvenance { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.alloc_id(), f)?; // propagates `alternate` flag + if self.immutable() { + write!(f, "<imm>")?; + } + Ok(()) + } +} + +const IMMUTABLE_MASK: u64 = 1 << 63; // the highest bit + +impl CtfeProvenance { + /// Returns the `AllocId` of this provenance. + #[inline(always)] + pub fn alloc_id(self) -> AllocId { + AllocId(NonZeroU64::new(self.0.get() & !IMMUTABLE_MASK).unwrap()) + } + + /// Returns whether this provenance is immutable. + #[inline] + pub fn immutable(self) -> bool { + self.0.get() & IMMUTABLE_MASK != 0 + } + + /// Returns an immutable version of this provenance. + #[inline] + pub fn as_immutable(self) -> Self { + CtfeProvenance(self.0 | IMMUTABLE_MASK) + } +} + +impl Provenance for CtfeProvenance { + // With the `AllocId` as provenance, the `offset` is interpreted *relative to the allocation*, + // so ptr-to-int casts are not possible (since we do not know the global physical offset). + const OFFSET_IS_ADDR: bool = false; + + fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Print AllocId. + fmt::Debug::fmt(&ptr.provenance.alloc_id(), f)?; // propagates `alternate` flag + // Print offset only if it is non-zero. + if ptr.offset.bytes() > 0 { + write!(f, "+{:#x}", ptr.offset.bytes())?; + } + // Print immutable status. + if ptr.provenance.immutable() { + write!(f, "<imm>")?; + } + Ok(()) + } + + fn get_alloc_id(self) -> Option<AllocId> { + Some(self.alloc_id()) + } + + fn join(_left: Option<Self>, _right: Option<Self>) -> Option<Self> { + panic!("merging provenance is not supported when `OFFSET_IS_ADDR` is false") + } +} + +// We also need this impl so that one can debug-print `Pointer<AllocId>` impl Provenance for AllocId { // With the `AllocId` as provenance, the `offset` is interpreted *relative to the allocation*, // so ptr-to-int casts are not possible (since we do not know the global physical offset). @@ -174,7 +233,7 @@ impl Provenance for AllocId { /// Pointers are "tagged" with provenance information; typically the `AllocId` they belong to. #[derive(Copy, Clone, Eq, PartialEq, TyEncodable, TyDecodable, Hash)] #[derive(HashStable)] -pub struct Pointer<Prov = AllocId> { +pub struct Pointer<Prov = CtfeProvenance> { pub(super) offset: Size, // kept private to avoid accidental misinterpretation (meaning depends on `Prov` type) pub provenance: Prov, } @@ -182,7 +241,7 @@ pub struct Pointer<Prov = AllocId> { static_assert_size!(Pointer, 16); // `Option<Prov>` pointers are also passed around quite a bit // (but not stored in permanent machine state). -static_assert_size!(Pointer<Option<AllocId>>, 16); +static_assert_size!(Pointer<Option<CtfeProvenance>>, 16); // We want the `Debug` output to be readable as it is used by `derive(Debug)` for // all the Miri types. @@ -215,7 +274,7 @@ impl<Prov: Provenance> fmt::Display for Pointer<Option<Prov>> { impl From<AllocId> for Pointer { #[inline(always)] fn from(alloc_id: AllocId) -> Self { - Pointer::new(alloc_id, Size::ZERO) + Pointer::new(alloc_id.into(), Size::ZERO) } } diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 0d548f88636..5ecff04f3ae 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -11,7 +11,10 @@ use rustc_target::abi::{HasDataLayout, Size}; use crate::ty::ScalarInt; -use super::{AllocId, InterpResult, Pointer, PointerArithmetic, Provenance, ScalarSizeMismatch}; +use super::{ + AllocId, CtfeProvenance, InterpResult, Pointer, PointerArithmetic, Provenance, + ScalarSizeMismatch, +}; /// A `Scalar` represents an immediate, primitive value existing outside of a /// `memory::Allocation`. It is in many ways like a small chunk of an `Allocation`, up to 16 bytes in @@ -22,7 +25,7 @@ use super::{AllocId, InterpResult, Pointer, PointerArithmetic, Provenance, Scala /// Do *not* match on a `Scalar`! Use the various `to_*` methods instead. #[derive(Clone, Copy, Eq, PartialEq, TyEncodable, TyDecodable, Hash)] #[derive(HashStable)] -pub enum Scalar<Prov = AllocId> { +pub enum Scalar<Prov = CtfeProvenance> { /// The raw bytes of a simple value. Int(ScalarInt), @@ -267,6 +270,9 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> { /// Will perform ptr-to-int casts if needed and possible. /// If that fails, we know the offset is relative, so we return an "erased" Scalar /// (which is useful for error messages but not much else). + /// + /// The error type is `AllocId`, not `CtfeProvenance`, since `AllocId` is the "minimal" + /// component all provenance types must have. #[inline] pub fn try_to_int(self) -> Result<ScalarInt, Scalar<AllocId>> { match self { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 1974a35cb85..bfaa0d88fc0 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1337,13 +1337,13 @@ pub fn write_allocations<'tcx>( fn alloc_ids_from_alloc( alloc: ConstAllocation<'_>, ) -> impl DoubleEndedIterator<Item = AllocId> + '_ { - alloc.inner().provenance().ptrs().values().copied() + alloc.inner().provenance().ptrs().values().map(|p| p.alloc_id()) } fn alloc_ids_from_const_val(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ { match val { ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => { - Either::Left(std::iter::once(ptr.provenance)) + Either::Left(std::iter::once(ptr.provenance.alloc_id())) } ConstValue::Scalar(interpret::Scalar::Int { .. }) => Either::Right(std::iter::empty()), ConstValue::ZeroSized => Either::Right(std::iter::empty()), diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index be35a54be58..f929a5cec25 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -381,7 +381,7 @@ impl<'tcx> Operand<'tcx> { impl<'tcx> ConstOperand<'tcx> { pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> { match self.const_.try_to_scalar() { - Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) { + Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance.alloc_id()) { GlobalAlloc::Static(def_id) => { assert!(!tcx.is_thread_local_static(def_id)); Some(def_id) diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index cdde6a596a8..b9200f1abf1 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -264,6 +264,7 @@ trivial! { rustc_middle::middle::stability::DeprecationEntry, rustc_middle::mir::ConstQualifs, rustc_middle::mir::interpret::AllocId, + rustc_middle::mir::interpret::CtfeProvenance, rustc_middle::mir::interpret::ErrorHandled, rustc_middle::mir::interpret::LitToConstError, rustc_middle::thir::ExprId, diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index f33421bbaa6..96ed1a4d0be 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -180,8 +180,8 @@ pub enum SelectionCandidate<'tcx> { /// /// The evaluation results are ordered: /// - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions` -/// implies `EvaluatedToAmbig` implies `EvaluatedToUnknown` -/// - `EvaluatedToErr` implies `EvaluatedToRecur` +/// implies `EvaluatedToAmbig` implies `EvaluatedToAmbigStackDependent` +/// - `EvaluatedToErr` implies `EvaluatedToErrStackDependent` /// - the "union" of evaluation results is equal to their maximum - /// all the "potential success" candidates can potentially succeed, /// so they are noops when unioned with a definite error, and within @@ -199,7 +199,7 @@ pub enum EvaluationResult { /// Evaluation is known to be ambiguous -- it *might* hold for some /// assignment of inference variables, but it might not. /// - /// While this has the same meaning as `EvaluatedToUnknown` -- we can't + /// While this has the same meaning as `EvaluatedToAmbigStackDependent` -- we can't /// know whether this obligation holds or not -- it is the result we /// would get with an empty stack, and therefore is cacheable. EvaluatedToAmbig, @@ -207,8 +207,8 @@ pub enum EvaluationResult { /// variables. We are somewhat imprecise there, so we don't actually /// know the real result. /// - /// This can't be trivially cached for the same reason as `EvaluatedToRecur`. - EvaluatedToUnknown, + /// This can't be trivially cached for the same reason as `EvaluatedToErrStackDependent`. + EvaluatedToAmbigStackDependent, /// Evaluation failed because we encountered an obligation we are already /// trying to prove on this branch. /// @@ -247,12 +247,12 @@ pub enum EvaluationResult { /// does not hold, because of the bound (which can indeed be satisfied /// by `SomeUnsizedType` from another crate). // - // FIXME: when an `EvaluatedToRecur` goes past its parent root, we + // FIXME: when an `EvaluatedToErrStackDependent` goes past its parent root, we // ought to convert it to an `EvaluatedToErr`, because we know // there definitely isn't a proof tree for that obligation. Not // doing so is still sound -- there isn't any proof tree, so the // branch still can't be a part of a minimal one -- but does not re-enable caching. - EvaluatedToRecur, + EvaluatedToErrStackDependent, /// Evaluation failed. EvaluatedToErr, } @@ -276,15 +276,15 @@ impl EvaluationResult { | EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig - | EvaluatedToUnknown => true, + | EvaluatedToAmbigStackDependent => true, - EvaluatedToErr | EvaluatedToRecur => false, + EvaluatedToErr | EvaluatedToErrStackDependent => false, } } pub fn is_stack_dependent(self) -> bool { match self { - EvaluatedToUnknown | EvaluatedToRecur => true, + EvaluatedToAmbigStackDependent | EvaluatedToErrStackDependent => true, EvaluatedToOkModuloOpaqueTypes | EvaluatedToOk diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 81cf41889d4..69ae05ca820 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -8,6 +8,7 @@ use crate::arena::ArenaAllocatable; use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; +use crate::mir::interpret::CtfeProvenance; use crate::mir::{ self, interpret::{AllocId, ConstAllocation}, @@ -164,6 +165,13 @@ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for AllocId { } } +impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for CtfeProvenance { + fn encode(&self, e: &mut E) { + self.alloc_id().encode(e); + self.immutable().encode(e); + } +} + impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::ParamEnv<'tcx> { fn encode(&self, e: &mut E) { self.caller_bounds().encode(e); @@ -295,6 +303,15 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for AllocId { } } +impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for CtfeProvenance { + fn decode(decoder: &mut D) -> Self { + let alloc_id: AllocId = Decodable::decode(decoder); + let prov = CtfeProvenance::from(alloc_id); + let immutable: bool = Decodable::decode(decoder); + if immutable { prov.as_immutable() } else { prov } + } +} + impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::SymbolName<'tcx> { fn decode(decoder: &mut D) -> Self { ty::SymbolName::new(decoder.interner(), decoder.read_str()) diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index a216cc28c8a..e48840fac20 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -1,5 +1,5 @@ use crate::middle::resolve_bound_vars as rbv; -use crate::mir::interpret::{AllocId, ErrorHandled, LitToConstInput, Scalar}; +use crate::mir::interpret::{ErrorHandled, LitToConstInput, Scalar}; use crate::ty::{self, GenericArgs, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; use rustc_data_structures::intern::Interned; use rustc_error_messages::MultiSpan; @@ -413,7 +413,7 @@ impl<'tcx> Const<'tcx> { } #[inline] - pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> { + pub fn try_to_scalar(self) -> Option<Scalar> { self.try_to_valtree()?.try_to_scalar() } diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index fb7bf78bafe..ffa0e89c473 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -1,5 +1,5 @@ use super::ScalarInt; -use crate::mir::interpret::{AllocId, Scalar}; +use crate::mir::interpret::Scalar; use crate::ty::{self, Ty, TyCtxt}; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; @@ -67,7 +67,7 @@ impl<'tcx> ValTree<'tcx> { Self::Leaf(i) } - pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> { + pub fn try_to_scalar(self) -> Option<Scalar> { self.try_to_scalar_int().map(Scalar::Int) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 8e71327f82e..4a01a24fd61 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2186,7 +2186,7 @@ impl<'tcx> TyCtxt<'tcx> { hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(hir::Impl { generics, .. }), .. - }) if generics.params.iter().any(|p| self.has_attr(p.def_id, sym::rustc_host)) + }) if generics.params.iter().any(|p| matches!(p.kind, hir::GenericParamKind::Const { is_host_effect: true, .. })) ) } diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs index 59c0639fea2..129d947697e 100644 --- a/compiler/rustc_middle/src/ty/impls_ty.rs +++ b/compiler/rustc_middle/src/ty/impls_ty.rs @@ -84,6 +84,14 @@ impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::AllocId { } } +// CtfeProvenance is an AllocId and a bool. +impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::CtfeProvenance { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + self.alloc_id().hash_stable(hcx, hasher); + self.immutable().hash_stable(hcx, hasher); + } +} + impl<'a> ToStableHashKey<StableHashingContext<'a>> for region::Scope { type KeyType = region::Scope; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 9feda4d205e..77196486ac1 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -98,9 +98,8 @@ pub use self::sty::{ CoroutineArgs, CoroutineArgsParts, EarlyParamRegion, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, GenSig, InlineConstArgs, InlineConstArgsParts, LateParamRegion, ParamConst, ParamTy, PolyExistentialPredicate, - PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, - PredicateKind, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, UpvarArgs, - VarianceDiagInfo, + PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyTraitRef, PredicateKind, + Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo, }; pub use self::trait_def::TraitDef; pub use self::typeck_results::{ @@ -2614,9 +2613,7 @@ pub struct SymbolName<'tcx> { impl<'tcx> SymbolName<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, name: &str) -> SymbolName<'tcx> { - SymbolName { - name: unsafe { str::from_utf8_unchecked(tcx.arena.alloc_slice(name.as_bytes())) }, - } + SymbolName { name: tcx.arena.alloc_str(name) } } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 25423348638..1592d852bc7 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1410,14 +1410,14 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ) -> Result<(), PrintError> { define_scoped_cx!(self); - let (alloc_id, offset) = ptr.into_parts(); + let (prov, offset) = ptr.into_parts(); 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(alloc_id) { + match self.tcx().try_get_global_alloc(prov.alloc_id()) { Some(GlobalAlloc::Memory(alloc)) => { let len = int.assert_bits(self.tcx().data_layout.pointer_size); let range = @@ -1447,7 +1447,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // FIXME: We should probably have a helper method to share code with the "Byte strings" // printing above (which also has to handle pointers to all sorts of things). if let Some(GlobalAlloc::Function(instance)) = - self.tcx().try_get_global_alloc(alloc_id) + self.tcx().try_get_global_alloc(prov.alloc_id()) { self.typed_value( |this| this.print_value_path(instance.def_id(), instance.args), @@ -2641,6 +2641,23 @@ impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> { } /// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only +/// the trait path, and additionally tries to "sugar" `Fn(...)` trait bounds. +#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)] +pub struct TraitRefPrintSugared<'tcx>(ty::TraitRef<'tcx>); + +impl<'tcx> rustc_errors::IntoDiagnosticArg for TraitRefPrintSugared<'tcx> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + +impl<'tcx> fmt::Debug for TraitRefPrintSugared<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + +/// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only /// the trait name. That is, it will print `Trait` instead of /// `<T as Trait<U>>`. #[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)] @@ -2657,6 +2674,10 @@ impl<'tcx> ty::TraitRef<'tcx> { TraitRefPrintOnlyTraitPath(self) } + pub fn print_trait_sugared(self) -> TraitRefPrintSugared<'tcx> { + TraitRefPrintSugared(self) + } + pub fn print_only_trait_name(self) -> TraitRefPrintOnlyTraitName<'tcx> { TraitRefPrintOnlyTraitName(self) } @@ -2666,6 +2687,10 @@ impl<'tcx> ty::Binder<'tcx, ty::TraitRef<'tcx>> { pub fn print_only_trait_path(self) -> ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>> { self.map_bound(|tr| tr.print_only_trait_path()) } + + pub fn print_trait_sugared(self) -> ty::Binder<'tcx, TraitRefPrintSugared<'tcx>> { + self.map_bound(|tr| tr.print_trait_sugared()) + } } #[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)] @@ -2745,6 +2770,7 @@ forward_display_to_print! { ty::PolyExistentialTraitRef<'tcx>, ty::Binder<'tcx, ty::TraitRef<'tcx>>, ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + ty::Binder<'tcx, TraitRefPrintSugared<'tcx>>, ty::Binder<'tcx, ty::FnSig<'tcx>>, ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>>, @@ -2844,6 +2870,24 @@ define_print_and_forward_display! { p!(print_def_path(self.0.def_id, self.0.args)); } + TraitRefPrintSugared<'tcx> { + if !with_no_queries() + && let Some(kind) = cx.tcx().fn_trait_kind_from_def_id(self.0.def_id) + && let ty::Tuple(args) = self.0.args.type_at(1).kind() + { + p!(write("{}", kind.as_str()), "("); + for (i, arg) in args.iter().enumerate() { + if i > 0 { + p!(", "); + } + p!(print(arg)); + } + p!(")"); + } else { + p!(print_def_path(self.0.def_id, self.0.args)); + } + } + TraitRefPrintOnlyTraitName<'tcx> { p!(print_def_path(self.0.def_id, &[])); } @@ -2892,7 +2936,7 @@ define_print_and_forward_display! { if let ty::ImplPolarity::Negative = self.polarity { p!("!"); } - p!(print(self.trait_ref.print_only_trait_path())) + p!(print(self.trait_ref.print_trait_sugared())) } ty::ProjectionPredicate<'tcx> { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 971acda33e2..0f19a2fd822 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -440,8 +440,9 @@ TrivialTypeTraversalAndLiftImpls! { crate::ty::ClosureKind, crate::ty::ParamConst, crate::ty::ParamTy, - interpret::Scalar, interpret::AllocId, + interpret::CtfeProvenance, + interpret::Scalar, rustc_target::abi::Size, } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e10b5706b48..e221b4e8bec 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -468,16 +468,6 @@ impl<'tcx> CoroutineArgs<'tcx> { self.split().return_ty.expect_ty() } - /// Returns the "coroutine signature", which consists of its yield - /// and return types. - /// - /// N.B., some bits of the code prefers to see this wrapped in a - /// binder, but it never contains bound regions. Probably this - /// function should be removed. - pub fn poly_sig(self) -> PolyGenSig<'tcx> { - ty::Binder::dummy(self.sig()) - } - /// Returns the "coroutine signature", which consists of its resume, yield /// and return types. pub fn sig(self) -> GenSig<'tcx> { @@ -1352,8 +1342,6 @@ pub struct GenSig<'tcx> { pub return_ty: Ty<'tcx>, } -pub type PolyGenSig<'tcx> = Binder<'tcx, GenSig<'tcx>>; - /// Signature of a function type, which we have arbitrarily /// decided to use to refer to the input/output types. /// 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 80602713905..b72b9da21b7 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -867,12 +867,6 @@ fn report_non_exhaustive_match<'p, 'tcx>( exhaustively", )); } - if cx.tcx.sess.is_nightly_build() { - err.help(format!( - "add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \ - enable precise `{ty}` matching", - )); - } } else if ty == cx.tcx.types.str_ { err.note("`&str` cannot be matched exhaustively, so a wildcard `_` is necessary"); } else if cx.is_foreign_non_exhaustive_enum(ty) { diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 31114190f07..ddcceeb7ef6 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -326,8 +326,7 @@ impl IntRange { /// `NegInfinity..PosInfinity`. In other words, as far as `IntRange` is concerned, there are /// values before `isize::MIN` and after `usize::MAX`/`isize::MAX`. /// This is to avoid e.g. `0..(u32::MAX as usize)` from being exhaustive on one architecture and - /// not others. See discussions around the `precise_pointer_size_matching` feature for more - /// details. + /// not others. This was decided in <https://github.com/rust-lang/rfcs/pull/2591>. /// /// These infinities affect splitting subtly: it is possible to get `NegInfinity..0` and /// `usize::MAX+1..PosInfinity` in the output. Diagnostics must be careful to handle these @@ -380,7 +379,7 @@ impl IntRange { /// Whether the range denotes the fictitious values before `isize::MIN` or after /// `usize::MAX`/`isize::MAX` (see doc of [`IntRange::split`] for why these exist). pub(crate) fn is_beyond_boundaries<'tcx>(&self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> bool { - ty.is_ptr_sized_integral() && !tcx.features().precise_pointer_size_matching && { + ty.is_ptr_sized_integral() && { // The two invalid ranges are `NegInfinity..isize::MIN` (represented as // `NegInfinity..0`), and `{u,i}size::MAX+1..PosInfinity`. `to_diagnostic_pat_range_bdy` // converts `MAX+1` to `PosInfinity`, and we couldn't have `PosInfinity` in `self.lo` @@ -941,11 +940,8 @@ impl ConstructorSet { } } &ty::Int(ity) => { - let range = if ty.is_ptr_sized_integral() - && !cx.tcx.features().precise_pointer_size_matching - { - // The min/max values of `isize` are not allowed to be observed unless the - // `precise_pointer_size_matching` feature is enabled. + let range = if ty.is_ptr_sized_integral() { + // The min/max values of `isize` are not allowed to be observed. IntRange { lo: NegInfinity, hi: PosInfinity } } else { let bits = Integer::from_int_ty(&cx.tcx, ity).size().bits() as u128; @@ -956,11 +952,8 @@ impl ConstructorSet { Self::Integers { range_1: range, range_2: None } } &ty::Uint(uty) => { - let range = if ty.is_ptr_sized_integral() - && !cx.tcx.features().precise_pointer_size_matching - { - // The max value of `usize` is not allowed to be observed unless the - // `precise_pointer_size_matching` feature is enabled. + let range = if ty.is_ptr_sized_integral() { + // The max value of `usize` is not allowed to be observed. let lo = MaybeInfiniteInt::new_finite(cx.tcx, ty, 0); IntRange { lo, hi: PosInfinity } } else { diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index b96125de95e..d88b33cc973 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -11,6 +11,7 @@ use rustc_middle::mir::visit::{ MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor, }; use rustc_middle::mir::*; +use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::{self, GenericArgs, Instance, ParamEnv, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::{def_id::DefId, Span}; @@ -220,7 +221,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> } fn before_access_global( - _tcx: TyCtxt<'tcx>, + _tcx: TyCtxtAt<'tcx>, _machine: &Self, _alloc_id: AllocId, alloc: ConstAllocation<'tcx>, @@ -240,10 +241,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> } #[inline(always)] - fn expose_ptr( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _ptr: Pointer<AllocId>, - ) -> InterpResult<'tcx> { + fn expose_ptr(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx> { throw_machine_stop_str!("exposing pointers isn't supported in ConstProp") } diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index e0abb5da047..4db0a1db166 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -129,16 +129,14 @@ impl CoverageSpan { /// If the span is part of a macro, and the macro is visible (expands directly to the given /// body_span), returns the macro name symbol. pub fn visible_macro(&self, body_span: Span) -> Option<Symbol> { - if let Some(current_macro) = self.current_macro() - && self - .expn_span - .parent_callsite() - .unwrap_or_else(|| bug!("macro must have a parent")) - .eq_ctxt(body_span) - { - return Some(current_macro); - } - None + let current_macro = self.current_macro()?; + let parent_callsite = self.expn_span.parent_callsite()?; + + // In addition to matching the context of the body span, the parent callsite + // must also be the source callsite, i.e. the parent must have no parent. + let is_visible_macro = + parent_callsite.parent_callsite().is_none() && parent_callsite.eq_ctxt(body_span); + is_visible_macro.then_some(current_macro) } pub fn is_macro_expansion(&self) -> bool { @@ -379,18 +377,22 @@ impl<'a> CoverageSpansGenerator<'a> { return; } - let merged_prefix_len = self.curr_original_span.lo() - curr.span.lo(); - let after_macro_bang = merged_prefix_len + BytePos(visible_macro.as_str().len() as u32 + 1); - if self.curr().span.lo() + after_macro_bang > self.curr().span.hi() { + // The split point is relative to `curr_original_span`, + // because `curr.span` may have been merged with preceding spans. + let split_point_after_macro_bang = self.curr_original_span.lo() + + BytePos(visible_macro.as_str().len() as u32) + + BytePos(1); // add 1 for the `!` + debug_assert!(split_point_after_macro_bang <= curr.span.hi()); + if split_point_after_macro_bang > curr.span.hi() { // Something is wrong with the macro name span; - // return now to avoid emitting malformed mappings. - // FIXME(#117788): Track down why this happens. + // return now to avoid emitting malformed mappings (e.g. #117788). return; } + let mut macro_name_cov = curr.clone(); - self.curr_mut().span = curr.span.with_lo(curr.span.lo() + after_macro_bang); - macro_name_cov.span = - macro_name_cov.span.with_hi(macro_name_cov.span.lo() + after_macro_bang); + macro_name_cov.span = macro_name_cov.span.with_hi(split_point_after_macro_bang); + self.curr_mut().span = curr.span.with_lo(split_point_after_macro_bang); + debug!( " and curr starts a new macro expansion, so add a new span just for \ the macro `{visible_macro}!`, new span={macro_name_cov:?}", diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 21b92e6d77c..e9949ebbc87 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -8,6 +8,7 @@ use rustc_hir::def::DefKind; use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult, Scalar}; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::*; +use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_mir_dataflow::value_analysis::{ @@ -876,7 +877,7 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm } fn before_access_global( - _tcx: TyCtxt<'tcx>, + _tcx: TyCtxtAt<'tcx>, _machine: &Self, _alloc_id: AllocId, alloc: ConstAllocation<'tcx>, diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 3a5270f105a..2358661738a 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use rustc_errors::{ Applicability, DecorateLint, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, - EmissionGuarantee, Handler, IntoDiagnostic, + EmissionGuarantee, ErrorGuaranteed, Handler, IntoDiagnostic, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails}; @@ -62,9 +62,9 @@ pub(crate) struct RequiresUnsafe { // so we need to eagerly translate the label here, which isn't supported by the derive API // We could also exhaustively list out the primary messages for all unsafe violations, // but this would result in a lot of duplication. -impl<'sess, G: EmissionGuarantee> IntoDiagnostic<'sess, G> for RequiresUnsafe { +impl<'sess> IntoDiagnostic<'sess> for RequiresUnsafe { #[track_caller] - fn into_diagnostic(self, handler: &'sess Handler) -> DiagnosticBuilder<'sess, G> { + fn into_diagnostic(self, handler: &'sess Handler) -> DiagnosticBuilder<'sess, ErrorGuaranteed> { let mut diag = handler.struct_diagnostic(fluent::mir_transform_requires_unsafe); diag.code(rustc_errors::DiagnosticId::Error("E0133".to_string())); diag.set_span(self.span); diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 735960f31b3..1a5979ef714 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -388,7 +388,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { self.ecx.copy_op(op, &field_dest, /*allow_transmute*/ false).ok()?; } self.ecx.write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest).ok()?; - self.ecx.alloc_mark_immutable(dest.ptr().provenance.unwrap()).ok()?; + self.ecx + .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id()) + .ok()?; dest.into() } else { return None; @@ -928,7 +930,8 @@ fn op_to_prop_const<'tcx>( } let pointer = mplace.ptr().into_pointer_or_addr().ok()?; - let (alloc_id, offset) = pointer.into_parts(); + let (prov, offset) = pointer.into_parts(); + let alloc_id = prov.alloc_id(); intern_const_alloc_for_constprop(ecx, alloc_id).ok()?; if matches!(ecx.tcx.global_alloc(alloc_id), GlobalAlloc::Memory(_)) { // `alloc_id` may point to a static. Codegen will choke on an `Indirect` with anything diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index b882a038711..3a7cc405ca7 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -385,8 +385,8 @@ fn collect_items_rec<'tcx>( recursion_depth_reset = None; if let Ok(alloc) = tcx.eval_static_initializer(def_id) { - for &id in alloc.inner().provenance().ptrs().values() { - collect_alloc(tcx, id, &mut used_items); + for &prov in alloc.inner().provenance().ptrs().values() { + collect_alloc(tcx, prov.alloc_id(), &mut used_items); } } @@ -1363,9 +1363,9 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt } GlobalAlloc::Memory(alloc) => { trace!("collecting {:?} with {:#?}", alloc_id, alloc); - for &inner in alloc.inner().provenance().ptrs().values() { + for &prov in alloc.inner().provenance().ptrs().values() { rustc_data_structures::stack::ensure_sufficient_stack(|| { - collect_alloc(tcx, inner, output); + collect_alloc(tcx, prov.alloc_id(), output); }); } } @@ -1440,12 +1440,12 @@ fn collect_const_value<'tcx>( ) { match value { mir::ConstValue::Scalar(Scalar::Ptr(ptr, _size)) => { - collect_alloc(tcx, ptr.provenance, output) + collect_alloc(tcx, ptr.provenance.alloc_id(), output) } mir::ConstValue::Indirect { alloc_id, .. } => collect_alloc(tcx, alloc_id, output), mir::ConstValue::Slice { data, meta: _ } => { - for &id in data.inner().provenance().ptrs().values() { - collect_alloc(tcx, id, output); + for &prov in data.inner().provenance().ptrs().values() { + collect_alloc(tcx, prov.alloc_id(), output); } } _ => {} diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 1c3c433d8b7..da51d9dbe9f 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -23,6 +23,8 @@ parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or late parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015 .label = to use `async fn`, switch to Rust 2018 or later +parse_async_gen_fn = `async gen` functions are not supported + parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 2018 or later parse_async_move_order_incorrect = the order of `move` and `async` is incorrect diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 03e047b297d..45f950db5c3 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use rustc_ast::token::Token; use rustc_ast::{Path, Visibility}; -use rustc_errors::{AddToDiagnostic, Applicability, EmissionGuarantee, IntoDiagnostic}; +use rustc_errors::{AddToDiagnostic, Applicability, ErrorGuaranteed, IntoDiagnostic}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::edition::{Edition, LATEST_STABLE_EDITION}; @@ -563,6 +563,13 @@ pub(crate) struct GenFn { } #[derive(Diagnostic)] +#[diag(parse_async_gen_fn)] +pub(crate) struct AsyncGenFn { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(parse_comma_after_base_struct)] #[note] pub(crate) struct CommaAfterBaseStruct { @@ -1038,12 +1045,12 @@ pub(crate) struct ExpectedIdentifier { pub help_cannot_start_number: Option<HelpIdentifierStartsWithNumber>, } -impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier { +impl<'a> IntoDiagnostic<'a> for ExpectedIdentifier { #[track_caller] fn into_diagnostic( self, handler: &'a rustc_errors::Handler, - ) -> rustc_errors::DiagnosticBuilder<'a, G> { + ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> { let token_descr = TokenDescription::from_token(&self.token); let mut diag = handler.struct_diagnostic(match token_descr { @@ -1095,12 +1102,12 @@ pub(crate) struct ExpectedSemi { pub sugg: ExpectedSemiSugg, } -impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedSemi { +impl<'a> IntoDiagnostic<'a> for ExpectedSemi { #[track_caller] fn into_diagnostic( self, handler: &'a rustc_errors::Handler, - ) -> rustc_errors::DiagnosticBuilder<'a, G> { + ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> { let token_descr = TokenDescription::from_token(&self.token); let mut diag = handler.struct_diagnostic(match token_descr { @@ -1726,7 +1733,7 @@ pub(crate) struct ExternItemCannotBeConst { #[primary_span] pub ident_span: Span, #[suggestion(code = "static ", applicability = "machine-applicable")] - pub const_span: Span, + pub const_span: Option<Span>, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 98e68e682ab..7ab0d3f35ea 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -673,15 +673,6 @@ impl<'a> Parser<'a> { ); } - // Add suggestion for a missing closing angle bracket if '>' is included in expected_tokens - // there are unclosed angle brackets - if self.unmatched_angle_bracket_count > 0 - && self.token.kind == TokenKind::Eq - && expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Gt))) - { - err.span_label(self.prev_token.span, "maybe try to close unmatched angle bracket"); - } - let sp = if self.token == token::Eof { // This is EOF; don't want to point at the following char, but rather the last token. self.prev_token.span @@ -811,6 +802,7 @@ impl<'a> Parser<'a> { } err.emit(); } + fn check_too_many_raw_str_terminators(&mut self, err: &mut Diagnostic) -> bool { let sm = self.sess.source_map(); match (&self.prev_token.kind, &self.token.kind) { @@ -1986,6 +1978,39 @@ impl<'a> Parser<'a> { } } + /// When trying to close a generics list and encountering code like + /// ```text + /// impl<S: Into<std::borrow::Cow<'static, str>> From<S> for Canonical {} + /// // ^ missing > here + /// ``` + /// we provide a structured suggestion on the error from `expect_gt`. + pub(super) fn expect_gt_or_maybe_suggest_closing_generics( + &mut self, + params: &[ast::GenericParam], + ) -> PResult<'a, ()> { + let Err(mut err) = self.expect_gt() else { + return Ok(()); + }; + // Attempt to find places where a missing `>` might belong. + if let [.., ast::GenericParam { bounds, .. }] = params + && let Some(poly) = bounds + .iter() + .filter_map(|bound| match bound { + ast::GenericBound::Trait(poly, _) => Some(poly), + _ => None, + }) + .last() + { + err.span_suggestion_verbose( + poly.span.shrink_to_hi(), + "you might have meant to end the type parameters here", + ">", + Applicability::MaybeIncorrect, + ); + } + Err(err) + } + pub(super) fn recover_seq_parse_error( &mut self, delim: Delimiter, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index f8444881d1a..8482824ec4b 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -10,7 +10,7 @@ use super::{ use crate::errors; use crate::maybe_recover_from_interpolated_ty_qpath; use ast::mut_visit::{noop_visit_expr, MutVisitor}; -use ast::{GenBlockKind, Pat, Path, PathSegment}; +use ast::{CoroutineKind, GenBlockKind, Pat, Path, PathSegment}; use core::mem; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; @@ -21,7 +21,7 @@ use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity}; use rustc_ast::visit::Visitor; use rustc_ast::{self as ast, AttrStyle, AttrVec, CaptureBy, ExprField, UnOp, DUMMY_NODE_ID}; use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty, TyKind}; -use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}; +use rustc_ast::{Arm, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}; use rustc_ast::{ClosureBinder, MetaItemLit, StmtKind}; use rustc_ast_pretty::pprust; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -2237,7 +2237,7 @@ impl<'a> Parser<'a> { let asyncness = if self.token.uninterpolated_span().at_least_rust_2018() { self.parse_asyncness(Case::Sensitive) } else { - Async::No + None }; let capture_clause = self.parse_capture_clause()?; @@ -2261,7 +2261,7 @@ impl<'a> Parser<'a> { } }; - if let Async::Yes { span, .. } = asyncness { + if let Some(CoroutineKind::Async { span, .. }) = asyncness { // Feature-gate `async ||` closures. self.sess.gated_spans.gate(sym::async_closure, span); } @@ -2284,7 +2284,7 @@ impl<'a> Parser<'a> { binder, capture_clause, constness, - asyncness, + coro_kind: asyncness, movability, fn_decl, body, diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 242c9d332bb..20f67b284b2 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -279,7 +279,7 @@ impl<'a> Parser<'a> { let span_lo = self.token.span; let (params, span) = if self.eat_lt() { let params = self.parse_generic_params()?; - self.expect_gt()?; + self.expect_gt_or_maybe_suggest_closing_generics(¶ms)?; (params, span_lo.to(self.prev_token.span)) } else { (ThinVec::new(), self.prev_token.span.shrink_to_hi()) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index a737f37a104..086e8d5cf9b 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -11,8 +11,8 @@ use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::util::case::Case; use rustc_ast::MacCall; use rustc_ast::{self as ast, AttrVec, Attribute, DUMMY_NODE_ID}; -use rustc_ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind}; use rustc_ast::{BindingAnnotation, Block, FnDecl, FnSig, Param, SelfKind}; +use rustc_ast::{Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind}; use rustc_ast::{EnumDef, FieldDef, Generics, TraitRef, Ty, TyKind, Variant, VariantData}; use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind}; use rustc_ast_pretty::pprust; @@ -1139,9 +1139,11 @@ impl<'a> Parser<'a> { Ok(kind) => kind, Err(kind) => match kind { ItemKind::Const(box ConstItem { ty, expr, .. }) => { + let const_span = Some(span.with_hi(ident.span.lo())) + .filter(|span| span.can_be_used_for_suggestions()); self.sess.emit_err(errors::ExternItemCannotBeConst { ident_span: ident.span, - const_span: span.with_hi(ident.span.lo()), + const_span, }); ForeignItemKind::Static(ty, Mutability::Not, expr) } @@ -2401,7 +2403,7 @@ impl<'a> Parser<'a> { let ext_start_sp = self.token.span; let ext = self.parse_extern(case); - if let Async::Yes { span, .. } = asyncness { + if let Some(CoroutineKind::Async { span, .. }) = asyncness { if span.is_rust_2015() { self.sess.emit_err(errors::AsyncFnIn2015 { span, @@ -2410,8 +2412,16 @@ impl<'a> Parser<'a> { } } - if let Gen::Yes { span, .. } = genness { - self.sess.emit_err(errors::GenFn { span }); + if let Some(CoroutineKind::Gen { span, .. }) = genness { + self.sess.gated_spans.gate(sym::gen_blocks, span); + } + + if let ( + Some(CoroutineKind::Async { span: async_span, .. }), + Some(CoroutineKind::Gen { span: gen_span, .. }), + ) = (asyncness, genness) + { + self.sess.emit_err(errors::AsyncGenFn { span: async_span.to(gen_span) }); } if !self.eat_keyword_case(kw::Fn, case) { @@ -2444,13 +2454,18 @@ impl<'a> Parser<'a> { } } else if self.check_keyword(kw::Async) { match asyncness { - Async::Yes { span, .. } => Some(WrongKw::Duplicated(span)), - Async::No => { - recover_asyncness = Async::Yes { + Some(CoroutineKind::Async { span, .. }) => { + Some(WrongKw::Duplicated(span)) + } + Some(CoroutineKind::Gen { .. }) => { + panic!("not sure how to recover here") + } + None => { + recover_asyncness = Some(CoroutineKind::Async { span: self.token.span, closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID, - }; + }); Some(WrongKw::Misplaced(unsafe_start_sp)) } } @@ -2531,6 +2546,8 @@ impl<'a> Parser<'a> { } } + // FIXME(gen_blocks): add keyword recovery logic for genness + if wrong_kw.is_some() && self.may_recover() && self.look_ahead(1, |tok| tok.is_keyword_case(kw::Fn, case)) @@ -2542,7 +2559,7 @@ impl<'a> Parser<'a> { return Ok(FnHeader { constness: recover_constness, unsafety: recover_unsafety, - asyncness: recover_asyncness, + coro_kind: recover_asyncness, ext, }); } @@ -2552,7 +2569,13 @@ impl<'a> Parser<'a> { } } - Ok(FnHeader { constness, unsafety, asyncness, ext }) + let coro_kind = match asyncness { + Some(CoroutineKind::Async { .. }) => asyncness, + Some(CoroutineKind::Gen { .. }) => unreachable!("asycness cannot be Gen"), + None => genness, + }; + + Ok(FnHeader { constness, unsafety, coro_kind, ext }) } /// Parses the parameter list and result type of a function declaration. diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index c680a950584..2816386cbad 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -11,7 +11,6 @@ mod stmt; mod ty; use crate::lexer::UnmatchedDelim; -use ast::Gen; pub use attr_wrapper::AttrWrapper; pub use diagnostics::AttemptLocalParseRecovery; pub(crate) use expr::ForbiddenLetReason; @@ -25,9 +24,10 @@ use rustc_ast::tokenstream::{AttributesData, DelimSpan, Spacing}; use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor}; use rustc_ast::util::case::Case; use rustc_ast::AttrId; +use rustc_ast::CoroutineKind; use rustc_ast::DUMMY_NODE_ID; use rustc_ast::{self as ast, AnonConst, Const, DelimArgs, Extern}; -use rustc_ast::{Async, AttrArgs, AttrArgsEq, Expr, ExprKind, Mutability, StrLit}; +use rustc_ast::{AttrArgs, AttrArgsEq, Expr, ExprKind, Mutability, StrLit}; use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; @@ -1125,22 +1125,30 @@ impl<'a> Parser<'a> { } /// Parses asyncness: `async` or nothing. - fn parse_asyncness(&mut self, case: Case) -> Async { + fn parse_asyncness(&mut self, case: Case) -> Option<CoroutineKind> { if self.eat_keyword_case(kw::Async, case) { let span = self.prev_token.uninterpolated_span(); - Async::Yes { span, closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID } + Some(CoroutineKind::Async { + span, + closure_id: DUMMY_NODE_ID, + return_impl_trait_id: DUMMY_NODE_ID, + }) } else { - Async::No + None } } /// Parses genness: `gen` or nothing. - fn parse_genness(&mut self, case: Case) -> Gen { + fn parse_genness(&mut self, case: Case) -> Option<CoroutineKind> { if self.token.span.at_least_rust_2024() && self.eat_keyword_case(kw::Gen, case) { let span = self.prev_token.uninterpolated_span(); - Gen::Yes { span, closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID } + Some(CoroutineKind::Gen { + span, + closure_id: DUMMY_NODE_ID, + return_impl_trait_id: DUMMY_NODE_ID, + }) } else { - Gen::No + None } } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index b1a57c3dfd9..f349140e8c3 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -304,23 +304,25 @@ impl<'a> Parser<'a> { if self.may_recover() && (self.eat_keyword_noexpect(kw::Impl) || self.eat_keyword_noexpect(kw::Dyn)) { - let kw = self.prev_token.ident().unwrap().0.name; + let kw = self.prev_token.ident().unwrap().0; + let removal_span = kw.span.with_hi(self.token.span.lo()); + let path = self.parse_path(PathStyle::Type)?; + let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); + let kind = + self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?; let mut err = self.sess.create_err(errors::TransposeDynOrImpl { - span: self.prev_token.span, - kw: kw.as_str(), + span: kw.span, + kw: kw.name.as_str(), sugg: errors::TransposeDynOrImplSugg { - removal_span: self.prev_token.span.with_hi(self.token.span.lo()), + removal_span, insertion_span: for_span.shrink_to_lo(), - kw: kw.as_str(), + kw: kw.name.as_str(), }, }); - let path = self.parse_path(PathStyle::Type)?; - let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus(); - let kind = - self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?; + // Take the parsed bare trait object and turn it either // into a `dyn` object or an `impl Trait`. - let kind = match (kind, kw) { + let kind = match (kind, kw.name) { (TyKind::TraitObject(bounds, _), kw::Dyn) => { TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn) } @@ -596,7 +598,7 @@ impl<'a> Parser<'a> { tokens: None, }; let span_start = self.token.span; - let ast::FnHeader { ext, unsafety, constness, asyncness } = + let ast::FnHeader { ext, unsafety, constness, coro_kind } = self.parse_fn_front_matter(&inherited_vis, Case::Sensitive)?; if self.may_recover() && self.token.kind == TokenKind::Lt { self.recover_fn_ptr_with_generics(lo, &mut params, param_insertion_point)?; @@ -609,9 +611,10 @@ impl<'a> Parser<'a> { // cover it. self.sess.emit_err(FnPointerCannotBeConst { span: whole_span, qualifier: span }); } - if let ast::Async::Yes { span, .. } = asyncness { + if let Some(ast::CoroutineKind::Async { span, .. }) = coro_kind { self.sess.emit_err(FnPointerCannotBeAsync { span: whole_span, qualifier: span }); } + // FIXME(gen_blocks): emit a similar error for `gen fn()` let decl_span = span_start.to(self.token.span); Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params: params, decl, decl_span }))) } diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 23baf14aea1..d0b782ba4ca 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -21,7 +21,7 @@ use rustc_hir::{LangItem, LanguageItems, Target}; use rustc_middle::ty::TyCtxt; use rustc_session::cstore::ExternCrate; use rustc_span::symbol::kw::Empty; -use rustc_span::{sym, Span}; +use rustc_span::Span; use rustc_middle::query::Providers; @@ -162,7 +162,12 @@ impl<'tcx> LanguageItemCollector<'tcx> { generics .params .iter() - .filter(|p| !self.tcx.has_attr(p.def_id, sym::rustc_host)) + .filter(|p| { + !matches!( + p.kind, + hir::GenericParamKind::Const { is_host_effect: true, .. } + ) + }) .count(), generics.span, ), diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index e7ec4749efe..9064cb6e875 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -531,44 +531,21 @@ impl<'tcx> EmbargoVisitor<'tcx> { macro_ev: EffectiveVisibility, ) -> bool { if self.macro_reachable.insert((module_def_id, defining_mod)) { - self.update_macro_reachable_mod(module_def_id, defining_mod, macro_ev); + for child in self.tcx.module_children_local(module_def_id.to_local_def_id()) { + if let Res::Def(def_kind, def_id) = child.res + && let Some(def_id) = def_id.as_local() + && child.vis.is_accessible_from(defining_mod, self.tcx) + { + let vis = self.tcx.local_visibility(def_id); + self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod, macro_ev); + } + } true } else { false } } - fn update_macro_reachable_mod( - &mut self, - module_def_id: LocalModDefId, - defining_mod: LocalModDefId, - macro_ev: EffectiveVisibility, - ) { - let module = self.tcx.hir().get_module(module_def_id).0; - for item_id in module.item_ids { - let def_kind = self.tcx.def_kind(item_id.owner_id); - let vis = self.tcx.local_visibility(item_id.owner_id.def_id); - self.update_macro_reachable_def( - item_id.owner_id.def_id, - def_kind, - vis, - defining_mod, - macro_ev, - ); - } - for child in self.tcx.module_children_local(module_def_id.to_local_def_id()) { - // FIXME: Use module children for the logic above too. - if !child.reexport_chain.is_empty() - && child.vis.is_accessible_from(defining_mod, self.tcx) - && let Res::Def(def_kind, def_id) = child.res - && let Some(def_id) = def_id.as_local() - { - let vis = self.tcx.local_visibility(def_id); - self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod, macro_ev); - } - } - } - fn update_macro_reachable_def( &mut self, def_id: LocalDefId, diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index 78930b151cd..9b66b9a48d9 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -3,7 +3,7 @@ #![feature(hash_raw_entry)] #![feature(min_specialization)] #![feature(let_chains)] -#![allow(rustc::potential_query_instability)] +#![allow(rustc::potential_query_instability, internal_features)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index a5faaaab639..3f8df16e03f 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -181,6 +181,8 @@ resolve_method_not_member_of_trait = method `{$method}` is not a member of trait `{$trait_}` .label = not a member of trait `{$trait_}` +resolve_missing_macro_rules_name = maybe you have forgotten to define a name for this `macro_rules!` + resolve_module_only = visibility must resolve to a module diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 647c92785e1..ab5d3b368eb 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -156,7 +156,10 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) { if let FnKind::Fn(_, _, sig, _, generics, body) = fn_kind { - if let Async::Yes { closure_id, .. } = sig.header.asyncness { + if let Some( + CoroutineKind::Async { closure_id, .. } | CoroutineKind::Gen { closure_id, .. }, + ) = sig.header.coro_kind + { self.visit_generics(generics); // For async functions, we need to create their inner defs inside of a @@ -281,11 +284,12 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { // Async closures desugar to closures inside of closures, so // we must create two defs. let closure_def = self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span); - match closure.asyncness { - Async::Yes { closure_id, .. } => { - self.create_def(closure_id, kw::Empty, DefKind::Closure, expr.span) - } - Async::No => closure_def, + match closure.coro_kind { + Some( + CoroutineKind::Async { closure_id, .. } + | CoroutineKind::Gen { closure_id, .. }, + ) => self.create_def(closure_id, kw::Empty, DefKind::Closure, expr.span), + None => closure_def, } } ExprKind::Gen(_, _, _) => { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 6c387a385e6..542aff69e34 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -27,10 +27,8 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Span, SyntaxContext}; use thin_vec::{thin_vec, ThinVec}; -use crate::errors::{ - AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive, - ExplicitUnsafeTraits, -}; +use crate::errors::{AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion}; +use crate::errors::{ConsiderAddingADerive, ExplicitUnsafeTraits, MaybeMissingMacroRulesName}; use crate::imports::{Import, ImportKind}; use crate::late::{PatternSource, Rib}; use crate::path_names_to_string; @@ -1421,14 +1419,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { "", ); + if macro_kind == MacroKind::Bang && ident.name == sym::macro_rules { + err.subdiagnostic(MaybeMissingMacroRulesName { span: ident.span }); + return; + } + if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) { err.subdiagnostic(ExplicitUnsafeTraits { span: ident.span, ident }); return; } + if self.macro_names.contains(&ident.normalize_to_macros_2_0()) { err.subdiagnostic(AddedMacroUse); return; } + if ident.name == kw::Default && let ModuleKind::Def(DefKind::Enum, def_id, _) = parent_scope.module.kind { @@ -1697,6 +1702,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { struct_span_err!(self.tcx.sess, ident.span, E0603, "{} `{}` is private", descr, ident); err.span_label(ident.span, format!("private {descr}")); + let mut not_publicly_reexported = false; if let Some((this_res, outer_ident)) = outermost_res { let import_suggestions = self.lookup_import_candidates( outer_ident, @@ -1717,6 +1723,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ); // If we suggest importing a public re-export, don't point at the definition. if point_to_def && ident.span != outer_ident.span { + not_publicly_reexported = true; err.span_label( outer_ident.span, format!("{} `{outer_ident}` is not publicly re-exported", this_res.descr()), @@ -1749,10 +1756,51 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } + let mut sugg_paths = vec![]; + if let Some(mut def_id) = res.opt_def_id() { + // We can't use `def_path_str` in resolve. + let mut path = vec![def_id]; + while let Some(parent) = self.tcx.opt_parent(def_id) { + def_id = parent; + if !def_id.is_top_level_module() { + path.push(def_id); + } else { + break; + } + } + // We will only suggest importing directly if it is accessible through that path. + let path_names: Option<Vec<String>> = path + .iter() + .rev() + .map(|def_id| { + self.tcx.opt_item_name(*def_id).map(|n| { + if def_id.is_top_level_module() { + "crate".to_string() + } else { + n.to_string() + } + }) + }) + .collect(); + if let Some(def_id) = path.get(0) + && let Some(path) = path_names + { + if let Some(def_id) = def_id.as_local() { + if self.effective_visibilities.is_directly_public(def_id) { + sugg_paths.push((path, false)); + } + } else if self.is_accessible_from(self.tcx.visibility(def_id), parent_scope.module) + { + sugg_paths.push((path, false)); + } + } + } + // Print the whole import chain to make it easier to see what happens. let first_binding = binding; let mut next_binding = Some(binding); let mut next_ident = ident; + let mut path = vec![]; while let Some(binding) = next_binding { let name = next_ident; next_binding = match binding.kind { @@ -1771,6 +1819,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { _ => None, }; + match binding.kind { + NameBindingKind::Import { import, .. } => { + for segment in import.module_path.iter().skip(1) { + path.push(segment.ident.to_string()); + } + sugg_paths.push(( + path.iter() + .cloned() + .chain(vec![ident.to_string()].into_iter()) + .collect::<Vec<_>>(), + true, // re-export + )); + } + NameBindingKind::Res(_) | NameBindingKind::Module(_) => {} + } let first = binding == first_binding; let msg = format!( "{and_refers_to}the {item} `{name}`{which} is defined here{dots}", @@ -1782,7 +1845,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let def_span = self.tcx.sess.source_map().guess_head_span(binding.span); let mut note_span = MultiSpan::from_span(def_span); if !first && binding.vis.is_public() { - note_span.push_span_label(def_span, "consider importing it directly"); + let desc = match binding.kind { + NameBindingKind::Import { .. } => "re-export", + _ => "directly", + }; + note_span.push_span_label(def_span, format!("you could import this {desc}")); } // Final step in the import chain, point out if the ADT is `non_exhaustive` // which is probably why this privacy violation occurred. @@ -1796,6 +1863,29 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } err.span_note(note_span, msg); } + // We prioritize shorter paths, non-core imports and direct imports over the alternatives. + sugg_paths.sort_by_key(|(p, reexport)| (p.len(), p[0] == "core", *reexport)); + for (sugg, reexport) in sugg_paths { + if not_publicly_reexported { + break; + } + if sugg.len() <= 1 { + // A single path segment suggestion is wrong. This happens on circular imports. + // `tests/ui/imports/issue-55884-2.rs` + continue; + } + let path = sugg.join("::"); + err.span_suggestion_verbose( + dedup_span, + format!( + "import `{ident}` {}", + if reexport { "through the re-export" } else { "directly" } + ), + path, + Applicability::MachineApplicable, + ); + break; + } err.emit(); } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 72ff959bbd6..1fdb193e571 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -666,6 +666,13 @@ pub(crate) struct ExplicitUnsafeTraits { } #[derive(Subdiagnostic)] +#[note(resolve_missing_macro_rules_name)] +pub(crate) struct MaybeMissingMacroRulesName { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Subdiagnostic)] #[help(resolve_added_macro_use)] pub(crate) struct AddedMacroUse; diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index b28ad671f12..c2306e3ea7d 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -477,6 +477,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.per_ns(|this, ns| { let key = BindingKey::new(target, ns); let _ = this.try_define(import.parent_scope.module, key, dummy_binding, false); + this.update_resolution(import.parent_scope.module, key, false, |_, resolution| { + resolution.single_imports.remove(&import); + }) }); self.record_use(target, dummy_binding, false); } else if import.imported_module.get().is_none() { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f20d5829030..ad14f5e5225 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -916,8 +916,10 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, &sig.decl.output, ); - if let Some((async_node_id, _)) = sig.header.asyncness.opt_return_id() { - this.record_lifetime_params_for_impl_trait(async_node_id); + if let Some((coro_node_id, _)) = + sig.header.coro_kind.map(|coro_kind| coro_kind.return_id()) + { + this.record_lifetime_params_for_impl_trait(coro_node_id); } }, ); @@ -940,12 +942,13 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, this.visit_generics(generics); let declaration = &sig.decl; - let async_node_id = sig.header.asyncness.opt_return_id(); + let coro_node_id = + sig.header.coro_kind.map(|coro_kind| coro_kind.return_id()); this.with_lifetime_rib( LifetimeRibKind::AnonymousCreateParameter { binder: fn_id, - report_in_path: async_node_id.is_some(), + report_in_path: coro_node_id.is_some(), }, |this| { this.resolve_fn_signature( @@ -958,7 +961,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, &declaration.output, ); - if let Some((async_node_id, _)) = async_node_id { + if let Some((async_node_id, _)) = coro_node_id { this.record_lifetime_params_for_impl_trait(async_node_id); } }, @@ -4288,8 +4291,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // `async |x| ...` gets desugared to `|x| async {...}`, so we need to // resolve the arguments within the proper scopes so that usages of them inside the // closure are detected as upvars rather than normal closure arg usages. + // + // Similarly, `gen |x| ...` gets desugared to `|x| gen {...}`, so we handle that too. ExprKind::Closure(box ast::Closure { - asyncness: Async::Yes { .. }, + coro_kind: Some(_), ref fn_decl, ref body, .. diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index 3a7959c332e..f2e646c70f5 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -16,6 +16,8 @@ session_crate_name_invalid = crate names cannot start with a `-`, but `{$s}` has session_expr_parentheses_needed = parentheses are required to parse this as an expression +session_failed_to_create_profiler = failed to create profiler: {$err} + session_feature_diagnostic_for_issue = see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information @@ -73,6 +75,7 @@ session_not_supported = not supported session_nul_in_c_str = null characters in C string literals are not supported session_octal_float_literal_not_supported = octal float literal is not supported + session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg} session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C profile-sample-use` does not exist. diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index e694e150b31..1ea3ab0d5ec 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2121,16 +2121,6 @@ fn should_override_cgus_and_disable_thinlto( (disable_local_thinlto, codegen_units) } -fn check_thread_count(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions) { - if unstable_opts.threads == 0 { - handler.early_error("value for threads must be a positive non-zero integer"); - } - - if unstable_opts.threads > 1 && unstable_opts.fuel.is_some() { - handler.early_error("optimization fuel is incompatible with multiple threads"); - } -} - fn collect_print_requests( handler: &EarlyErrorHandler, cg: &mut CodegenOptions, @@ -2646,7 +2636,17 @@ pub fn build_session_options( let (disable_local_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(handler, &output_types, matches, cg.codegen_units); - check_thread_count(handler, &unstable_opts); + if unstable_opts.threads == 0 { + handler.early_error("value for threads must be a positive non-zero integer"); + } + + let fuel = unstable_opts.fuel.is_some() || unstable_opts.print_fuel.is_some(); + if fuel && unstable_opts.threads > 1 { + handler.early_error("optimization fuel is incompatible with multiple threads"); + } + if fuel && cg.incremental.is_some() { + handler.early_error("optimization fuel is incompatible with incremental compilation"); + } let incremental = cg.incremental.as_ref().map(PathBuf::from); diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 70ee46ea902..7eed59709c8 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -3,7 +3,7 @@ use std::num::NonZeroU32; use crate::parse::ParseSess; use rustc_ast::token; use rustc_ast::util::literal::LitError; -use rustc_errors::{error_code, DiagnosticMessage, EmissionGuarantee, IntoDiagnostic, MultiSpan}; +use rustc_errors::{error_code, DiagnosticMessage, ErrorGuaranteed, IntoDiagnostic, MultiSpan}; use rustc_macros::Diagnostic; use rustc_span::{BytePos, Span, Symbol}; use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple}; @@ -13,12 +13,12 @@ pub struct FeatureGateError { pub explain: DiagnosticMessage, } -impl<'a, T: EmissionGuarantee> IntoDiagnostic<'a, T> for FeatureGateError { +impl<'a> IntoDiagnostic<'a> for FeatureGateError { #[track_caller] fn into_diagnostic( self, handler: &'a rustc_errors::Handler, - ) -> rustc_errors::DiagnosticBuilder<'a, T> { + ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> { let mut diag = handler.struct_diagnostic(self.explain); diag.set_span(self.span); diag.code(error_code!(E0658)); @@ -444,3 +444,9 @@ pub(crate) struct FunctionReturnRequiresX86OrX8664; #[derive(Diagnostic)] #[diag(session_function_return_thunk_extern_requires_non_large_code_model)] pub(crate) struct FunctionReturnThunkExternRequiresNonLargeCodeModel; + +#[derive(Diagnostic)] +#[diag(session_failed_to_create_profiler)] +pub struct FailedToCreateProfiler { + pub err: String, +} diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 57a535d8c10..123e9c788f5 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -24,7 +24,7 @@ use rustc_errors::registry::Registry; use rustc_errors::{ error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, ErrorGuaranteed, FluentBundle, Handler, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted, - SubdiagnosticMessage, TerminalUrl, + TerminalUrl, }; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; @@ -461,7 +461,7 @@ impl Session { } #[rustc_lint_diagnostics] pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! { - self.diagnostic().fatal(msg).raise() + self.diagnostic().fatal(msg) } #[rustc_lint_diagnostics] #[track_caller] @@ -1349,7 +1349,7 @@ fn default_emitter( // JUSTIFICATION: literally session construction #[allow(rustc::bad_opt_access)] pub fn build_session( - handler: &EarlyErrorHandler, + early_handler: EarlyErrorHandler, sopts: config::Options, io: CompilerIO, bundle: Option<Lrc<rustc_errors::FluentBundle>>, @@ -1379,12 +1379,13 @@ pub fn build_session( None => filesearch::get_or_default_sysroot().expect("Failed finding sysroot"), }; - let target_cfg = config::build_target_config(handler, &sopts, target_override, &sysroot); + let target_cfg = config::build_target_config(&early_handler, &sopts, target_override, &sysroot); let host_triple = TargetTriple::from_triple(config::host_triple()); - let (host, target_warnings) = Target::search(&host_triple, &sysroot) - .unwrap_or_else(|e| handler.early_error(format!("Error loading host specification: {e}"))); + let (host, target_warnings) = Target::search(&host_triple, &sysroot).unwrap_or_else(|e| { + early_handler.early_error(format!("Error loading host specification: {e}")) + }); for warning in target_warnings.warning_messages() { - handler.early_warn(warning) + early_handler.early_warn(warning) } let loader = file_loader.unwrap_or_else(|| Box::new(RealFileLoader)); @@ -1413,6 +1414,10 @@ pub fn build_session( span_diagnostic = span_diagnostic.with_ice_file(ice_file); } + // Now that the proper handler has been constructed, drop the early handler + // to prevent accidental use. + drop(early_handler); + let self_profiler = if let SwitchWithOptPath::Enabled(ref d) = sopts.unstable_opts.self_profile { let directory = @@ -1427,7 +1432,7 @@ pub fn build_session( match profiler { Ok(profiler) => Some(Arc::new(profiler)), Err(e) => { - handler.early_warn(format!("failed to create profiler: {e}")); + span_diagnostic.emit_warning(errors::FailedToCreateProfiler { err: e.to_string() }); None } } @@ -1471,7 +1476,13 @@ pub fn build_session( // Check jobserver before getting `jobserver::client`. jobserver::check(|err| { - handler.early_warn_with_note(err, "the build environment is likely misconfigured") + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] + parse_sess + .span_diagnostic + .struct_warn(err) + .note("the build environment is likely misconfigured") + .emit() }); let sess = Session { @@ -1781,16 +1792,6 @@ impl EarlyErrorHandler { pub fn early_warn(&self, msg: impl Into<DiagnosticMessage>) { self.handler.struct_warn(msg).emit() } - - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] - pub fn early_warn_with_note( - &self, - msg: impl Into<DiagnosticMessage>, - note: impl Into<SubdiagnosticMessage>, - ) { - self.handler.struct_warn(msg).note(note).emit() - } } fn mk_emitter(output: ErrorOutputType) -> Box<DynEmitter> { diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 202ca1b156a..63207200353 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -9,10 +9,12 @@ use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy}; use rustc_span::Symbol; use stable_mir::mir::alloc::AllocId; use stable_mir::mir::mono::{Instance, MonoItem, StaticDef}; +use stable_mir::mir::{Mutability, Safety}; use stable_mir::ty::{ - AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, - ExistentialTraitRef, FloatTy, GenericArgKind, GenericArgs, IntTy, Region, RigidTy, Span, - TraitRef, Ty, UintTy, + Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, + DynKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig, + GenericArgKind, GenericArgs, IndexedVal, IntTy, Movability, Region, RigidTy, Span, TermKind, + TraitRef, Ty, UintTy, VariantDef, VariantIdx, }; use stable_mir::{CrateItem, DefId}; @@ -84,17 +86,38 @@ impl<'tcx> RustcInternal<'tcx> for RigidTy { } RigidTy::Str => rustc_ty::TyKind::Str, RigidTy::Slice(ty) => rustc_ty::TyKind::Slice(ty.internal(tables)), - RigidTy::RawPtr(..) - | RigidTy::Ref(..) - | RigidTy::Foreign(_) - | RigidTy::FnDef(_, _) - | RigidTy::FnPtr(_) - | RigidTy::Closure(..) - | RigidTy::Coroutine(..) - | RigidTy::CoroutineWitness(..) - | RigidTy::Dynamic(..) - | RigidTy::Tuple(..) => { - todo!() + RigidTy::RawPtr(ty, mutability) => rustc_ty::TyKind::RawPtr(rustc_ty::TypeAndMut { + ty: ty.internal(tables), + mutbl: mutability.internal(tables), + }), + RigidTy::Ref(region, ty, mutability) => rustc_ty::TyKind::Ref( + region.internal(tables), + ty.internal(tables), + mutability.internal(tables), + ), + RigidTy::Foreign(def) => rustc_ty::TyKind::Foreign(def.0.internal(tables)), + RigidTy::FnDef(def, args) => { + rustc_ty::TyKind::FnDef(def.0.internal(tables), args.internal(tables)) + } + RigidTy::FnPtr(sig) => rustc_ty::TyKind::FnPtr(sig.internal(tables)), + RigidTy::Closure(def, args) => { + rustc_ty::TyKind::Closure(def.0.internal(tables), args.internal(tables)) + } + RigidTy::Coroutine(def, args, mov) => rustc_ty::TyKind::Coroutine( + def.0.internal(tables), + args.internal(tables), + mov.internal(tables), + ), + RigidTy::CoroutineWitness(def, args) => { + rustc_ty::TyKind::CoroutineWitness(def.0.internal(tables), args.internal(tables)) + } + RigidTy::Dynamic(predicate, region, dyn_kind) => rustc_ty::TyKind::Dynamic( + tables.tcx.mk_poly_existential_predicates(&predicate.internal(tables)), + region.internal(tables), + dyn_kind.internal(tables), + ), + RigidTy::Tuple(tys) => { + rustc_ty::TyKind::Tuple(tables.tcx.mk_type_list(&tys.internal(tables))) } } } @@ -141,6 +164,57 @@ impl<'tcx> RustcInternal<'tcx> for FloatTy { } } +impl<'tcx> RustcInternal<'tcx> for Mutability { + type T = rustc_ty::Mutability; + + fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + match self { + Mutability::Not => rustc_ty::Mutability::Not, + Mutability::Mut => rustc_ty::Mutability::Mut, + } + } +} + +impl<'tcx> RustcInternal<'tcx> for Movability { + type T = rustc_ty::Movability; + + fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + match self { + Movability::Static => rustc_ty::Movability::Static, + Movability::Movable => rustc_ty::Movability::Movable, + } + } +} + +impl<'tcx> RustcInternal<'tcx> for FnSig { + type T = rustc_ty::FnSig<'tcx>; + + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + rustc_ty::FnSig { + inputs_and_output: tables.tcx.mk_type_list(&self.inputs_and_output.internal(tables)), + c_variadic: self.c_variadic, + unsafety: self.unsafety.internal(tables), + abi: self.abi.internal(tables), + } + } +} + +impl<'tcx> RustcInternal<'tcx> for VariantIdx { + type T = rustc_target::abi::VariantIdx; + + fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + rustc_target::abi::VariantIdx::from(self.to_index()) + } +} + +impl<'tcx> RustcInternal<'tcx> for VariantDef { + type T = &'tcx rustc_ty::VariantDef; + + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + self.adt_def.internal(tables).variant(self.idx.internal(tables)) + } +} + fn ty_const<'tcx>(constant: &Const, tables: &mut Tables<'tcx>) -> rustc_ty::Const<'tcx> { match constant.internal(tables) { rustc_middle::mir::Const::Ty(c) => c, @@ -230,6 +304,58 @@ impl<'tcx> RustcInternal<'tcx> for BoundVariableKind { } } +impl<'tcx> RustcInternal<'tcx> for DynKind { + type T = rustc_ty::DynKind; + + fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + match self { + DynKind::Dyn => rustc_ty::DynKind::Dyn, + DynKind::DynStar => rustc_ty::DynKind::DynStar, + } + } +} + +impl<'tcx> RustcInternal<'tcx> for ExistentialPredicate { + type T = rustc_ty::ExistentialPredicate<'tcx>; + + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + match self { + ExistentialPredicate::Trait(trait_ref) => { + rustc_ty::ExistentialPredicate::Trait(trait_ref.internal(tables)) + } + ExistentialPredicate::Projection(proj) => { + rustc_ty::ExistentialPredicate::Projection(proj.internal(tables)) + } + ExistentialPredicate::AutoTrait(trait_def) => { + rustc_ty::ExistentialPredicate::AutoTrait(trait_def.0.internal(tables)) + } + } + } +} + +impl<'tcx> RustcInternal<'tcx> for ExistentialProjection { + type T = rustc_ty::ExistentialProjection<'tcx>; + + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + rustc_ty::ExistentialProjection { + def_id: self.def_id.0.internal(tables), + args: self.generic_args.internal(tables), + term: self.term.internal(tables), + } + } +} + +impl<'tcx> RustcInternal<'tcx> for TermKind { + type T = rustc_ty::Term<'tcx>; + + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + match self { + TermKind::Type(ty) => ty.internal(tables).into(), + TermKind::Const(const_) => ty_const(const_, tables).into(), + } + } +} + impl<'tcx> RustcInternal<'tcx> for ExistentialTraitRef { type T = rustc_ty::ExistentialTraitRef<'tcx>; @@ -279,6 +405,53 @@ impl<'tcx> RustcInternal<'tcx> for AdtDef { } } +impl<'tcx> RustcInternal<'tcx> for Abi { + type T = rustc_target::spec::abi::Abi; + + fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + match *self { + Abi::Rust => rustc_target::spec::abi::Abi::Rust, + Abi::C { unwind } => rustc_target::spec::abi::Abi::C { unwind }, + Abi::Cdecl { unwind } => rustc_target::spec::abi::Abi::Cdecl { unwind }, + Abi::Stdcall { unwind } => rustc_target::spec::abi::Abi::Stdcall { unwind }, + Abi::Fastcall { unwind } => rustc_target::spec::abi::Abi::Fastcall { unwind }, + Abi::Vectorcall { unwind } => rustc_target::spec::abi::Abi::Vectorcall { unwind }, + Abi::Thiscall { unwind } => rustc_target::spec::abi::Abi::Thiscall { unwind }, + Abi::Aapcs { unwind } => rustc_target::spec::abi::Abi::Aapcs { unwind }, + Abi::Win64 { unwind } => rustc_target::spec::abi::Abi::Win64 { unwind }, + Abi::SysV64 { unwind } => rustc_target::spec::abi::Abi::SysV64 { unwind }, + Abi::PtxKernel => rustc_target::spec::abi::Abi::PtxKernel, + Abi::Msp430Interrupt => rustc_target::spec::abi::Abi::Msp430Interrupt, + Abi::X86Interrupt => rustc_target::spec::abi::Abi::X86Interrupt, + Abi::AmdGpuKernel => rustc_target::spec::abi::Abi::AmdGpuKernel, + Abi::EfiApi => rustc_target::spec::abi::Abi::EfiApi, + Abi::AvrInterrupt => rustc_target::spec::abi::Abi::AvrInterrupt, + Abi::AvrNonBlockingInterrupt => rustc_target::spec::abi::Abi::AvrNonBlockingInterrupt, + Abi::CCmseNonSecureCall => rustc_target::spec::abi::Abi::CCmseNonSecureCall, + Abi::Wasm => rustc_target::spec::abi::Abi::Wasm, + Abi::System { unwind } => rustc_target::spec::abi::Abi::System { unwind }, + Abi::RustIntrinsic => rustc_target::spec::abi::Abi::RustIntrinsic, + Abi::RustCall => rustc_target::spec::abi::Abi::RustCall, + Abi::PlatformIntrinsic => rustc_target::spec::abi::Abi::PlatformIntrinsic, + Abi::Unadjusted => rustc_target::spec::abi::Abi::Unadjusted, + Abi::RustCold => rustc_target::spec::abi::Abi::RustCold, + Abi::RiscvInterruptM => rustc_target::spec::abi::Abi::RiscvInterruptM, + Abi::RiscvInterruptS => rustc_target::spec::abi::Abi::RiscvInterruptS, + } + } +} + +impl<'tcx> RustcInternal<'tcx> for Safety { + type T = rustc_hir::Unsafety; + + fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T { + match self { + Safety::Unsafe => rustc_hir::Unsafety::Unsafe, + Safety::Normal => rustc_hir::Unsafety::Normal, + } + } +} + impl<'tcx> RustcInternal<'tcx> for Span { type T = rustc_span::Span; @@ -297,6 +470,7 @@ where (*self).internal(tables) } } + impl<'tcx, T> RustcInternal<'tcx> for Option<T> where T: RustcInternal<'tcx>, @@ -307,3 +481,14 @@ where self.as_ref().map(|inner| inner.internal(tables)) } } + +impl<'tcx, T> RustcInternal<'tcx> for Vec<T> +where + T: RustcInternal<'tcx>, +{ + type T = Vec<T::T>; + + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + self.iter().map(|e| e.internal(tables)).collect() + } +} diff --git a/compiler/rustc_smir/src/rustc_smir/alloc.rs b/compiler/rustc_smir/src/rustc_smir/alloc.rs index 63a2a145069..850a52ce275 100644 --- a/compiler/rustc_smir/src/rustc_smir/alloc.rs +++ b/compiler/rustc_smir/src/rustc_smir/alloc.rs @@ -47,7 +47,7 @@ pub fn new_allocation<'tcx>( } ConstValue::Slice { data, meta } => { let alloc_id = tables.tcx.reserve_and_set_memory_alloc(data); - let ptr = Pointer::new(alloc_id, rustc_target::abi::Size::ZERO); + let ptr = Pointer::new(alloc_id.into(), rustc_target::abi::Size::ZERO); let scalar_ptr = rustc_middle::mir::interpret::Scalar::from_pointer(ptr, &tables.tcx); let scalar_meta = rustc_middle::mir::interpret::Scalar::from_target_usize(meta, &tables.tcx); @@ -112,7 +112,10 @@ pub(super) fn allocation_filter<'tcx>( .iter() .filter(|a| a.0 >= alloc_range.start && a.0 <= alloc_range.end()) { - ptrs.push((offset.bytes_usize() - alloc_range.start.bytes_usize(), tables.prov(*prov))); + ptrs.push(( + offset.bytes_usize() - alloc_range.start.bytes_usize(), + tables.prov(prov.alloc_id()), + )); } Allocation { bytes: bytes, diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 0bd640ee1e3..b10dfe85914 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -12,8 +12,8 @@ use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::mono::{InstanceDef, StaticDef}; use stable_mir::mir::Body; use stable_mir::ty::{ - AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FnDef, GenericArgs, LineInfo, - PolyFnSig, RigidTy, Span, TyKind, + AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs, + LineInfo, PolyFnSig, RigidTy, Span, TyKind, VariantDef, }; use stable_mir::{self, Crate, CrateItem, DefId, Error, Filename, ItemKind, Symbol}; use std::cell::RefCell; @@ -187,9 +187,9 @@ impl<'tcx> Context for TablesWrapper<'tcx> { new_item_kind(tables.tcx.def_kind(tables[item.0])) } - fn is_foreign_item(&self, item: CrateItem) -> bool { + fn is_foreign_item(&self, item: DefId) -> bool { let tables = self.0.borrow(); - tables.tcx.is_foreign_item(tables[item.0]) + tables.tcx.is_foreign_item(tables[item]) } fn adt_kind(&self, def: AdtDef) -> AdtKind { @@ -209,6 +209,21 @@ impl<'tcx> Context for TablesWrapper<'tcx> { sig.stable(&mut *tables) } + fn adt_variants_len(&self, def: AdtDef) -> usize { + let mut tables = self.0.borrow_mut(); + def.internal(&mut *tables).variants().len() + } + + fn variant_name(&self, def: VariantDef) -> Symbol { + let mut tables = self.0.borrow_mut(); + def.internal(&mut *tables).name.to_string() + } + + fn variant_fields(&self, def: VariantDef) -> Vec<FieldDef> { + let mut tables = self.0.borrow_mut(); + def.internal(&mut *tables).fields.iter().map(|f| f.stable(&mut *tables)).collect() + } + fn eval_target_usize(&self, cnst: &Const) -> Result<u64, Error> { let mut tables = self.0.borrow_mut(); let mir_const = cnst.internal(&mut *tables); @@ -235,11 +250,25 @@ impl<'tcx> Context for TablesWrapper<'tcx> { tables.tcx.mk_ty_from_kind(internal_kind).stable(&mut *tables) } + #[allow(rustc::usage_of_qualified_ty)] + fn new_box_ty(&self, ty: stable_mir::ty::Ty) -> stable_mir::ty::Ty { + let mut tables = self.0.borrow_mut(); + let inner = ty.internal(&mut *tables); + ty::Ty::new_box(tables.tcx, inner).stable(&mut *tables) + } + fn def_ty(&self, item: stable_mir::DefId) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); tables.tcx.type_of(item.internal(&mut *tables)).instantiate_identity().stable(&mut *tables) } + fn def_ty_with_args(&self, item: stable_mir::DefId, args: &GenericArgs) -> stable_mir::ty::Ty { + let mut tables = self.0.borrow_mut(); + let args = args.internal(&mut *tables); + let def_ty = tables.tcx.type_of(item.internal(&mut *tables)); + def_ty.instantiate(tables.tcx, args).stable(&mut *tables) + } + fn const_literal(&self, cnst: &stable_mir::ty::Const) -> String { internal(cnst).to_string() } @@ -254,6 +283,13 @@ impl<'tcx> Context for TablesWrapper<'tcx> { tables.types[ty].kind().stable(&mut *tables) } + fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> stable_mir::ty::Ty { + let mut tables = self.0.borrow_mut(); + let internal_kind = ty.internal(&mut *tables); + let internal_ty = tables.tcx.mk_ty_from_kind(internal_kind); + internal_ty.discriminant_ty(tables.tcx).stable(&mut *tables) + } + fn instance_body(&self, def: InstanceDef) -> Option<Body> { let mut tables = self.0.borrow_mut(); let instance = tables.instances[def]; @@ -286,9 +322,9 @@ impl<'tcx> Context for TablesWrapper<'tcx> { matches!(instance.def, ty::InstanceDef::DropGlue(_, None)) } - fn mono_instance(&self, item: stable_mir::CrateItem) -> stable_mir::mir::mono::Instance { + fn mono_instance(&self, def_id: stable_mir::DefId) -> stable_mir::mir::mono::Instance { let mut tables = self.0.borrow_mut(); - let def_id = tables[item.0]; + let def_id = tables[def_id]; Instance::mono(tables.tcx, def_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 165b8c50e70..0cea3fcc7f7 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -517,7 +517,7 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> { mir::AggregateKind::Adt(def_id, var_idx, generic_arg, user_ty_index, field_idx) => { stable_mir::mir::AggregateKind::Adt( tables.adt_def(*def_id), - var_idx.index(), + var_idx.stable(tables), generic_arg.stable(tables), user_ty_index.map(|idx| idx.index()), field_idx.map(|idx| idx.index()), diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs index edb32df305c..9c0b2b29bca 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs @@ -1,7 +1,7 @@ //! Conversion of internal Rust compiler items to stable ones. use rustc_target::abi::FieldIdx; -use stable_mir::mir::VariantIdx; +use stable_mir::ty::{IndexedVal, VariantIdx}; use crate::rustc_smir::{Stable, Tables}; @@ -25,17 +25,10 @@ impl<'tcx> Stable<'tcx> for FieldIdx { } } -impl<'tcx> Stable<'tcx> for (rustc_target::abi::VariantIdx, FieldIdx) { - type T = (usize, usize); - fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { - (self.0.as_usize(), self.1.as_usize()) - } -} - impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx { type T = VariantIdx; fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { - self.as_usize() + VariantIdx::to_val(self.as_usize()) } } @@ -67,6 +60,14 @@ impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind { } } +impl<'tcx> Stable<'tcx> for rustc_span::Symbol { + type T = stable_mir::Symbol; + + fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + self.to_string() + } +} + impl<'tcx> Stable<'tcx> for rustc_span::Span { type T = stable_mir::ty::Span; diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index f837f28e11e..4fe847c291c 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -137,6 +137,17 @@ impl<'tcx> Stable<'tcx> for ty::AdtKind { } } +impl<'tcx> Stable<'tcx> for ty::FieldDef { + type T = stable_mir::ty::FieldDef; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + stable_mir::ty::FieldDef { + def: tables.create_def_id(self.did), + name: self.name.stable(tables), + } + } +} + impl<'tcx> Stable<'tcx> for ty::GenericArgs<'tcx> { type T = stable_mir::ty::GenericArgs; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index eee587f3b2a..4cb48a12c96 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -141,3 +141,24 @@ where } } } + +impl<'tcx, T> Stable<'tcx> for &[T] +where + T: Stable<'tcx>, +{ + type T = Vec<T::T>; + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + self.iter().map(|e| e.stable(tables)).collect() + } +} + +impl<'tcx, T, U> Stable<'tcx> for (T, U) +where + T: Stable<'tcx>, + U: Stable<'tcx>, +{ + type T = (T::T, U::T); + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + (self.0.stable(tables), self.1.stable(tables)) + } +} diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d7e822382ef..5c1e703837a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -973,6 +973,7 @@ symbols! { managed_boxes, manually_drop, map, + map_err, marker, marker_trait_attr, masked, @@ -1137,6 +1138,7 @@ symbols! { offset, offset_of, offset_of_enum, + ok_or_else, omit_gdb_pretty_printer_section, on, on_unimplemented, @@ -1393,7 +1395,6 @@ symbols! { rustc_expected_cgu_reuse, rustc_has_incoherent_inherent_impls, rustc_hidden_type_of_opaques, - rustc_host, rustc_if_this_changed, rustc_inherit_overflow_checks, rustc_insignificant_dtor, @@ -2118,11 +2119,7 @@ impl Interner { return Symbol::new(idx as u32); } - // SAFETY: we convert from `&str` to `&[u8]`, clone it into the arena, - // and immediately convert the clone back to `&[u8]`, all because there - // is no `inner.arena.alloc_str()` method. This is clearly safe. - let string: &str = - unsafe { str::from_utf8_unchecked(inner.arena.alloc_slice(string.as_bytes())) }; + let string: &str = inner.arena.alloc_str(string); // SAFETY: we can extend the arena allocation to `'static` because we // only access these while the arena is still alive. diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 311b94d9e0e..8c035ba948b 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -93,7 +93,6 @@ #![allow(internal_features)] #![feature(never_type)] #![recursion_limit = "256"] -#![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 18ca347de97..e49d134659e 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -773,12 +773,7 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio let mut ty = ty; match ty.kind() { - ty::Float(..) - | ty::Char - | ty::Str - | ty::Never - | ty::Foreign(..) - | ty::CoroutineWitness(..) => {} + ty::Float(..) | ty::Str | ty::Never | ty::Foreign(..) | ty::CoroutineWitness(..) => {} ty::Bool => { if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { @@ -792,6 +787,14 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio } } + ty::Char => { + if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { + // Since #118032, char is guaranteed to have the same size, alignment, and function + // call ABI as u32 on all platforms. + ty = tcx.types.u32; + } + } + ty::Int(..) | ty::Uint(..) => { if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { // Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit wide. diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index dbce2f30f93..63002aa4aa4 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1637,6 +1637,7 @@ supported_targets! { ("riscv32imc-esp-espidf", riscv32imc_esp_espidf), ("riscv32imac-esp-espidf", riscv32imac_esp_espidf), ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf), + ("riscv32imafc-unknown-none-elf", riscv32imafc_unknown_none_elf), ("riscv32imac-unknown-xous-elf", riscv32imac_unknown_xous_elf), ("riscv32gc-unknown-linux-gnu", riscv32gc_unknown_linux_gnu), ("riscv32gc-unknown-linux-musl", riscv32gc_unknown_linux_musl), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs index eec2668d487..b490e80258c 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs @@ -4,7 +4,6 @@ pub fn target() -> Target { let mut base = base::teeos::opts(); base.features = "+strict-align,+neon,+fp-armv8".into(); base.max_atomic_width = Some(128); - base.linker = Some("aarch64-linux-gnu-ld".into()); Target { llvm_target: "aarch64-unknown-none".into(), diff --git a/compiler/rustc_target/src/spec/targets/i386_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/i386_unknown_linux_gnu.rs deleted file mode 100644 index 801a8893399..00000000000 --- a/compiler/rustc_target/src/spec/targets/i386_unknown_linux_gnu.rs +++ /dev/null @@ -1,8 +0,0 @@ -use crate::spec::Target; - -pub fn target() -> Target { - let mut base = super::i686_unknown_linux_gnu::target(); - base.cpu = "i386".into(); - base.llvm_target = "i386-unknown-linux-gnu".into(); - base -} diff --git a/compiler/rustc_target/src/spec/targets/i486_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/i486_unknown_linux_gnu.rs deleted file mode 100644 index a11fbecc3c3..00000000000 --- a/compiler/rustc_target/src/spec/targets/i486_unknown_linux_gnu.rs +++ /dev/null @@ -1,8 +0,0 @@ -use crate::spec::Target; - -pub fn target() -> Target { - let mut base = super::i686_unknown_linux_gnu::target(); - base.cpu = "i486".into(); - base.llvm_target = "i486-unknown-linux-gnu".into(); - base -} diff --git a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs index a263e5d5cde..ed0591ad918 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imac_unknown_xous_elf.rs @@ -14,7 +14,7 @@ pub fn target() -> Target { cpu: "generic-rv32".into(), max_atomic_width: Some(32), features: "+m,+a,+c".into(), - panic_strategy: PanicStrategy::Abort, + panic_strategy: PanicStrategy::Unwind, relocation_model: RelocModel::Static, ..Default::default() }, diff --git a/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs new file mode 100644 index 00000000000..9fb68874ac8 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/riscv32imafc_unknown_none_elf.rs @@ -0,0 +1,24 @@ +use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(), + llvm_target: "riscv32".into(), + pointer_width: 32, + arch: "riscv32".into(), + + options: TargetOptions { + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + cpu: "generic-rv32".into(), + max_atomic_width: Some(32), + llvm_abiname: "ilp32f".into(), + features: "+m,+a,+c,+f".into(), + panic_strategy: PanicStrategy::Abort, + relocation_model: RelocModel::Static, + emit_debug_gdb_scripts: false, + eh_frame_header: false, + ..Default::default() + }, + } +} diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 38153cccfdd..4b11cc3ace9 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -1,8 +1,10 @@ +use crate::solve::FulfillmentCtxt; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::{self, DefiningAnchor, ObligationCtxt}; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; +use rustc_infer::traits::{TraitEngine, TraitEngineExt}; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryResponse}; use rustc_middle::traits::query::NoSolution; @@ -27,7 +29,7 @@ pub trait InferCtxtExt<'tcx> { /// - the parameter environment /// /// Invokes `evaluate_obligation`, so in the event that evaluating - /// `Ty: Trait` causes overflow, EvaluatedToRecur (or EvaluatedToUnknown) + /// `Ty: Trait` causes overflow, EvaluatedToErrStackDependent (or EvaluatedToAmbigStackDependent) /// will be returned. fn type_implements_trait( &self, @@ -35,6 +37,13 @@ pub trait InferCtxtExt<'tcx> { params: impl IntoIterator<Item: Into<GenericArg<'tcx>>>, param_env: ty::ParamEnv<'tcx>, ) -> traits::EvaluationResult; + + fn could_impl_trait( + &self, + trait_def_id: DefId, + ty: Ty<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> Option<Vec<traits::FulfillmentError<'tcx>>>; } impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { @@ -76,6 +85,69 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { }; self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr) } + + fn could_impl_trait( + &self, + trait_def_id: DefId, + ty: Ty<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> Option<Vec<traits::FulfillmentError<'tcx>>> { + self.probe(|_snapshot| { + if let ty::Adt(def, args) = ty.kind() + && let Some((impl_def_id, _)) = self + .tcx + .all_impls(trait_def_id) + .filter_map(|impl_def_id| { + self.tcx.impl_trait_ref(impl_def_id).map(|r| (impl_def_id, r)) + }) + .map(|(impl_def_id, imp)| (impl_def_id, imp.skip_binder())) + .filter(|(_, imp)| match imp.self_ty().peel_refs().kind() { + ty::Adt(i_def, _) if i_def.did() == def.did() => true, + _ => false, + }) + .next() + { + let mut fulfill_cx = FulfillmentCtxt::new(self); + // We get all obligations from the impl to talk about specific + // trait bounds. + let obligations = self + .tcx + .predicates_of(impl_def_id) + .instantiate(self.tcx, args) + .into_iter() + .map(|(clause, span)| { + traits::Obligation::new( + self.tcx, + traits::ObligationCause::dummy_with_span(span), + param_env, + clause, + ) + }) + .collect::<Vec<_>>(); + fulfill_cx.register_predicate_obligations(self, obligations); + let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty]); + let obligation = traits::Obligation::new( + self.tcx, + traits::ObligationCause::dummy(), + param_env, + trait_ref, + ); + fulfill_cx.register_predicate_obligation(self, obligation); + let mut errors = fulfill_cx.select_all_or_error(self); + // We remove the last predicate failure, which corresponds to + // the top-level obligation, because most of the type we only + // care about the other ones, *except* when it is the only one. + // This seems to only be relevant for arbitrary self-types. + // Look at `tests/ui/moves/move-fn-self-receiver.rs`. + if errors.len() > 1 { + errors.truncate(errors.len() - 1); + } + Some(errors) + } else { + None + } + }) + } } pub trait InferCtxtBuilderExt<'tcx> { diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index b9e256236e9..bf3b72caeb4 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -41,7 +41,9 @@ mod trait_goals; pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt}; pub use fulfill::FulfillmentCtxt; -pub(crate) use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; +pub(crate) use normalize::{ + deeply_normalize, deeply_normalize_for_diagnostics, deeply_normalize_with_skipped_universes, +}; #[derive(Debug, Clone, Copy)] enum SolverMode { diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index b0a34898570..ea512ba5fa7 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -4,12 +4,13 @@ use crate::traits::{needs_normalization, BoundVarReplacer, PlaceholderReplacer}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::infer::at::At; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::InferCtxt; use rustc_infer::traits::TraitEngineExt; use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::traits::Reveal; +use rustc_middle::traits::{ObligationCause, Reveal}; use rustc_middle::ty::{self, AliasTy, Ty, TyCtxt, UniverseIndex}; -use rustc_middle::ty::{FallibleTypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{TypeFoldable, TypeVisitableExt}; use super::FulfillmentCtxt; @@ -230,3 +231,42 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> { } } } + +// Deeply normalize a value and return it +pub(crate) fn deeply_normalize_for_diagnostics<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( + infcx: &InferCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + t: T, +) -> T { + t.fold_with(&mut DeeplyNormalizeForDiagnosticsFolder { + at: infcx.at(&ObligationCause::dummy(), param_env), + }) +} + +struct DeeplyNormalizeForDiagnosticsFolder<'a, 'tcx> { + at: At<'a, 'tcx>, +} + +impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_, 'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.at.infcx.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + deeply_normalize_with_skipped_universes( + self.at, + ty, + vec![None; ty.outer_exclusive_binder().as_usize()], + ) + .unwrap_or_else(|_| ty.super_fold_with(self)) + } + + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + deeply_normalize_with_skipped_universes( + self.at, + ct, + vec![None; ct.outer_exclusive_binder().as_usize()], + ) + .unwrap_or_else(|_| ct.super_fold_with(self)) + } +} diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 8e97333ad0f..db4d4a93e54 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -6,8 +6,8 @@ use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::InferOk; -use crate::solve::inspect; use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor}; +use crate::solve::{deeply_normalize_for_diagnostics, inspect}; use crate::traits::engine::TraitEngineExt; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs}; @@ -245,7 +245,7 @@ fn overlap<'tcx>( let trait_ref = infcx.resolve_vars_if_possible(trait_ref); format!( "of `{}` for `{}`", - trait_ref.print_only_trait_path(), + trait_ref.print_trait_sugared(), trait_ref.self_ty() ) } @@ -308,7 +308,13 @@ fn overlap<'tcx>( .iter() .any(|c| c.0.involves_placeholders()); - let impl_header = selcx.infcx.resolve_vars_if_possible(impl1_header); + let mut impl_header = infcx.resolve_vars_if_possible(impl1_header); + + // Deeply normalize the impl header for diagnostics, ignoring any errors if this fails. + if infcx.next_trait_solver() { + impl_header = deeply_normalize_for_diagnostics(&infcx, param_env, impl_header); + } + Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder }) } @@ -1084,6 +1090,10 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> { Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"), Ok(Err(conflict)) => { if !trait_ref.references_error() { + // Normalize the trait ref for diagnostics, ignoring any errors if this fails. + let trait_ref = + deeply_normalize_for_diagnostics(infcx, param_env, trait_ref); + let self_ty = trait_ref.self_ty(); let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty); ambiguity_cause = Some(match conflict { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index fbe6e2bd5b8..c07db12b25b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -184,14 +184,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { flags.push((sym::cause, Some("MainFunctionType".to_string()))); } - if let Some(kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id) - && let ty::Tuple(args) = trait_ref.args.type_at(1).kind() - { - let args = args.iter().map(|ty| ty.to_string()).collect::<Vec<_>>().join(", "); - flags.push((sym::Trait, Some(format!("{}({args})", kind.as_str())))); - } else { - flags.push((sym::Trait, Some(trait_ref.print_only_trait_path().to_string()))); - } + flags.push((sym::Trait, Some(trait_ref.print_trait_sugared().to_string()))); // Add all types without trimmed paths or visible paths, ensuring they end up with // their "canonical" def path. diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index b3910a2770b..090706070eb 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -3,6 +3,7 @@ use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch}; use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use crate::infer::InferCtxtExt as _; use crate::infer::{self, InferCtxt}; use crate::traits::error_reporting::infer_ctxt_ext::InferCtxtExt; use crate::traits::error_reporting::{ambiguity, ambiguity::Ambiguity::*}; @@ -40,7 +41,7 @@ use rustc_session::config::{DumpSolverProofTree, TraitSolver}; use rustc_session::Limit; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::symbol::sym; -use rustc_span::{ExpnKind, Span, DUMMY_SP}; +use rustc_span::{BytePos, ExpnKind, Span, Symbol, DUMMY_SP}; use std::borrow::Cow; use std::fmt; use std::iter; @@ -106,6 +107,13 @@ pub trait TypeErrCtxtExt<'tcx> { fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool; + fn try_conversion_context( + &self, + obligation: &PredicateObligation<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + err: &mut Diagnostic, + ) -> bool; + fn report_const_param_not_wf( &self, ty: Ty<'tcx>, @@ -509,6 +517,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut err = struct_span_err!(self.tcx.sess, span, E0277, "{}", err_msg); + let mut suggested = false; + if is_try_conversion { + suggested = self.try_conversion_context(&obligation, trait_ref.skip_binder(), &mut err); + } + if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) { err.span_label( ret_span, @@ -609,8 +622,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref); self.suggest_dereferencing_index(&obligation, &mut err, trait_predicate); - let mut suggested = - self.suggest_dereferences(&obligation, &mut err, trait_predicate); + suggested |= self.suggest_dereferences(&obligation, &mut err, trait_predicate); suggested |= self.suggest_fn_call(&obligation, &mut err, trait_predicate); let impl_candidates = self.find_similar_impl_candidates(trait_predicate); suggested = if let &[cand] = &impl_candidates[..] { @@ -622,7 +634,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span.shrink_to_hi(), format!( "the trait `{}` is implemented for fn pointer `{}`, try casting using `as`", - cand.print_only_trait_path(), + cand.print_trait_sugared(), cand.self_ty(), ), format!(" as {}", cand.self_ty()), @@ -982,6 +994,223 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { false } + /// When the `E` of the resulting `Result<T, E>` in an expression `foo().bar().baz()?`, + /// identify thoe method chain sub-expressions that could or could not have been annotated + /// with `?`. + fn try_conversion_context( + &self, + obligation: &PredicateObligation<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + err: &mut Diagnostic, + ) -> bool { + let span = obligation.cause.span; + struct V<'v> { + search_span: Span, + found: Option<&'v hir::Expr<'v>>, + } + impl<'v> Visitor<'v> for V<'v> { + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + if let hir::ExprKind::Match(expr, _arms, hir::MatchSource::TryDesugar(_)) = ex.kind + { + if ex.span.with_lo(ex.span.hi() - BytePos(1)).source_equal(self.search_span) { + if let hir::ExprKind::Call(_, [expr, ..]) = expr.kind { + self.found = Some(expr); + return; + } + } + } + hir::intravisit::walk_expr(self, ex); + } + } + let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id); + let body_id = match self.tcx.hir().find(hir_id) { + Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) => { + body_id + } + _ => return false, + }; + let mut v = V { search_span: span, found: None }; + v.visit_body(self.tcx.hir().body(*body_id)); + let Some(expr) = v.found else { + return false; + }; + let Some(typeck) = &self.typeck_results else { + return false; + }; + let Some((ObligationCauseCode::QuestionMark, Some(y))) = obligation.cause.code().parent() + else { + return false; + }; + if !self.tcx.is_diagnostic_item(sym::FromResidual, y.def_id()) { + return false; + } + let self_ty = trait_ref.self_ty(); + let found_ty = trait_ref.args.get(1).and_then(|a| a.as_type()); + + let mut prev_ty = self.resolve_vars_if_possible( + typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), + ); + + // We always look at the `E` type, because that's the only one affected by `?`. If the + // incorrect `Result<T, E>` is because of the `T`, we'll get an E0308 on the whole + // expression, after the `?` has "unwrapped" the `T`. + let get_e_type = |prev_ty: Ty<'tcx>| -> Option<Ty<'tcx>> { + let ty::Adt(def, args) = prev_ty.kind() else { + return None; + }; + let Some(arg) = args.get(1) else { + return None; + }; + if !self.tcx.is_diagnostic_item(sym::Result, def.did()) { + return None; + } + Some(arg.as_type()?) + }; + + let mut suggested = false; + let mut chain = vec![]; + + // The following logic is simlar to `point_at_chain`, but that's focused on associated types + let mut expr = expr; + while let hir::ExprKind::MethodCall(path_segment, rcvr_expr, args, span) = expr.kind { + // Point at every method call in the chain with the `Result` type. + // let foo = bar.iter().map(mapper)?; + // ------ ----------- + expr = rcvr_expr; + chain.push((span, prev_ty)); + + let next_ty = self.resolve_vars_if_possible( + typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), + ); + + let is_diagnostic_item = |symbol: Symbol, ty: Ty<'tcx>| { + let ty::Adt(def, _) = ty.kind() else { + return false; + }; + self.tcx.is_diagnostic_item(symbol, def.did()) + }; + // For each method in the chain, see if this is `Result::map_err` or + // `Option::ok_or_else` and if it is, see if the closure passed to it has an incorrect + // trailing `;`. + if let Some(ty) = get_e_type(prev_ty) + && let Some(found_ty) = found_ty + // Ideally we would instead use `FnCtxt::lookup_method_for_diagnostic` for 100% + // accurate check, but we are in the wrong stage to do that and looking for + // `Result::map_err` by checking the Self type and the path segment is enough. + // sym::ok_or_else + && ( + ( // Result::map_err + path_segment.ident.name == sym::map_err + && is_diagnostic_item(sym::Result, next_ty) + ) || ( // Option::ok_or_else + path_segment.ident.name == sym::ok_or_else + && is_diagnostic_item(sym::Option, next_ty) + ) + ) + // Found `Result<_, ()>?` + && let ty::Tuple(tys) = found_ty.kind() + && tys.is_empty() + // The current method call returns `Result<_, ()>` + && self.can_eq(obligation.param_env, ty, found_ty) + // There's a single argument in the method call and it is a closure + && args.len() == 1 + && let Some(arg) = args.get(0) + && let hir::ExprKind::Closure(closure) = arg.kind + // The closure has a block for its body with no tail expression + && let body = self.tcx.hir().body(closure.body) + && let hir::ExprKind::Block(block, _) = body.value.kind + && let None = block.expr + // The last statement is of a type that can be converted to the return error type + && let [.., stmt] = block.stmts + && let hir::StmtKind::Semi(expr) = stmt.kind + && let expr_ty = self.resolve_vars_if_possible( + typeck.expr_ty_adjusted_opt(expr) + .unwrap_or(Ty::new_misc_error(self.tcx)), + ) + && self + .infcx + .type_implements_trait( + self.tcx.get_diagnostic_item(sym::From).unwrap(), + [self_ty, expr_ty], + obligation.param_env, + ) + .must_apply_modulo_regions() + { + suggested = true; + err.span_suggestion_short( + stmt.span.with_lo(expr.span.hi()), + "remove this semicolon", + String::new(), + Applicability::MachineApplicable, + ); + } + + prev_ty = next_ty; + + if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind + && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path + && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id) + && let Some(parent) = self.tcx.hir().find_parent(binding.hir_id) + { + // We've reached the root of the method call chain... + if let hir::Node::Local(local) = parent + && let Some(binding_expr) = local.init + { + // ...and it is a binding. Get the binding creation and continue the chain. + expr = binding_expr; + } + if let hir::Node::Param(_param) = parent { + // ...and it is a an fn argument. + break; + } + } + } + // `expr` is now the "root" expression of the method call chain, which can be any + // expression kind, like a method call or a path. If this expression is `Result<T, E>` as + // well, then we also point at it. + prev_ty = self.resolve_vars_if_possible( + typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), + ); + chain.push((expr.span, prev_ty)); + + let mut prev = None; + for (span, err_ty) in chain.into_iter().rev() { + let err_ty = get_e_type(err_ty); + let err_ty = match (err_ty, prev) { + (Some(err_ty), Some(prev)) if !self.can_eq(obligation.param_env, err_ty, prev) => { + err_ty + } + (Some(err_ty), None) => err_ty, + _ => { + prev = err_ty; + continue; + } + }; + if self + .infcx + .type_implements_trait( + self.tcx.get_diagnostic_item(sym::From).unwrap(), + [self_ty, err_ty], + obligation.param_env, + ) + .must_apply_modulo_regions() + { + if !suggested { + err.span_label(span, format!("this has type `Result<_, {err_ty}>`")); + } + } else { + err.span_label( + span, + format!( + "this can't be annotated with `?` because it has type `Result<_, {err_ty}>`", + ), + ); + } + prev = Some(err_ty); + } + suggested + } + fn report_const_param_not_wf( &self, ty: Ty<'tcx>, @@ -1785,7 +2014,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()), }); err.highlighted_help(vec![ - (format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle), + (format!("the trait `{}` ", cand.print_trait_sugared()), Style::NoStyle), ("is".to_string(), Style::Highlight), (" implemented for `".to_string(), Style::NoStyle), (cand.self_ty().to_string(), Style::Highlight), @@ -1821,7 +2050,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { _ => (" implemented for `", ""), }; err.highlighted_help(vec![ - (format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle), + (format!("the trait `{}` ", cand.print_trait_sugared()), Style::NoStyle), ("is".to_string(), Style::Highlight), (desc.to_string(), Style::NoStyle), (cand.self_ty().to_string(), Style::Highlight), @@ -1854,7 +2083,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let end = if candidates.len() <= 9 { candidates.len() } else { 8 }; err.help(format!( "the following {other}types implement trait `{}`:{}{}", - trait_ref.print_only_trait_path(), + trait_ref.print_trait_sugared(), candidates[..end].join(""), if candidates.len() > 9 { format!("\nand {} others", candidates.len() - 8) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 45bdff09dee..5b0829b5732 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -2076,7 +2076,7 @@ fn confirm_coroutine_candidate<'cx, 'tcx>( else { unreachable!() }; - let coroutine_sig = args.as_coroutine().poly_sig(); + let coroutine_sig = args.as_coroutine().sig(); let Normalized { value: coroutine_sig, obligations } = normalize_with_depth( selcx, obligation.param_env, @@ -2091,29 +2091,28 @@ fn confirm_coroutine_candidate<'cx, 'tcx>( let coroutine_def_id = tcx.require_lang_item(LangItem::Coroutine, None); - let predicate = super::util::coroutine_trait_ref_and_outputs( + let (trait_ref, yield_ty, return_ty) = super::util::coroutine_trait_ref_and_outputs( tcx, coroutine_def_id, obligation.predicate.self_ty(), coroutine_sig, - ) - .map_bound(|(trait_ref, yield_ty, return_ty)| { - let name = tcx.associated_item(obligation.predicate.def_id).name; - let ty = if name == sym::Return { - return_ty - } else if name == sym::Yield { - yield_ty - } else { - bug!() - }; + ); - ty::ProjectionPredicate { - projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args), - term: ty.into(), - } - }); + let name = tcx.associated_item(obligation.predicate.def_id).name; + let ty = if name == sym::Return { + return_ty + } else if name == sym::Yield { + yield_ty + } else { + bug!() + }; + + let predicate = ty::ProjectionPredicate { + projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args), + term: ty.into(), + }; - confirm_param_env_candidate(selcx, obligation, predicate, false) + confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) .with_addl_obligations(nested) .with_addl_obligations(obligations) } @@ -2128,7 +2127,7 @@ fn confirm_future_candidate<'cx, 'tcx>( else { unreachable!() }; - let coroutine_sig = args.as_coroutine().poly_sig(); + let coroutine_sig = args.as_coroutine().sig(); let Normalized { value: coroutine_sig, obligations } = normalize_with_depth( selcx, obligation.param_env, @@ -2142,22 +2141,21 @@ fn confirm_future_candidate<'cx, 'tcx>( let tcx = selcx.tcx(); let fut_def_id = tcx.require_lang_item(LangItem::Future, None); - let predicate = super::util::future_trait_ref_and_outputs( + let (trait_ref, return_ty) = super::util::future_trait_ref_and_outputs( tcx, fut_def_id, obligation.predicate.self_ty(), coroutine_sig, - ) - .map_bound(|(trait_ref, return_ty)| { - debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output); + ); - ty::ProjectionPredicate { - projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args), - term: return_ty.into(), - } - }); + debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output); + + let predicate = ty::ProjectionPredicate { + projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args), + term: return_ty.into(), + }; - confirm_param_env_candidate(selcx, obligation, predicate, false) + confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) .with_addl_obligations(nested) .with_addl_obligations(obligations) } @@ -2172,7 +2170,7 @@ fn confirm_iterator_candidate<'cx, 'tcx>( else { unreachable!() }; - let gen_sig = args.as_coroutine().poly_sig(); + let gen_sig = args.as_coroutine().sig(); let Normalized { value: gen_sig, obligations } = normalize_with_depth( selcx, obligation.param_env, @@ -2186,22 +2184,21 @@ fn confirm_iterator_candidate<'cx, 'tcx>( let tcx = selcx.tcx(); let iter_def_id = tcx.require_lang_item(LangItem::Iterator, None); - let predicate = super::util::iterator_trait_ref_and_outputs( + let (trait_ref, yield_ty) = super::util::iterator_trait_ref_and_outputs( tcx, iter_def_id, obligation.predicate.self_ty(), gen_sig, - ) - .map_bound(|(trait_ref, yield_ty)| { - debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item); + ); - ty::ProjectionPredicate { - projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args), - term: yield_ty.into(), - } - }); + debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item); - confirm_param_env_candidate(selcx, obligation, predicate, false) + let predicate = ty::ProjectionPredicate { + projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args), + term: yield_ty.into(), + }; + + confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) .with_addl_obligations(nested) .with_addl_obligations(obligations) } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index a33160b7c43..fc4f6f37621 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -731,7 +731,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligation, ?coroutine_def_id, ?args, "confirm_coroutine_candidate"); - let coroutine_sig = args.as_coroutine().poly_sig(); + let coroutine_sig = args.as_coroutine().sig(); // NOTE: The self-type is a coroutine type and hence is // in fact unparameterized (or at least does not reference any @@ -742,15 +742,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .no_bound_vars() .expect("unboxed closure type should not capture bound vars from the predicate"); - let trait_ref = super::util::coroutine_trait_ref_and_outputs( + let (trait_ref, _, _) = super::util::coroutine_trait_ref_and_outputs( self.tcx(), obligation.predicate.def_id(), self_ty, coroutine_sig, - ) - .map_bound(|(trait_ref, ..)| trait_ref); + ); - let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?; debug!(?trait_ref, ?nested, "coroutine candidate obligations"); Ok(nested) @@ -770,17 +769,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligation, ?coroutine_def_id, ?args, "confirm_future_candidate"); - let coroutine_sig = args.as_coroutine().poly_sig(); + let coroutine_sig = args.as_coroutine().sig(); - let trait_ref = super::util::future_trait_ref_and_outputs( + let (trait_ref, _) = super::util::future_trait_ref_and_outputs( self.tcx(), obligation.predicate.def_id(), obligation.predicate.no_bound_vars().expect("future has no bound vars").self_ty(), coroutine_sig, - ) - .map_bound(|(trait_ref, ..)| trait_ref); + ); - let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?; debug!(?trait_ref, ?nested, "future candidate obligations"); Ok(nested) @@ -800,17 +798,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligation, ?coroutine_def_id, ?args, "confirm_iterator_candidate"); - let gen_sig = args.as_coroutine().poly_sig(); + let gen_sig = args.as_coroutine().sig(); - let trait_ref = super::util::iterator_trait_ref_and_outputs( + let (trait_ref, _) = super::util::iterator_trait_ref_and_outputs( self.tcx(), obligation.predicate.def_id(), obligation.predicate.no_bound_vars().expect("iterator has no bound vars").self_ty(), gen_sig, - ) - .map_bound(|(trait_ref, ..)| trait_ref); + ); - let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?; debug!(?trait_ref, ?nested, "iterator candidate obligations"); Ok(nested) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index b26c781100a..0d3ec41f511 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -78,7 +78,7 @@ impl<'tcx> IntercrateAmbiguityCause<'tcx> { IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty } => { format!( "downstream crates may implement trait `{trait_desc}`{self_desc}", - trait_desc = trait_ref.print_only_trait_path(), + trait_desc = trait_ref.print_trait_sugared(), self_desc = if let Some(self_ty) = self_ty { format!(" for type `{self_ty}`") } else { @@ -90,7 +90,7 @@ impl<'tcx> IntercrateAmbiguityCause<'tcx> { format!( "upstream crates may add a new impl of trait `{trait_desc}`{self_desc} \ in future versions", - trait_desc = trait_ref.print_only_trait_path(), + trait_desc = trait_ref.print_trait_sugared(), self_desc = if let Some(self_ty) = self_ty { format!(" for type `{self_ty}`") } else { @@ -222,8 +222,8 @@ pub enum TreatInductiveCycleAs { impl From<TreatInductiveCycleAs> for EvaluationResult { fn from(treat: TreatInductiveCycleAs) -> EvaluationResult { match treat { - TreatInductiveCycleAs::Ambig => EvaluatedToUnknown, - TreatInductiveCycleAs::Recur => EvaluatedToRecur, + TreatInductiveCycleAs::Ambig => EvaluatedToAmbigStackDependent, + TreatInductiveCycleAs::Recur => EvaluatedToErrStackDependent, } } } @@ -1231,7 +1231,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) { debug!("evaluate_stack --> unbound argument, recursive --> giving up",); - return Ok(EvaluatedToUnknown); + return Ok(EvaluatedToAmbigStackDependent); } match self.candidate_from_obligation(stack) { diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 56f5057608f..39f5ff52eba 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -412,7 +412,7 @@ fn report_conflicting_impls<'tcx>( let msg = DelayDm(|| { format!( "conflicting implementations of trait `{}`{}{}", - overlap.trait_ref.print_only_trait_path(), + overlap.trait_ref.print_trait_sugared(), overlap.self_ty.map_or_else(String::new, |ty| format!(" for type `{ty}`")), match used_to_be_allowed { Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)", diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index bbde0c82743..5574badf238 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -279,33 +279,33 @@ pub fn coroutine_trait_ref_and_outputs<'tcx>( tcx: TyCtxt<'tcx>, fn_trait_def_id: DefId, self_ty: Ty<'tcx>, - sig: ty::PolyGenSig<'tcx>, -) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> { + sig: ty::GenSig<'tcx>, +) -> (ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>) { assert!(!self_ty.has_escaping_bound_vars()); - let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, sig.skip_binder().resume_ty]); - sig.map_bound(|sig| (trait_ref, sig.yield_ty, sig.return_ty)) + let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, sig.resume_ty]); + (trait_ref, sig.yield_ty, sig.return_ty) } pub fn future_trait_ref_and_outputs<'tcx>( tcx: TyCtxt<'tcx>, fn_trait_def_id: DefId, self_ty: Ty<'tcx>, - sig: ty::PolyGenSig<'tcx>, -) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> { + sig: ty::GenSig<'tcx>, +) -> (ty::TraitRef<'tcx>, Ty<'tcx>) { assert!(!self_ty.has_escaping_bound_vars()); let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty]); - sig.map_bound(|sig| (trait_ref, sig.return_ty)) + (trait_ref, sig.return_ty) } pub fn iterator_trait_ref_and_outputs<'tcx>( tcx: TyCtxt<'tcx>, iterator_def_id: DefId, self_ty: Ty<'tcx>, - sig: ty::PolyGenSig<'tcx>, -) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> { + sig: ty::GenSig<'tcx>, +) -> (ty::TraitRef<'tcx>, Ty<'tcx>) { assert!(!self_ty.has_escaping_bound_vars()); let trait_ref = ty::TraitRef::new(tcx, iterator_def_id, [self_ty]); - sig.map_bound(|sig| (trait_ref, sig.yield_ty)) + (trait_ref, sig.yield_ty) } pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 3a890d70d79..0f8d9c6bf4b 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -761,18 +761,15 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let defer_to_coercion = self.tcx().features().object_safe_for_dispatch; if !defer_to_coercion { - let cause = self.cause(traits::WellFormed(None)); - let component_traits = data.auto_traits().chain(data.principal_def_id()); - let tcx = self.tcx(); - self.out.extend(component_traits.map(|did| { - traits::Obligation::with_depth( - tcx, - cause.clone(), + if let Some(principal) = data.principal_def_id() { + self.out.push(traits::Obligation::with_depth( + self.tcx(), + self.cause(traits::WellFormed(None)), depth, param_env, - ty::Binder::dummy(ty::PredicateKind::ObjectSafe(did)), - ) - })); + ty::Binder::dummy(ty::PredicateKind::ObjectSafe(principal)), + )); + } } } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index b28e3d5c412..a58e98ce99c 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -99,11 +99,11 @@ fn fn_sig_for_fn_abi<'tcx>( } ty::Coroutine(did, args, _) => { let coroutine_kind = tcx.coroutine_kind(did).unwrap(); - let sig = args.as_coroutine().poly_sig(); + let sig = args.as_coroutine().sig(); - let bound_vars = tcx.mk_bound_variable_kinds_from_iter( - sig.bound_vars().iter().chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))), - ); + let bound_vars = tcx.mk_bound_variable_kinds_from_iter(iter::once( + ty::BoundVariableKind::Region(ty::BrEnv), + )); let br = ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind: ty::BoundRegionKind::BrEnv, @@ -124,7 +124,6 @@ fn fn_sig_for_fn_abi<'tcx>( } }; - let sig = sig.skip_binder(); // The `FnSig` and the `ret_ty` here is for a coroutines main // `Coroutine::resume(...) -> CoroutineState` function in case we // have an ordinary coroutine, the `Future::poll(...) -> Poll` diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index daf4465963e..7916d04250d 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -9,9 +9,9 @@ use crate::mir::alloc::{AllocId, GlobalAlloc}; use crate::mir::mono::{Instance, InstanceDef, StaticDef}; use crate::mir::Body; use crate::ty::{ - AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FnDef, GenericArgs, + AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs, GenericPredicates, Generics, ImplDef, ImplTrait, LineInfo, PolyFnSig, RigidTy, Span, TraitDecl, - TraitDef, Ty, TyKind, + TraitDef, Ty, TyKind, VariantDef, }; use crate::{ mir, Crate, CrateItem, CrateItems, DefId, Error, Filename, ImplTraitDecls, ItemKind, Symbol, @@ -60,7 +60,7 @@ pub trait Context { fn item_kind(&self, item: CrateItem) -> ItemKind; /// Returns whether this is a foreign item. - fn is_foreign_item(&self, item: CrateItem) -> bool; + fn is_foreign_item(&self, item: DefId) -> bool; /// Returns the kind of a given algebraic data type fn adt_kind(&self, def: AdtDef) -> AdtKind; @@ -71,6 +71,13 @@ pub trait Context { /// Retrieve the function signature for the given generic arguments. fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig; + /// The number of variants in this ADT. + fn adt_variants_len(&self, def: AdtDef) -> usize; + + /// The name of a variant. + fn variant_name(&self, def: VariantDef) -> Symbol; + fn variant_fields(&self, def: VariantDef) -> Vec<FieldDef>; + /// Evaluate constant as a target usize. fn eval_target_usize(&self, cnst: &Const) -> Result<u64, Error>; @@ -80,9 +87,15 @@ pub trait Context { /// Create a new type from the given kind. fn new_rigid_ty(&self, kind: RigidTy) -> Ty; + /// Create a new box type, `Box<T>`, for the given inner type `T`. + fn new_box_ty(&self, ty: Ty) -> Ty; + /// Returns the type of given crate item. fn def_ty(&self, item: DefId) -> Ty; + /// Returns the type of given definition instantiated with the given arguments. + fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty; + /// Returns literal value of a const as a string. fn const_literal(&self, cnst: &Const) -> String; @@ -92,6 +105,9 @@ pub trait Context { /// Obtain the representation of a type. fn ty_kind(&self, ty: Ty) -> TyKind; + // Get the discriminant Ty for this Ty if there's one. + fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> Ty; + /// Get the body of an Instance which is already monomorphized. fn instance_body(&self, instance: InstanceDef) -> Option<Body>; @@ -109,7 +125,7 @@ pub trait Context { /// Convert a non-generic crate item into an instance. /// This function will panic if the item is generic. - fn mono_instance(&self, item: CrateItem) -> Instance; + fn mono_instance(&self, def_id: DefId) -> Instance; /// Item requires monomorphization. fn requires_monomorphization(&self, def_id: DefId) -> bool; diff --git a/compiler/stable_mir/src/error.rs b/compiler/stable_mir/src/error.rs index 1ff65717e87..bb5e1a34180 100644 --- a/compiler/stable_mir/src/error.rs +++ b/compiler/stable_mir/src/error.rs @@ -28,7 +28,7 @@ pub enum CompilerError<T> { } /// A generic error to represent an API request that cannot be fulfilled. -#[derive(Debug)] +#[derive(Clone, Debug, Eq, PartialEq)] pub struct Error(pub(crate) String); impl Error { diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index 2099c485c6f..1e7495009d8 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -120,7 +120,7 @@ impl CrateItem { } pub fn is_foreign_item(&self) -> bool { - with(|cx| cx.is_foreign_item(*self)) + with(|cx| cx.is_foreign_item(self.0)) } pub fn dump<W: io::Write>(&self, w: &mut W) -> io::Result<()> { diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 3a4f4283562..90bd7aa7d18 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -1,6 +1,7 @@ use crate::mir::pretty::{function_body, pretty_statement, pretty_terminator}; use crate::ty::{ AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind, + VariantIdx, }; use crate::{Error, Opaque, Span, Symbol}; use std::io; @@ -9,17 +10,17 @@ use std::io; pub struct Body { pub blocks: Vec<BasicBlock>, - // Declarations of locals within the function. - // - // The first local is the return value pointer, followed by `arg_count` - // locals for the function arguments, followed by any user-declared - // variables and temporaries. + /// Declarations of locals within the function. + /// + /// The first local is the return value pointer, followed by `arg_count` + /// locals for the function arguments, followed by any user-declared + /// variables and temporaries. pub(super) locals: LocalDecls, - // The number of arguments this function takes. + /// The number of arguments this function takes. pub(super) arg_count: usize, - // Debug information pertaining to user variables, including captures. + /// Debug information pertaining to user variables, including captures. pub(super) var_debug_info: Vec<VarDebugInfo>, } @@ -69,6 +70,11 @@ impl Body { &self.locals } + /// Get the local declaration for this local. + pub fn local_decl(&self, local: Local) -> Option<&LocalDecl> { + self.locals.get(local) + } + pub fn dump<W: io::Write>(&self, w: &mut W) -> io::Result<()> { writeln!(w, "{}", function_body(self))?; self.blocks @@ -268,6 +274,38 @@ pub enum BinOp { Offset, } +impl BinOp { + /// Return the type of this operation for the given input Ty. + /// This function does not perform type checking, and it currently doesn't handle SIMD. + pub fn ty(&self, lhs_ty: Ty, rhs_ty: Ty) -> Ty { + assert!(lhs_ty.kind().is_primitive()); + assert!(rhs_ty.kind().is_primitive()); + match self { + BinOp::Add + | BinOp::AddUnchecked + | BinOp::Sub + | BinOp::SubUnchecked + | BinOp::Mul + | BinOp::MulUnchecked + | BinOp::Div + | BinOp::Rem + | BinOp::BitXor + | BinOp::BitAnd + | BinOp::BitOr => { + assert_eq!(lhs_ty, rhs_ty); + lhs_ty + } + BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked | BinOp::Offset => { + lhs_ty + } + BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => { + assert_eq!(lhs_ty, rhs_ty); + Ty::bool_ty() + } + } + } +} + #[derive(Clone, Debug, Eq, PartialEq)] pub enum UnOp { Not, @@ -469,6 +507,63 @@ pub enum Rvalue { Use(Operand), } +impl Rvalue { + pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> { + match self { + Rvalue::Use(operand) => operand.ty(locals), + Rvalue::Repeat(operand, count) => { + Ok(Ty::new_array_with_const_len(operand.ty(locals)?, count.clone())) + } + Rvalue::ThreadLocalRef(did) => Ok(did.ty()), + Rvalue::Ref(reg, bk, place) => { + let place_ty = place.ty(locals)?; + Ok(Ty::new_ref(reg.clone(), place_ty, bk.to_mutable_lossy())) + } + Rvalue::AddressOf(mutability, place) => { + let place_ty = place.ty(locals)?; + Ok(Ty::new_ptr(place_ty, *mutability)) + } + Rvalue::Len(..) => Ok(Ty::usize_ty()), + Rvalue::Cast(.., ty) => Ok(*ty), + Rvalue::BinaryOp(op, lhs, rhs) => { + let lhs_ty = lhs.ty(locals)?; + let rhs_ty = rhs.ty(locals)?; + Ok(op.ty(lhs_ty, rhs_ty)) + } + Rvalue::CheckedBinaryOp(op, lhs, rhs) => { + let lhs_ty = lhs.ty(locals)?; + let rhs_ty = rhs.ty(locals)?; + let ty = op.ty(lhs_ty, rhs_ty); + Ok(Ty::new_tuple(&[ty, Ty::bool_ty()])) + } + Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, operand) => operand.ty(locals), + Rvalue::Discriminant(place) => { + let place_ty = place.ty(locals)?; + place_ty + .kind() + .discriminant_ty() + .ok_or_else(|| error!("Expected a `RigidTy` but found: {place_ty:?}")) + } + Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => { + Ok(Ty::usize_ty()) + } + Rvalue::Aggregate(ak, ops) => match *ak { + AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64), + AggregateKind::Tuple => Ok(Ty::new_tuple( + &ops.iter().map(|op| op.ty(locals)).collect::<Result<Vec<_>, _>>()?, + )), + AggregateKind::Adt(def, _, ref args, _, _) => Ok(def.ty_with_args(args)), + AggregateKind::Closure(def, ref args) => Ok(Ty::new_closure(def, args.clone())), + AggregateKind::Coroutine(def, ref args, mov) => { + Ok(Ty::new_coroutine(def, args.clone(), mov)) + } + }, + Rvalue::ShallowInitBox(_, ty) => Ok(Ty::new_box(*ty)), + Rvalue::CopyForDeref(place) => place.ty(locals), + } + } +} + #[derive(Clone, Debug, Eq, PartialEq)] pub enum AggregateKind { Array(Ty), @@ -492,12 +587,32 @@ pub struct Place { pub projection: Vec<ProjectionElem>, } +impl From<Local> for Place { + fn from(local: Local) -> Self { + Place { local, projection: vec![] } + } +} + +/// Debug information pertaining to a user variable. #[derive(Clone, Debug, Eq, PartialEq)] pub struct VarDebugInfo { + /// The variable name. pub name: Symbol, + + /// Source info of the user variable, including the scope + /// within which the variable is visible (to debuginfo). pub source_info: SourceInfo, + + /// The user variable's data is split across several fragments, + /// each described by a `VarDebugInfoFragment`. pub composite: Option<VarDebugInfoFragment>, + + /// Where the data for this user variable is to be found. pub value: VarDebugInfoContents, + + /// When present, indicates what argument number this variable is in the function that it + /// originated from (starting from 1). Note, if MIR inlining is enabled, then this is the + /// argument number in the original function before it was inlined. pub argument_index: Option<u16>, } @@ -632,22 +747,7 @@ pub const RETURN_LOCAL: Local = 0; /// `b`'s `FieldIdx` is `1`, /// `c`'s `FieldIdx` is `0`, and /// `g`'s `FieldIdx` is `2`. -type FieldIdx = usize; - -/// The source-order index of a variant in a type. -/// -/// For example, in the following types, -/// ```ignore(illustrative) -/// enum Demo1 { -/// Variant0 { a: bool, b: i32 }, -/// Variant1 { c: u8, d: u64 }, -/// } -/// struct Demo2 { e: u8, f: u16, g: u8 } -/// ``` -/// `a` is in the variant with the `VariantIdx` of `0`, -/// `c` is in the variant with the `VariantIdx` of `1`, and -/// `g` is in the variant with the `VariantIdx` of `0`. -pub type VariantIdx = usize; +pub type FieldIdx = usize; type UserTypeAnnotationIndex = usize; @@ -714,6 +814,17 @@ pub enum BorrowKind { }, } +impl BorrowKind { + pub fn to_mutable_lossy(self) -> Mutability { + match self { + BorrowKind::Mut { .. } => Mutability::Mut, + BorrowKind::Shared => Mutability::Not, + // FIXME: There's no type corresponding to a shallow borrow, so use `&` as an approximation. + BorrowKind::Fake => Mutability::Not, + } + } +} + #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum MutBorrowKind { Default, diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs index 10270c82e63..5c27f9281de 100644 --- a/compiler/stable_mir/src/mir/mono.rs +++ b/compiler/stable_mir/src/mir/mono.rs @@ -39,9 +39,16 @@ impl Instance { with(|context| context.instance_body(self.def)) } + /// Check whether this instance has a body available. + /// + /// This call is much cheaper than `instance.body().is_some()`, since it doesn't try to build + /// the StableMIR body. + pub fn has_body(&self) -> bool { + with(|cx| cx.has_body(self.def.def_id())) + } + pub fn is_foreign_item(&self) -> bool { - let item = CrateItem::try_from(*self); - item.as_ref().is_ok_and(CrateItem::is_foreign_item) + with(|cx| cx.is_foreign_item(self.def.def_id())) } /// Get the instance type with generic substitutions applied and lifetimes erased. @@ -143,8 +150,9 @@ impl TryFrom<CrateItem> for Instance { fn try_from(item: CrateItem) -> Result<Self, Self::Error> { with(|context| { - if !context.requires_monomorphization(item.0) { - Ok(context.mono_instance(item)) + let def_id = item.def_id(); + if !context.requires_monomorphization(def_id) { + Ok(context.mono_instance(def_id)) } else { Err(Error::new("Item requires monomorphization".to_string())) } @@ -212,6 +220,21 @@ impl TryFrom<CrateItem> for StaticDef { } } +impl TryFrom<Instance> for StaticDef { + type Error = crate::Error; + + fn try_from(value: Instance) -> Result<Self, Self::Error> { + StaticDef::try_from(CrateItem::try_from(value)?) + } +} + +impl From<StaticDef> for Instance { + fn from(value: StaticDef) -> Self { + // A static definition should always be convertible to an instance. + with(|cx| cx.mono_instance(value.def_id())) + } +} + impl StaticDef { /// Return the type of this static definition. pub fn ty(&self) -> Ty { diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index 0c44781c463..d46caad9a01 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -452,7 +452,7 @@ impl Location { } /// Information about a place's usage. -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct PlaceContext { /// Whether the access is mutable or not. Keep this private so we can increment the type in a /// backward compatible manner. diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 6c4fb4a7753..c922264f8a3 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -30,6 +30,51 @@ impl Ty { pub fn try_new_array(elem_ty: Ty, size: u64) -> Result<Ty, Error> { Ok(Ty::from_rigid_kind(RigidTy::Array(elem_ty, Const::try_from_target_usize(size)?))) } + + /// Create a new array type from Const length. + pub fn new_array_with_const_len(elem_ty: Ty, len: Const) -> Ty { + Ty::from_rigid_kind(RigidTy::Array(elem_ty, len)) + } + + /// Create a new pointer type. + pub fn new_ptr(pointee_ty: Ty, mutability: Mutability) -> Ty { + Ty::from_rigid_kind(RigidTy::RawPtr(pointee_ty, mutability)) + } + + /// Create a new reference type. + pub fn new_ref(reg: Region, pointee_ty: Ty, mutability: Mutability) -> Ty { + Ty::from_rigid_kind(RigidTy::Ref(reg, pointee_ty, mutability)) + } + + /// Create a new pointer type. + pub fn new_tuple(tys: &[Ty]) -> Ty { + Ty::from_rigid_kind(RigidTy::Tuple(Vec::from(tys))) + } + + /// Create a new closure type. + pub fn new_closure(def: ClosureDef, args: GenericArgs) -> Ty { + Ty::from_rigid_kind(RigidTy::Closure(def, args)) + } + + /// Create a new coroutine type. + pub fn new_coroutine(def: CoroutineDef, args: GenericArgs, mov: Movability) -> Ty { + Ty::from_rigid_kind(RigidTy::Coroutine(def, args, mov)) + } + + /// Create a new box type that represents `Box<T>`, for the given inner type `T`. + pub fn new_box(inner_ty: Ty) -> Ty { + with(|cx| cx.new_box_ty(inner_ty)) + } + + /// Create a type representing `usize`. + pub fn usize_ty() -> Ty { + Ty::from_rigid_kind(RigidTy::Uint(UintTy::Usize)) + } + + /// Create a type representing `bool`. + pub fn bool_ty() -> Ty { + Ty::from_rigid_kind(RigidTy::Bool) + } } impl Ty { @@ -199,6 +244,19 @@ impl TyKind { matches!(self, TyKind::RigidTy(RigidTy::FnPtr(..))) } + pub fn is_primitive(&self) -> bool { + matches!( + self, + TyKind::RigidTy( + RigidTy::Bool + | RigidTy::Char + | RigidTy::Int(_) + | RigidTy::Uint(_) + | RigidTy::Float(_) + ) + ) + } + pub fn trait_principal(&self) -> Option<Binder<ExistentialTraitRef>> { if let TyKind::RigidTy(RigidTy::Dynamic(predicates, _, _)) = self { if let Some(Binder { value: ExistentialPredicate::Trait(trait_ref), bound_vars }) = @@ -241,6 +299,7 @@ impl TyKind { } /// Get the function signature for function like types (Fn, FnPtr, Closure, Coroutine) + /// FIXME(closure) pub fn fn_sig(&self) -> Option<PolyFnSig> { match self { TyKind::RigidTy(RigidTy::FnDef(def, args)) => Some(with(|cx| cx.fn_sig(*def, args))), @@ -248,6 +307,11 @@ impl TyKind { _ => None, } } + + /// Get the discriminant type for this type. + pub fn discriminant_ty(&self) -> Option<Ty> { + self.rigid().map(|ty| with(|cx| cx.rigid_ty_discriminant_ty(ty))) + } } pub struct TypeAndMut { @@ -279,6 +343,13 @@ pub enum RigidTy { CoroutineWitness(CoroutineWitnessDef, GenericArgs), } +impl RigidTy { + /// Get the discriminant type for this type. + pub fn discriminant_ty(&self) -> Ty { + with(|cx| cx.rigid_ty_discriminant_ty(self)) + } +} + impl From<RigidTy> for TyKind { fn from(value: RigidTy) -> Self { TyKind::RigidTy(value) @@ -366,9 +437,97 @@ impl AdtDef { with(|cx| cx.adt_kind(*self)) } + /// Retrieve the type of this Adt. + pub fn ty(&self) -> Ty { + with(|cx| cx.def_ty(self.0)) + } + + /// Retrieve the type of this Adt instantiating the type with the given arguments. + /// + /// This will assume the type can be instantiated with these arguments. + pub fn ty_with_args(&self, args: &GenericArgs) -> Ty { + with(|cx| cx.def_ty_with_args(self.0, args)) + } + pub fn is_box(&self) -> bool { with(|cx| cx.adt_is_box(*self)) } + + /// The number of variants in this ADT. + pub fn num_variants(&self) -> usize { + with(|cx| cx.adt_variants_len(*self)) + } + + /// Retrieve the variants in this ADT. + pub fn variants(&self) -> Vec<VariantDef> { + self.variants_iter().collect() + } + + /// Iterate over the variants in this ADT. + pub fn variants_iter(&self) -> impl Iterator<Item = VariantDef> + '_ { + (0..self.num_variants()) + .map(|idx| VariantDef { idx: VariantIdx::to_val(idx), adt_def: *self }) + } + + pub fn variant(&self, idx: VariantIdx) -> Option<VariantDef> { + (idx.to_index() < self.num_variants()).then_some(VariantDef { idx, adt_def: *self }) + } +} + +/// Definition of a variant, which can be either a struct / union field or an enum variant. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct VariantDef { + /// The variant index. + /// + /// ## Warning + /// Do not access this field directly! + pub idx: VariantIdx, + /// The data type where this variant comes from. + /// For now, we use this to retrieve information about the variant itself so we don't need to + /// cache more information. + /// + /// ## Warning + /// Do not access this field directly! + pub adt_def: AdtDef, +} + +impl VariantDef { + pub fn name(&self) -> Symbol { + with(|cx| cx.variant_name(*self)) + } + + /// Retrieve all the fields in this variant. + // We expect user to cache this and use it directly since today it is expensive to generate all + // fields name. + pub fn fields(&self) -> Vec<FieldDef> { + with(|cx| cx.variant_fields(*self)) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct FieldDef { + /// The field definition. + /// + /// ## Warning + /// Do not access this field directly! This is public for the compiler to have access to it. + pub def: DefId, + + /// The field name. + pub name: Symbol, +} + +impl FieldDef { + /// Retrieve the type of this field instantiating the type with the given arguments. + /// + /// This will assume the type can be instantiated with these arguments. + pub fn ty_with_args(&self, args: &GenericArgs) -> Ty { + with(|cx| cx.def_ty_with_args(self.def, args)) + } + + /// Retrieve the type of this field. + pub fn ty(&self) -> Ty { + with(|cx| cx.def_ty(self.def)) + } } impl Display for AdtKind { @@ -906,3 +1065,21 @@ macro_rules! index_impl { index_impl!(ConstId); index_impl!(Ty); index_impl!(Span); + +/// The source-order index of a variant in a type. +/// +/// For example, in the following types, +/// ```ignore(illustrative) +/// enum Demo1 { +/// Variant0 { a: bool, b: i32 }, +/// Variant1 { c: u8, d: u64 }, +/// } +/// struct Demo2 { e: u8, f: u16, g: u8 } +/// ``` +/// `a` is in the variant with the `VariantIdx` of `0`, +/// `c` is in the variant with the `VariantIdx` of `1`, and +/// `g` is in the variant with the `VariantIdx` of `0`. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct VariantIdx(usize); + +index_impl!(VariantIdx); diff --git a/library/alloc/benches/vec.rs b/library/alloc/benches/vec.rs index c1d3e1bdfe7..8ebfe313dc5 100644 --- a/library/alloc/benches/vec.rs +++ b/library/alloc/benches/vec.rs @@ -658,13 +658,17 @@ fn random_sorted_fill(mut seed: u32, buf: &mut [u32]) { buf.sort(); } -fn bench_vec_dedup_old(b: &mut Bencher, sz: usize) { +// Measures performance of slice dedup impl. +// This was used to justify separate implementation of dedup for Vec. +// This algorithm was used for Vecs prior to Rust 1.52. +fn bench_dedup_slice_truncate(b: &mut Bencher, sz: usize) { let mut template = vec![0u32; sz]; b.bytes = std::mem::size_of_val(template.as_slice()) as u64; random_sorted_fill(0x43, &mut template); let mut vec = template.clone(); b.iter(|| { + let vec = black_box(&mut vec); let len = { let (dedup, _) = vec.partition_dedup(); dedup.len() @@ -672,59 +676,143 @@ fn bench_vec_dedup_old(b: &mut Bencher, sz: usize) { vec.truncate(len); black_box(vec.first()); + let vec = black_box(vec); vec.clear(); vec.extend_from_slice(&template); }); } -fn bench_vec_dedup_new(b: &mut Bencher, sz: usize) { +// Measures performance of Vec::dedup on random data. +fn bench_vec_dedup_random(b: &mut Bencher, sz: usize) { let mut template = vec![0u32; sz]; b.bytes = std::mem::size_of_val(template.as_slice()) as u64; random_sorted_fill(0x43, &mut template); let mut vec = template.clone(); b.iter(|| { + let vec = black_box(&mut vec); vec.dedup(); black_box(vec.first()); + let vec = black_box(vec); + vec.clear(); + vec.extend_from_slice(&template); + }); +} + +// Measures performance of Vec::dedup when there is no items removed +fn bench_vec_dedup_none(b: &mut Bencher, sz: usize) { + let mut template = vec![0u32; sz]; + b.bytes = std::mem::size_of_val(template.as_slice()) as u64; + template.chunks_exact_mut(2).for_each(|w| { + w[0] = black_box(0); + w[1] = black_box(5); + }); + + let mut vec = template.clone(); + b.iter(|| { + let vec = black_box(&mut vec); + vec.dedup(); + black_box(vec.first()); + // Unlike other benches of `dedup` + // this doesn't reinitialize vec + // because we measure how efficient dedup is + // when no memory written + }); +} + +// Measures performance of Vec::dedup when there is all items removed +fn bench_vec_dedup_all(b: &mut Bencher, sz: usize) { + let mut template = vec![0u32; sz]; + b.bytes = std::mem::size_of_val(template.as_slice()) as u64; + template.iter_mut().for_each(|w| { + *w = black_box(0); + }); + + let mut vec = template.clone(); + b.iter(|| { + let vec = black_box(&mut vec); + vec.dedup(); + black_box(vec.first()); + let vec = black_box(vec); vec.clear(); vec.extend_from_slice(&template); }); } #[bench] -fn bench_dedup_old_100(b: &mut Bencher) { - bench_vec_dedup_old(b, 100); +fn bench_dedup_slice_truncate_100(b: &mut Bencher) { + bench_dedup_slice_truncate(b, 100); } #[bench] -fn bench_dedup_new_100(b: &mut Bencher) { - bench_vec_dedup_new(b, 100); +fn bench_dedup_random_100(b: &mut Bencher) { + bench_vec_dedup_random(b, 100); } #[bench] -fn bench_dedup_old_1000(b: &mut Bencher) { - bench_vec_dedup_old(b, 1000); +fn bench_dedup_none_100(b: &mut Bencher) { + bench_vec_dedup_none(b, 100); } + +#[bench] +fn bench_dedup_all_100(b: &mut Bencher) { + bench_vec_dedup_all(b, 100); +} + +#[bench] +fn bench_dedup_slice_truncate_1000(b: &mut Bencher) { + bench_dedup_slice_truncate(b, 1000); +} +#[bench] +fn bench_dedup_random_1000(b: &mut Bencher) { + bench_vec_dedup_random(b, 1000); +} + +#[bench] +fn bench_dedup_none_1000(b: &mut Bencher) { + bench_vec_dedup_none(b, 1000); +} + #[bench] -fn bench_dedup_new_1000(b: &mut Bencher) { - bench_vec_dedup_new(b, 1000); +fn bench_dedup_all_1000(b: &mut Bencher) { + bench_vec_dedup_all(b, 1000); } #[bench] -fn bench_dedup_old_10000(b: &mut Bencher) { - bench_vec_dedup_old(b, 10000); +fn bench_dedup_slice_truncate_10000(b: &mut Bencher) { + bench_dedup_slice_truncate(b, 10000); } #[bench] -fn bench_dedup_new_10000(b: &mut Bencher) { - bench_vec_dedup_new(b, 10000); +fn bench_dedup_random_10000(b: &mut Bencher) { + bench_vec_dedup_random(b, 10000); } #[bench] -fn bench_dedup_old_100000(b: &mut Bencher) { - bench_vec_dedup_old(b, 100000); +fn bench_dedup_none_10000(b: &mut Bencher) { + bench_vec_dedup_none(b, 10000); } + +#[bench] +fn bench_dedup_all_10000(b: &mut Bencher) { + bench_vec_dedup_all(b, 10000); +} + +#[bench] +fn bench_dedup_slice_truncate_100000(b: &mut Bencher) { + bench_dedup_slice_truncate(b, 100000); +} +#[bench] +fn bench_dedup_random_100000(b: &mut Bencher) { + bench_vec_dedup_random(b, 100000); +} + +#[bench] +fn bench_dedup_none_100000(b: &mut Bencher) { + bench_vec_dedup_none(b, 100000); +} + #[bench] -fn bench_dedup_new_100000(b: &mut Bencher) { - bench_vec_dedup_new(b, 100000); +fn bench_dedup_all_100000(b: &mut Bencher) { + bench_vec_dedup_all(b, 100000); } #[bench] diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 25c63b425ce..fdf5e134f4d 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1038,10 +1038,18 @@ impl<T: ?Sized, A: Allocator> Box<T, A> { /// use std::ptr; /// /// let x = Box::new(String::from("Hello")); - /// let p = Box::into_raw(x); + /// let ptr = Box::into_raw(x); + /// unsafe { + /// ptr::drop_in_place(ptr); + /// dealloc(ptr as *mut u8, Layout::new::<String>()); + /// } + /// ``` + /// Note: This is equivalent to the following: + /// ``` + /// let x = Box::new(String::from("Hello")); + /// let ptr = Box::into_raw(x); /// unsafe { - /// ptr::drop_in_place(p); - /// dealloc(p as *mut u8, Layout::new::<String>()); + /// drop(Box::from_raw(ptr)); /// } /// ``` /// diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index da0abdc9746..5a4a94d79d8 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -2843,16 +2843,14 @@ impl<T: ?Sized, A: Allocator> Weak<T, A> { /// (i.e., when this `Weak` was created by `Weak::new`). #[inline] fn inner(&self) -> Option<WeakInner<'_>> { - if is_dangling(self.ptr.as_ptr()) { + let ptr = self.ptr.as_ptr(); + if is_dangling(ptr) { None } else { // We are careful to *not* create a reference covering the "data" field, as // the field may be mutated concurrently (for example, if the last `Arc` // is dropped, the data field will be dropped in-place). - Some(unsafe { - let ptr = self.ptr.as_ptr(); - WeakInner { strong: &(*ptr).strong, weak: &(*ptr).weak } - }) + Some(unsafe { WeakInner { strong: &(*ptr).strong, weak: &(*ptr).weak } }) } } diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs index e4f96fd7640..a6cbed092c0 100644 --- a/library/alloc/src/vec/in_place_collect.rs +++ b/library/alloc/src/vec/in_place_collect.rs @@ -168,7 +168,7 @@ const fn in_place_collectible<DEST, SRC>( step_merge: Option<NonZeroUsize>, step_expand: Option<NonZeroUsize>, ) -> bool { - if DEST::IS_ZST || mem::align_of::<SRC>() < mem::align_of::<DEST>() { + if const { SRC::IS_ZST || DEST::IS_ZST || mem::align_of::<SRC>() < mem::align_of::<DEST>() } { return false; } @@ -186,6 +186,27 @@ const fn in_place_collectible<DEST, SRC>( } } +const fn needs_realloc<SRC, DEST>(src_cap: usize, dst_cap: usize) -> bool { + if const { mem::align_of::<SRC>() != mem::align_of::<DEST>() } { + return src_cap > 0; + } + + // If src type size is an integer multiple of the destination type size then + // the caller will have calculated a `dst_cap` that is an integer multiple of + // `src_cap` without remainder. + if const { + let src_sz = mem::size_of::<SRC>(); + let dest_sz = mem::size_of::<DEST>(); + dest_sz != 0 && src_sz % dest_sz == 0 + } { + return false; + } + + // type layouts don't guarantee a fit, so do a runtime check to see if + // the allocations happen to match + return src_cap > 0 && src_cap * mem::size_of::<SRC>() != dst_cap * mem::size_of::<DEST>(); +} + /// This provides a shorthand for the source type since local type aliases aren't a thing. #[rustc_specialization_trait] trait InPlaceCollect: SourceIter<Source: AsVecIntoIter> + InPlaceIterable { @@ -259,13 +280,10 @@ where // that wasn't a multiple of the destination type size. // Since the discrepancy should generally be small this should only result in some // bookkeeping updates and no memmove. - if (const { - let src_sz = mem::size_of::<I::Src>(); - src_sz > 0 && mem::size_of::<T>() % src_sz != 0 - } && src_cap * mem::size_of::<I::Src>() != dst_cap * mem::size_of::<T>()) - || const { mem::align_of::<T>() != mem::align_of::<I::Src>() } - { + if needs_realloc::<I::Src, T>(src_cap, dst_cap) { let alloc = Global; + debug_assert_ne!(src_cap, 0); + debug_assert_ne!(dst_cap, 0); unsafe { // The old allocation exists, therefore it must have a valid layout. let src_align = mem::align_of::<I::Src>(); @@ -286,6 +304,8 @@ where let Ok(reallocated) = result else { handle_alloc_error(new_layout) }; dst_buf = reallocated.as_ptr() as *mut T; } + } else { + debug_assert_eq!(src_cap * mem::size_of::<I::Src>(), dst_cap * mem::size_of::<T>()); } mem::forget(dst_guard); diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index bcf4163e39c..fca85c6123b 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1777,7 +1777,32 @@ impl<T, A: Allocator> Vec<T, A> { return; } - /* INVARIANT: vec.len() > read >= write > write-1 >= 0 */ + // Check if we ever want to remove anything. + // This allows to use copy_non_overlapping in next cycle. + // And avoids any memory writes if we don't need to remove anything. + let mut first_duplicate_idx: usize = 1; + let start = self.as_mut_ptr(); + while first_duplicate_idx != len { + let found_duplicate = unsafe { + // SAFETY: first_duplicate always in range [1..len) + // Note that we start iteration from 1 so we never overflow. + let prev = start.add(first_duplicate_idx.wrapping_sub(1)); + let current = start.add(first_duplicate_idx); + // We explicitly say in docs that references are reversed. + same_bucket(&mut *current, &mut *prev) + }; + if found_duplicate { + break; + } + first_duplicate_idx += 1; + } + // Don't need to remove anything. + // We cannot get bigger than len. + if first_duplicate_idx == len { + return; + } + + /* INVARIANT: vec.len() > read > write > write-1 >= 0 */ struct FillGapOnDrop<'a, T, A: core::alloc::Allocator> { /* Offset of the element we want to check if it is duplicate */ read: usize, @@ -1823,31 +1848,39 @@ impl<T, A: Allocator> Vec<T, A> { } } - let mut gap = FillGapOnDrop { read: 1, write: 1, vec: self }; - let ptr = gap.vec.as_mut_ptr(); - /* Drop items while going through Vec, it should be more efficient than * doing slice partition_dedup + truncate */ + // Construct gap first and then drop item to avoid memory corruption if `T::drop` panics. + let mut gap = + FillGapOnDrop { read: first_duplicate_idx + 1, write: first_duplicate_idx, vec: self }; + unsafe { + // SAFETY: we checked that first_duplicate_idx in bounds before. + // If drop panics, `gap` would remove this item without drop. + ptr::drop_in_place(start.add(first_duplicate_idx)); + } + /* SAFETY: Because of the invariant, read_ptr, prev_ptr and write_ptr * are always in-bounds and read_ptr never aliases prev_ptr */ unsafe { while gap.read < len { - let read_ptr = ptr.add(gap.read); - let prev_ptr = ptr.add(gap.write.wrapping_sub(1)); + let read_ptr = start.add(gap.read); + let prev_ptr = start.add(gap.write.wrapping_sub(1)); - if same_bucket(&mut *read_ptr, &mut *prev_ptr) { + // We explicitly say in docs that references are reversed. + let found_duplicate = same_bucket(&mut *read_ptr, &mut *prev_ptr); + if found_duplicate { // Increase `gap.read` now since the drop may panic. gap.read += 1; /* We have found duplicate, drop it in-place */ ptr::drop_in_place(read_ptr); } else { - let write_ptr = ptr.add(gap.write); + let write_ptr = start.add(gap.write); - /* Because `read_ptr` can be equal to `write_ptr`, we either - * have to use `copy` or conditional `copy_nonoverlapping`. - * Looks like the first option is faster. */ - ptr::copy(read_ptr, write_ptr, 1); + /* read_ptr cannot be equal to write_ptr because at this point + * we guaranteed to skip at least one element (before loop starts). + */ + ptr::copy_nonoverlapping(read_ptr, write_ptr, 1); /* We have filled that place, so go further */ gap.write += 1; diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index ded6b2079d2..2dcfc6b4abf 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -41,6 +41,7 @@ #![feature(thin_box)] #![feature(strict_provenance)] #![feature(drain_keep_rest)] +#![allow(internal_features)] #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 81de7085e09..3d3175ba3a9 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1213,6 +1213,14 @@ fn test_in_place_specialization_step_up_down() { assert_ne!(src_bytes, sink_bytes); assert_eq!(sink.len(), 2); + let mut src: Vec<[u8; 3]> = Vec::with_capacity(17); + src.resize( 8, [0; 3]); + let iter = src.into_iter().map(|[a, b, _]| [a, b]); + assert_in_place_trait(&iter); + let sink: Vec<[u8; 2]> = iter.collect(); + assert_eq!(sink.len(), 8); + assert!(sink.capacity() <= 25); + let src = vec![[0u8; 4]; 256]; let srcptr = src.as_ptr(); let iter = src diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index f10a82c5694..030040ba09a 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -143,17 +143,17 @@ //! //! ``` //! # #![allow(dead_code)] -//! use std::cell::RefCell; +//! use std::cell::OnceCell; //! //! struct Graph { //! edges: Vec<(i32, i32)>, -//! span_tree_cache: RefCell<Option<Vec<(i32, i32)>>> +//! span_tree_cache: OnceCell<Vec<(i32, i32)>> //! } //! //! impl Graph { //! fn minimum_spanning_tree(&self) -> Vec<(i32, i32)> { -//! self.span_tree_cache.borrow_mut() -//! .get_or_insert_with(|| self.calc_span_tree()) +//! self.span_tree_cache +//! .get_or_init(|| self.calc_span_tree()) //! .clone() //! } //! diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index ab86e4e39ea..3406112ddb1 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1906,6 +1906,7 @@ extern "rust-intrinsic" { /// /// ``` /// #![feature(core_intrinsics)] + /// # #![allow(internal_features)] /// /// use std::intrinsics::ctlz; /// @@ -1918,6 +1919,7 @@ extern "rust-intrinsic" { /// /// ``` /// #![feature(core_intrinsics)] + /// # #![allow(internal_features)] /// /// use std::intrinsics::ctlz; /// @@ -1939,6 +1941,7 @@ extern "rust-intrinsic" { /// /// ``` /// #![feature(core_intrinsics)] + /// # #![allow(internal_features)] /// /// use std::intrinsics::ctlz_nonzero; /// @@ -1965,6 +1968,7 @@ extern "rust-intrinsic" { /// /// ``` /// #![feature(core_intrinsics)] + /// # #![allow(internal_features)] /// /// use std::intrinsics::cttz; /// @@ -1977,6 +1981,7 @@ extern "rust-intrinsic" { /// /// ``` /// #![feature(core_intrinsics)] + /// # #![allow(internal_features)] /// /// use std::intrinsics::cttz; /// @@ -1998,6 +2003,7 @@ extern "rust-intrinsic" { /// /// ``` /// #![feature(core_intrinsics)] + /// # #![allow(internal_features)] /// /// use std::intrinsics::cttz_nonzero; /// @@ -2463,6 +2469,7 @@ extern "rust-intrinsic" { /// ```no_run /// #![feature(const_eval_select)] /// #![feature(core_intrinsics)] + /// # #![allow(internal_features)] /// use std::hint::unreachable_unchecked; /// use std::intrinsics::const_eval_select; /// diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 553e18c6883..1b6e77b96b1 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -84,6 +84,7 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { #[rustc_nounwind] #[rustc_const_unstable(feature = "core_panic", issue = "none")] pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! { + #[inline] // this should always be inlined into `panic_nounwind_fmt` #[track_caller] fn runtime(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! { if cfg!(feature = "panic_immediate_abort") { @@ -112,6 +113,7 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo #[inline] #[track_caller] const fn comptime(fmt: fmt::Arguments<'_>, _force_no_backtrace: bool) -> ! { + // We don't unwind anyway at compile-time so we can call the regular `panic_fmt`. panic_fmt(fmt); } @@ -142,7 +144,8 @@ pub const fn panic(expr: &'static str) -> ! { panic_fmt(fmt::Arguments::new_const(&[expr])); } -/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize. +/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize on the caller. +/// If you want `#[track_caller]` for nicer errors, call `panic_nounwind_fmt` directly. #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics @@ -205,8 +208,8 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { panic!("index out of bounds: the len is {len} but the index is {index}") } -#[cold] -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] +#[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] #[lang = "panic_misaligned_pointer_dereference"] // needed by codegen for panic on misaligned pointer deref #[rustc_nounwind] // `CheckAlignment` MIR pass requires this function to never unwind diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index ff292ff2dcb..765f73636fb 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -50,22 +50,19 @@ macro_rules! tuple_impls { maybe_tuple_doc! { $($T)+ @ #[unstable(feature = "structural_match", issue = "31434")] - impl<$($T: ConstParamTy),+> ConstParamTy for ($($T,)+) - {} + impl<$($T: ConstParamTy),+> ConstParamTy for ($($T,)+) {} } maybe_tuple_doc! { $($T)+ @ #[unstable(feature = "structural_match", issue = "31434")] - impl<$($T),+> StructuralPartialEq for ($($T,)+) - {} + impl<$($T),+> StructuralPartialEq for ($($T,)+) {} } maybe_tuple_doc! { $($T)+ @ #[unstable(feature = "structural_match", issue = "31434")] - impl<$($T),+> StructuralEq for ($($T,)+) - {} + impl<$($T),+> StructuralEq for ($($T,)+) {} } maybe_tuple_doc! { @@ -118,7 +115,7 @@ macro_rules! tuple_impls { impl<$($T: Default),+> Default for ($($T,)+) { #[inline] fn default() -> ($($T,)+) { - ($({ let x: $T = Default::default(); x},)+) + ($($T::default(),)+) } } } @@ -196,7 +193,7 @@ macro_rules! lexical_partial_cmp { ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => { match ($a).partial_cmp(&$b) { Some(Equal) => lexical_partial_cmp!($($rest_a, $rest_b),+), - ordering => ordering + ordering => ordering } }; ($a:expr, $b:expr) => { ($a).partial_cmp(&$b) }; @@ -206,7 +203,7 @@ macro_rules! lexical_cmp { ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => { match ($a).cmp(&$b) { Equal => lexical_cmp!($($rest_a, $rest_b),+), - ordering => ordering + ordering => ordering } }; ($a:expr, $b:expr) => { ($a).cmp(&$b) }; diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 3fbb058b09b..c531117bed5 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -117,6 +117,7 @@ #![feature(get_many_mut)] #![feature(offset_of)] #![feature(iter_map_windows)] +#![allow(internal_features)] #![deny(unsafe_op_in_unsafe_fn)] #![deny(fuzzy_provenance_casts)] diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index 6e097e2caf2..8fd64279ac5 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -81,6 +81,16 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 { } core::intrinsics::unreachable(); } + } else if #[cfg(target_os = "teeos")] { + mod teeos { + extern "C" { + pub fn TEE_Panic(code: u32) -> !; + } + } + + unsafe fn abort() -> ! { + teeos::TEE_Panic(1); + } } else { unsafe fn abort() -> ! { core::intrinsics::abort(); diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 9363fde5de2..7a0bae34642 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -49,6 +49,7 @@ cfg_if::cfg_if! { } else if #[cfg(any( all(target_family = "windows", target_env = "gnu"), target_os = "psp", + target_os = "xous", target_os = "solid_asp3", all(target_family = "unix", not(target_os = "espidf")), all(target_vendor = "fortanix", target_env = "sgx"), diff --git a/library/std/build.rs b/library/std/build.rs index 11ba29766c1..0f5068b59b7 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -34,6 +34,7 @@ fn main() { || target.contains("xous") || target.contains("hurd") || target.contains("uefi") + || target.contains("teeos") // See src/bootstrap/synthetic_targets.rs || env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok() { diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 159ffe7ac96..88420bd3612 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -53,6 +53,9 @@ cfg_if::cfg_if! { } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { mod sgx; pub use self::sgx::*; + } else if #[cfg(target_os = "teeos")] { + mod teeos; + pub use self::teeos::*; } else { mod unsupported; pub use self::unsupported::*; diff --git a/library/std/src/sys/personality/mod.rs b/library/std/src/sys/personality/mod.rs index 386a399f532..0fff53f1887 100644 --- a/library/std/src/sys/personality/mod.rs +++ b/library/std/src/sys/personality/mod.rs @@ -28,6 +28,7 @@ cfg_if::cfg_if! { } else if #[cfg(any( all(target_family = "windows", target_env = "gnu"), target_os = "psp", + target_os = "xous", target_os = "solid_asp3", all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re")), all(target_vendor = "fortanix", target_env = "sgx"), diff --git a/library/std/src/sys/teeos/alloc.rs b/library/std/src/sys/teeos/alloc.rs new file mode 100644 index 00000000000..e236819aa23 --- /dev/null +++ b/library/std/src/sys/teeos/alloc.rs @@ -0,0 +1,57 @@ +use crate::alloc::{GlobalAlloc, Layout, System}; +use crate::ptr; +use crate::sys::common::alloc::{realloc_fallback, MIN_ALIGN}; + +#[stable(feature = "alloc_system_type", since = "1.28.0")] +unsafe impl GlobalAlloc for System { + #[inline] + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + // jemalloc provides alignment less than MIN_ALIGN for small allocations. + // So only rely on MIN_ALIGN if size >= align. + // Also see <https://github.com/rust-lang/rust/issues/45955> and + // <https://github.com/rust-lang/rust/issues/62251#issuecomment-507580914>. + if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { + libc::malloc(layout.size()) as *mut u8 + } else { + aligned_malloc(&layout) + } + } + + #[inline] + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + // See the comment above in `alloc` for why this check looks the way it does. + if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { + libc::calloc(layout.size(), 1) as *mut u8 + } else { + let ptr = self.alloc(layout); + if !ptr.is_null() { + ptr::write_bytes(ptr, 0, layout.size()); + } + ptr + } + } + + #[inline] + unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { + libc::free(ptr as *mut libc::c_void) + } + + #[inline] + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + if layout.align() <= MIN_ALIGN && layout.align() <= new_size { + libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 + } else { + realloc_fallback(self, ptr, layout, new_size) + } + } +} + +#[inline] +unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + let mut out = ptr::null_mut(); + // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`. + // Since these are all powers of 2, we can just use max. + let align = layout.align().max(crate::mem::size_of::<usize>()); + let ret = libc::posix_memalign(&mut out, align, layout.size()); + if ret != 0 { ptr::null_mut() } else { out as *mut u8 } +} diff --git a/library/std/src/sys/teeos/locks/condvar.rs b/library/std/src/sys/teeos/locks/condvar.rs new file mode 100644 index 00000000000..c08e8145b8c --- /dev/null +++ b/library/std/src/sys/teeos/locks/condvar.rs @@ -0,0 +1,100 @@ +use crate::cell::UnsafeCell; +use crate::ptr; +use crate::sync::atomic::{AtomicPtr, Ordering::Relaxed}; +use crate::sys::locks::mutex::{self, Mutex}; +use crate::sys::time::TIMESPEC_MAX; +use crate::sys_common::lazy_box::{LazyBox, LazyInit}; +use crate::time::Duration; + +extern "C" { + pub fn pthread_cond_timedwait( + cond: *mut libc::pthread_cond_t, + lock: *mut libc::pthread_mutex_t, + adstime: *const libc::timespec, + ) -> libc::c_int; +} + +struct AllocatedCondvar(UnsafeCell<libc::pthread_cond_t>); + +pub struct Condvar { + inner: LazyBox<AllocatedCondvar>, + mutex: AtomicPtr<libc::pthread_mutex_t>, +} + +#[inline] +fn raw(c: &Condvar) -> *mut libc::pthread_cond_t { + c.inner.0.get() +} + +unsafe impl Send for AllocatedCondvar {} +unsafe impl Sync for AllocatedCondvar {} + +impl LazyInit for AllocatedCondvar { + fn init() -> Box<Self> { + let condvar = Box::new(AllocatedCondvar(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER))); + + let r = unsafe { libc::pthread_cond_init(condvar.0.get(), crate::ptr::null()) }; + assert_eq!(r, 0); + + condvar + } +} + +impl Drop for AllocatedCondvar { + #[inline] + fn drop(&mut self) { + let r = unsafe { libc::pthread_cond_destroy(self.0.get()) }; + debug_assert_eq!(r, 0); + } +} + +impl Condvar { + pub const fn new() -> Condvar { + Condvar { inner: LazyBox::new(), mutex: AtomicPtr::new(ptr::null_mut()) } + } + + #[inline] + fn verify(&self, mutex: *mut libc::pthread_mutex_t) { + match self.mutex.compare_exchange(ptr::null_mut(), mutex, Relaxed, Relaxed) { + Ok(_) => {} // Stored the address + Err(n) if n == mutex => {} // Lost a race to store the same address + _ => panic!("attempted to use a condition variable with two mutexes"), + } + } + + #[inline] + pub fn notify_one(&self) { + let r = unsafe { libc::pthread_cond_signal(raw(self)) }; + debug_assert_eq!(r, 0); + } + + #[inline] + pub fn notify_all(&self) { + let r = unsafe { libc::pthread_cond_broadcast(raw(self)) }; + debug_assert_eq!(r, 0); + } + + #[inline] + pub unsafe fn wait(&self, mutex: &Mutex) { + let mutex = mutex::raw(mutex); + self.verify(mutex); + let r = libc::pthread_cond_wait(raw(self), mutex); + debug_assert_eq!(r, 0); + } + + pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { + use crate::sys::time::Timespec; + + let mutex = mutex::raw(mutex); + self.verify(mutex); + + let timeout = Timespec::now(libc::CLOCK_MONOTONIC) + .checked_add_duration(&dur) + .and_then(|t| t.to_timespec()) + .unwrap_or(TIMESPEC_MAX); + + let r = pthread_cond_timedwait(raw(self), mutex, &timeout); + assert!(r == libc::ETIMEDOUT || r == 0); + r == 0 + } +} diff --git a/library/std/src/sys/teeos/locks/mod.rs b/library/std/src/sys/teeos/locks/mod.rs new file mode 100644 index 00000000000..c58e9c7fd45 --- /dev/null +++ b/library/std/src/sys/teeos/locks/mod.rs @@ -0,0 +1,8 @@ +pub mod condvar; +#[path = "../../unix/locks/pthread_mutex.rs"] +pub mod mutex; +pub mod rwlock; + +pub(crate) use condvar::Condvar; +pub(crate) use mutex::Mutex; +pub(crate) use rwlock::RwLock; diff --git a/library/std/src/sys/teeos/locks/rwlock.rs b/library/std/src/sys/teeos/locks/rwlock.rs new file mode 100644 index 00000000000..27cdb88788f --- /dev/null +++ b/library/std/src/sys/teeos/locks/rwlock.rs @@ -0,0 +1,44 @@ +use crate::sys::locks::mutex::Mutex; + +/// we do not supported rwlock, so use mutex to simulate rwlock. +/// it's useful because so many code in std will use rwlock. +pub struct RwLock { + inner: Mutex, +} + +impl RwLock { + #[inline] + pub const fn new() -> RwLock { + RwLock { inner: Mutex::new() } + } + + #[inline] + pub fn read(&self) { + unsafe { self.inner.lock() }; + } + + #[inline] + pub fn try_read(&self) -> bool { + unsafe { self.inner.try_lock() } + } + + #[inline] + pub fn write(&self) { + unsafe { self.inner.lock() }; + } + + #[inline] + pub unsafe fn try_write(&self) -> bool { + unsafe { self.inner.try_lock() } + } + + #[inline] + pub unsafe fn read_unlock(&self) { + unsafe { self.inner.unlock() }; + } + + #[inline] + pub unsafe fn write_unlock(&self) { + unsafe { self.inner.unlock() }; + } +} diff --git a/library/std/src/sys/teeos/mod.rs b/library/std/src/sys/teeos/mod.rs new file mode 100644 index 00000000000..ed8c54b2c36 --- /dev/null +++ b/library/std/src/sys/teeos/mod.rs @@ -0,0 +1,167 @@ +//! System bindings for the Teeos platform +//! +//! This module contains the facade (aka platform-specific) implementations of +//! OS level functionality for Teeos. +#![allow(unsafe_op_in_unsafe_fn)] +#![allow(unused_variables)] +#![allow(dead_code)] + +pub use self::rand::hashmap_random_keys; + +pub mod alloc; +#[path = "../unsupported/args.rs"] +pub mod args; +#[path = "../unix/cmath.rs"] +pub mod cmath; +#[path = "../unsupported/env.rs"] +pub mod env; +pub mod locks; +//pub mod fd; +#[path = "../unsupported/fs.rs"] +pub mod fs; +#[path = "../unsupported/io.rs"] +pub mod io; +#[path = "../unix/memchr.rs"] +pub mod memchr; +pub mod net; +#[path = "../unsupported/once.rs"] +pub mod once; +pub mod os; +#[path = "../unix/os_str.rs"] +pub mod os_str; +#[path = "../unix/path.rs"] +pub mod path; +#[path = "../unsupported/pipe.rs"] +pub mod pipe; +#[path = "../unsupported/process.rs"] +pub mod process; +mod rand; +pub mod stdio; +pub mod thread; +pub mod thread_local_dtor; +#[path = "../unix/thread_local_key.rs"] +pub mod thread_local_key; +#[path = "../unsupported/thread_parking.rs"] +pub mod thread_parking; +#[allow(non_upper_case_globals)] +#[path = "../unix/time.rs"] +pub mod time; + +use crate::io::ErrorKind; + +pub fn abort_internal() -> ! { + unsafe { libc::abort() } +} + +// Trusted Applications are loaded as dynamic libraries on Teeos, +// so this should never be called. +pub fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {} + +// SAFETY: must be called only once during runtime cleanup. +// this is not guaranteed to run, for example when the program aborts. +pub unsafe fn cleanup() { + unimplemented!() + // We do NOT have stack overflow handler, because TEE OS will kill TA when it happens. + // So cleanup is commented + // stack_overflow::cleanup(); +} + +#[inline] +pub(crate) fn is_interrupted(errno: i32) -> bool { + errno == libc::EINTR +} + +// Note: code below is 1:1 copied from unix/mod.rs +pub fn decode_error_kind(errno: i32) -> ErrorKind { + use ErrorKind::*; + match errno as libc::c_int { + libc::E2BIG => ArgumentListTooLong, + libc::EADDRINUSE => AddrInUse, + libc::EADDRNOTAVAIL => AddrNotAvailable, + libc::EBUSY => ResourceBusy, + libc::ECONNABORTED => ConnectionAborted, + libc::ECONNREFUSED => ConnectionRefused, + libc::ECONNRESET => ConnectionReset, + libc::EDEADLK => Deadlock, + libc::EDQUOT => FilesystemQuotaExceeded, + libc::EEXIST => AlreadyExists, + libc::EFBIG => FileTooLarge, + libc::EHOSTUNREACH => HostUnreachable, + libc::EINTR => Interrupted, + libc::EINVAL => InvalidInput, + libc::EISDIR => IsADirectory, + libc::ELOOP => FilesystemLoop, + libc::ENOENT => NotFound, + libc::ENOMEM => OutOfMemory, + libc::ENOSPC => StorageFull, + libc::ENOSYS => Unsupported, + libc::EMLINK => TooManyLinks, + libc::ENAMETOOLONG => InvalidFilename, + libc::ENETDOWN => NetworkDown, + libc::ENETUNREACH => NetworkUnreachable, + libc::ENOTCONN => NotConnected, + libc::ENOTDIR => NotADirectory, + libc::ENOTEMPTY => DirectoryNotEmpty, + libc::EPIPE => BrokenPipe, + libc::EROFS => ReadOnlyFilesystem, + libc::ESPIPE => NotSeekable, + libc::ESTALE => StaleNetworkFileHandle, + libc::ETIMEDOUT => TimedOut, + libc::ETXTBSY => ExecutableFileBusy, + libc::EXDEV => CrossesDevices, + + libc::EACCES | libc::EPERM => PermissionDenied, + + // These two constants can have the same value on some systems, + // but different values on others, so we can't use a match + // clause + x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => WouldBlock, + + _ => Uncategorized, + } +} + +#[doc(hidden)] +pub trait IsMinusOne { + fn is_minus_one(&self) -> bool; +} + +macro_rules! impl_is_minus_one { + ($($t:ident)*) => ($(impl IsMinusOne for $t { + fn is_minus_one(&self) -> bool { + *self == -1 + } + })*) +} + +impl_is_minus_one! { i8 i16 i32 i64 isize } + +pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> { + if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) } +} + +pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T> +where + T: IsMinusOne, + F: FnMut() -> T, +{ + loop { + match cvt(f()) { + Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + other => return other, + } + } +} + +pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> { + if error == 0 { Ok(()) } else { Err(crate::io::Error::from_raw_os_error(error)) } +} + +use crate::io as std_io; +pub fn unsupported<T>() -> std_io::Result<T> { + Err(unsupported_err()) +} + +pub fn unsupported_err() -> std_io::Error { + std_io::Error::new(std_io::ErrorKind::Unsupported, "operation not supported on this platform") +} diff --git a/library/std/src/sys/teeos/net.rs b/library/std/src/sys/teeos/net.rs new file mode 100644 index 00000000000..0df681dbfa5 --- /dev/null +++ b/library/std/src/sys/teeos/net.rs @@ -0,0 +1,372 @@ +use crate::fmt; +use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; +use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; +use crate::sys::unsupported; +use crate::time::Duration; + +pub struct TcpStream(!); + +impl TcpStream { + pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> { + unsupported() + } + + pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> { + unsupported() + } + + pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> { + self.0 + } + + pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> { + self.0 + } + + pub fn read_timeout(&self) -> io::Result<Option<Duration>> { + self.0 + } + + pub fn write_timeout(&self) -> io::Result<Option<Duration>> { + self.0 + } + + pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> { + self.0 + } + + pub fn read(&self, _: &mut [u8]) -> io::Result<usize> { + self.0 + } + + pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> { + self.0 + } + + pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> { + self.0 + } + + pub fn is_read_vectored(&self) -> bool { + self.0 + } + + pub fn write(&self, _: &[u8]) -> io::Result<usize> { + self.0 + } + + pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> { + self.0 + } + + pub fn is_write_vectored(&self) -> bool { + self.0 + } + + pub fn peer_addr(&self) -> io::Result<SocketAddr> { + self.0 + } + + pub fn socket_addr(&self) -> io::Result<SocketAddr> { + self.0 + } + + pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { + self.0 + } + + pub fn duplicate(&self) -> io::Result<TcpStream> { + self.0 + } + + pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> { + self.0 + } + + pub fn linger(&self) -> io::Result<Option<Duration>> { + self.0 + } + + pub fn set_nodelay(&self, _: bool) -> io::Result<()> { + self.0 + } + + pub fn nodelay(&self) -> io::Result<bool> { + self.0 + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + self.0 + } + + pub fn ttl(&self) -> io::Result<u32> { + self.0 + } + + pub fn take_error(&self) -> io::Result<Option<io::Error>> { + self.0 + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + self.0 + } +} + +impl fmt::Debug for TcpStream { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0 + } +} + +pub struct TcpListener(!); + +impl TcpListener { + pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> { + unsupported() + } + + pub fn socket_addr(&self) -> io::Result<SocketAddr> { + self.0 + } + + pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { + self.0 + } + + pub fn duplicate(&self) -> io::Result<TcpListener> { + self.0 + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + self.0 + } + + pub fn ttl(&self) -> io::Result<u32> { + self.0 + } + + pub fn set_only_v6(&self, _: bool) -> io::Result<()> { + self.0 + } + + pub fn only_v6(&self) -> io::Result<bool> { + self.0 + } + + pub fn take_error(&self) -> io::Result<Option<io::Error>> { + self.0 + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + self.0 + } +} + +impl fmt::Debug for TcpListener { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0 + } +} + +pub struct UdpSocket(!); + +impl UdpSocket { + pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> { + unsupported() + } + + pub fn peer_addr(&self) -> io::Result<SocketAddr> { + self.0 + } + + pub fn socket_addr(&self) -> io::Result<SocketAddr> { + self.0 + } + + pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.0 + } + + pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.0 + } + + pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> { + self.0 + } + + pub fn duplicate(&self) -> io::Result<UdpSocket> { + self.0 + } + + pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> { + self.0 + } + + pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> { + self.0 + } + + pub fn read_timeout(&self) -> io::Result<Option<Duration>> { + self.0 + } + + pub fn write_timeout(&self) -> io::Result<Option<Duration>> { + self.0 + } + + pub fn set_broadcast(&self, _: bool) -> io::Result<()> { + self.0 + } + + pub fn broadcast(&self) -> io::Result<bool> { + self.0 + } + + pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { + self.0 + } + + pub fn multicast_loop_v4(&self) -> io::Result<bool> { + self.0 + } + + pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { + self.0 + } + + pub fn multicast_ttl_v4(&self) -> io::Result<u32> { + self.0 + } + + pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { + self.0 + } + + pub fn multicast_loop_v6(&self) -> io::Result<bool> { + self.0 + } + + pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { + self.0 + } + + pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { + self.0 + } + + pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { + self.0 + } + + pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { + self.0 + } + + pub fn set_ttl(&self, _: u32) -> io::Result<()> { + self.0 + } + + pub fn ttl(&self) -> io::Result<u32> { + self.0 + } + + pub fn take_error(&self) -> io::Result<Option<io::Error>> { + self.0 + } + + pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { + self.0 + } + + pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> { + self.0 + } + + pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> { + self.0 + } + + pub fn send(&self, _: &[u8]) -> io::Result<usize> { + self.0 + } + + pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> { + self.0 + } +} + +impl fmt::Debug for UdpSocket { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0 + } +} + +pub struct LookupHost(!); + +impl LookupHost { + pub fn port(&self) -> u16 { + self.0 + } +} + +impl Iterator for LookupHost { + type Item = SocketAddr; + fn next(&mut self) -> Option<SocketAddr> { + self.0 + } +} + +impl TryFrom<&str> for LookupHost { + type Error = io::Error; + + fn try_from(_v: &str) -> io::Result<LookupHost> { + unsupported() + } +} + +impl<'a> TryFrom<(&'a str, u16)> for LookupHost { + type Error = io::Error; + + fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> { + unsupported() + } +} + +#[allow(nonstandard_style)] +pub mod netc { + pub const AF_INET: u8 = 0; + pub const AF_INET6: u8 = 1; + pub type sa_family_t = u8; + + #[derive(Copy, Clone)] + pub struct in_addr { + pub s_addr: u32, + } + + #[derive(Copy, Clone)] + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: u16, + pub sin_addr: in_addr, + } + + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u8; 16], + } + + #[derive(Copy, Clone)] + pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: u16, + pub sin6_addr: in6_addr, + pub sin6_flowinfo: u32, + pub sin6_scope_id: u32, + } + + #[derive(Copy, Clone)] + pub struct sockaddr {} +} + +pub type Socket = UdpSocket; diff --git a/library/std/src/sys/teeos/os.rs b/library/std/src/sys/teeos/os.rs new file mode 100644 index 00000000000..e54a92f01f8 --- /dev/null +++ b/library/std/src/sys/teeos/os.rs @@ -0,0 +1,134 @@ +//! Implementation of `std::os` functionality for teeos + +use core::marker::PhantomData; + +use crate::error::Error as StdError; +use crate::ffi::{OsStr, OsString}; +use crate::fmt; +use crate::io; +use crate::path; +use crate::path::PathBuf; + +use super::unsupported; + +pub fn errno() -> i32 { + unsafe { (*libc::__errno_location()) as i32 } +} + +// Hardcoded to return 4096, since `sysconf` is only implemented as a stub. +pub fn page_size() -> usize { + // unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }; + 4096 +} + +// Everything below are stubs and copied from unsupported.rs + +pub fn error_string(_errno: i32) -> String { + "error string unimplemented".to_string() +} + +pub fn getcwd() -> io::Result<PathBuf> { + unsupported() +} + +pub fn chdir(_: &path::Path) -> io::Result<()> { + unsupported() +} + +pub struct SplitPaths<'a>(!, PhantomData<&'a ()>); + +pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> { + panic!("unsupported") +} + +impl<'a> Iterator for SplitPaths<'a> { + type Item = PathBuf; + fn next(&mut self) -> Option<PathBuf> { + self.0 + } +} + +#[derive(Debug)] +pub struct JoinPathsError; + +pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError> +where + I: Iterator<Item = T>, + T: AsRef<OsStr>, +{ + Err(JoinPathsError) +} + +impl fmt::Display for JoinPathsError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "not supported on this platform yet".fmt(f) + } +} + +impl StdError for JoinPathsError { + #[allow(deprecated)] + fn description(&self) -> &str { + "not supported on this platform yet" + } +} + +pub fn current_exe() -> io::Result<PathBuf> { + unsupported() +} + +pub struct Env(!); + +impl Env { + // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt. + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + let Self(inner) = self; + match *inner {} + } +} + +impl fmt::Debug for Env { + fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self(inner) = self; + match *inner {} + } +} + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + let Self(inner) = self; + match *inner {} + } +} + +pub fn env() -> Env { + panic!("not supported on this platform") +} + +pub fn getenv(_: &OsStr) -> Option<OsString> { + None +} + +pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) +} + +pub fn unsetenv(_: &OsStr) -> io::Result<()> { + Err(io::Error::new(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) +} + +pub fn temp_dir() -> PathBuf { + panic!("no filesystem on this platform") +} + +pub fn home_dir() -> Option<PathBuf> { + None +} + +pub fn exit(_code: i32) -> ! { + panic!("TA should not call `exit`") +} + +pub fn getpid() -> u32 { + panic!("no pids on this platform") +} diff --git a/library/std/src/sys/teeos/rand.rs b/library/std/src/sys/teeos/rand.rs new file mode 100644 index 00000000000..b45c3bb40e7 --- /dev/null +++ b/library/std/src/sys/teeos/rand.rs @@ -0,0 +1,21 @@ +pub fn hashmap_random_keys() -> (u64, u64) { + const KEY_LEN: usize = core::mem::size_of::<u64>(); + + let mut v = [0u8; KEY_LEN * 2]; + imp::fill_bytes(&mut v); + + let key1 = v[0..KEY_LEN].try_into().unwrap(); + let key2 = v[KEY_LEN..].try_into().unwrap(); + + (u64::from_ne_bytes(key1), u64::from_ne_bytes(key2)) +} + +mod imp { + extern "C" { + fn TEE_GenerateRandom(randomBuffer: *mut core::ffi::c_void, randomBufferLen: libc::size_t); + } + + pub fn fill_bytes(v: &mut [u8]) { + unsafe { TEE_GenerateRandom(v.as_mut_ptr() as _, v.len() * crate::mem::size_of::<u8>()) } + } +} diff --git a/library/std/src/sys/teeos/stdio.rs b/library/std/src/sys/teeos/stdio.rs new file mode 100644 index 00000000000..9ca04f29273 --- /dev/null +++ b/library/std/src/sys/teeos/stdio.rs @@ -0,0 +1,88 @@ +#![deny(unsafe_op_in_unsafe_fn)] + +use crate::io; +use core::arch::asm; + +pub struct Stdin; +pub struct Stdout; +pub struct Stderr; + +const KCALL_DEBUG_CMD_PUT_BYTES: i64 = 2; + +unsafe fn debug_call(cap_ref: u64, call_no: i64, arg1: u64, arg2: u64) -> i32 { + let ret: u64; + unsafe { + asm!( + "svc #99", + inout("x0") cap_ref => ret, + in("x1") call_no, + in("x2") arg1, + in("x3") arg2, + ); + } + + ret as i32 +} + +fn print_buf(s: &[u8]) -> io::Result<usize> { + // Corresponds to `HM_DEBUG_PUT_BYTES_LIMIT`. + const MAX_LEN: usize = 512; + let len = if s.len() > MAX_LEN { MAX_LEN } else { s.len() }; + let result = unsafe { debug_call(0, KCALL_DEBUG_CMD_PUT_BYTES, s.as_ptr() as u64, len as u64) }; + + if result == 0 { Ok(len) } else { Err(io::Error::from(io::ErrorKind::InvalidInput)) } +} + +impl Stdin { + pub const fn new() -> Stdin { + Stdin + } +} + +impl io::Read for Stdin { + fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> { + Ok(0) + } +} + +impl Stdout { + pub const fn new() -> Stdout { + Stdout + } +} + +impl io::Write for Stdout { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + print_buf(buf) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl Stderr { + pub const fn new() -> Stderr { + Stderr + } +} + +impl io::Write for Stderr { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + print_buf(buf) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +pub const STDIN_BUF_SIZE: usize = 0; + +pub fn is_ebadf(err: &io::Error) -> bool { + err.raw_os_error() == Some(libc::EBADF as i32) +} + +pub fn panic_output() -> Option<impl io::Write> { + Some(Stderr::new()) +} diff --git a/library/std/src/sys/teeos/thread.rs b/library/std/src/sys/teeos/thread.rs new file mode 100644 index 00000000000..155f333f906 --- /dev/null +++ b/library/std/src/sys/teeos/thread.rs @@ -0,0 +1,164 @@ +use core::convert::TryInto; + +use crate::cmp; +use crate::ffi::CStr; +use crate::io; +use crate::mem; +use crate::num::NonZeroUsize; +use crate::ptr; +use crate::sys::os; +use crate::time::Duration; + +pub const DEFAULT_MIN_STACK_SIZE: usize = 8 * 1024; + +pub struct Thread { + id: libc::pthread_t, +} + +// Some platforms may have pthread_t as a pointer in which case we still want +// a thread to be Send/Sync +unsafe impl Send for Thread {} +unsafe impl Sync for Thread {} + +extern "C" { + pub fn TEE_Wait(timeout: u32) -> u32; +} + +impl Thread { + // unsafe: see thread::Builder::spawn_unchecked for safety requirements + pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> { + let p = Box::into_raw(Box::new(p)); + let mut native: libc::pthread_t = mem::zeroed(); + let mut attr: libc::pthread_attr_t = mem::zeroed(); + assert_eq!(libc::pthread_attr_init(&mut attr), 0); + assert_eq!( + libc::pthread_attr_settee( + &mut attr, + libc::TEESMP_THREAD_ATTR_CA_INHERIT, + libc::TEESMP_THREAD_ATTR_TASK_ID_INHERIT, + libc::TEESMP_THREAD_ATTR_HAS_SHADOW, + ), + 0, + ); + + let stack_size = cmp::max(stack, min_stack_size(&attr)); + + match libc::pthread_attr_setstacksize(&mut attr, stack_size) { + 0 => {} + n => { + assert_eq!(n, libc::EINVAL); + // EINVAL means |stack_size| is either too small or not a + // multiple of the system page size. Because it's definitely + // >= PTHREAD_STACK_MIN, it must be an alignment issue. + // Round up to the nearest page and try again. + let page_size = os::page_size(); + let stack_size = + (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); + assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0); + } + }; + + let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _); + // Note: if the thread creation fails and this assert fails, then p will + // be leaked. However, an alternative design could cause double-free + // which is clearly worse. + assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + + return if ret != 0 { + // The thread failed to start and as a result p was not consumed. Therefore, it is + // safe to reconstruct the box so that it gets deallocated. + drop(Box::from_raw(p)); + Err(io::Error::from_raw_os_error(ret)) + } else { + // The new thread will start running earliest after the next yield. + // We add a yield here, so that the user does not have to. + Thread::yield_now(); + Ok(Thread { id: native }) + }; + + extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void { + unsafe { + // Next, set up our stack overflow handler which may get triggered if we run + // out of stack. + // this is not necessary in TEE. + //let _handler = stack_overflow::Handler::new(); + // Finally, let's run some code. + Box::from_raw(main as *mut Box<dyn FnOnce()>)(); + } + ptr::null_mut() + } + } + + pub fn yield_now() { + let ret = unsafe { libc::sched_yield() }; + debug_assert_eq!(ret, 0); + } + + /// This does not do anything on teeos + pub fn set_name(_name: &CStr) { + // Both pthread_setname_np and prctl are not available to the TA, + // so we can't implement this currently. If the need arises please + // contact the teeos rustzone team. + } + + /// only main thread could wait for sometime in teeos + pub fn sleep(dur: Duration) { + let sleep_millis = dur.as_millis(); + let final_sleep: u32 = + if sleep_millis >= u32::MAX as u128 { u32::MAX } else { sleep_millis as u32 }; + unsafe { + let _ = TEE_Wait(final_sleep); + } + } + + /// must join, because no pthread_detach supported + pub fn join(self) { + unsafe { + let ret = libc::pthread_join(self.id, ptr::null_mut()); + mem::forget(self); + assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret)); + } + } + + pub fn id(&self) -> libc::pthread_t { + self.id + } + + pub fn into_id(self) -> libc::pthread_t { + let id = self.id; + mem::forget(self); + id + } +} + +impl Drop for Thread { + fn drop(&mut self) { + // we can not call detach, so just panic if thread spawn without join + panic!("thread must join, detach is not supported!"); + } +} + +// Note: Both `sched_getaffinity` and `sysconf` are available but not functional on +// teeos, so this function always returns an Error! +pub fn available_parallelism() -> io::Result<NonZeroUsize> { + Err(io::Error::new( + io::ErrorKind::NotFound, + "The number of hardware threads is not known for the target platform", + )) +} + +// stub +pub mod guard { + use crate::ops::Range; + pub type Guard = Range<usize>; + pub unsafe fn current() -> Option<Guard> { + None + } + pub unsafe fn init() -> Option<Guard> { + None + } +} + +fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { + libc::PTHREAD_STACK_MIN.try_into().expect("Infallible") +} diff --git a/library/std/src/sys/teeos/thread_local_dtor.rs b/library/std/src/sys/teeos/thread_local_dtor.rs new file mode 100644 index 00000000000..5c6bc4d6750 --- /dev/null +++ b/library/std/src/sys/teeos/thread_local_dtor.rs @@ -0,0 +1,4 @@ +pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { + use crate::sys_common::thread_local_dtor::register_dtor_fallback; + register_dtor_fallback(t, dtor); +} diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index 077698a462c..881b3a25c51 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -180,7 +180,7 @@ pub fn getcwd() -> io::Result<PathBuf> { } #[cfg(target_os = "espidf")] -pub fn chdir(p: &path::Path) -> io::Result<()> { +pub fn chdir(_p: &path::Path) -> io::Result<()> { super::unsupported::unsupported() } diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index f2e86a4fb2b..f62eb828ee5 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -23,11 +23,11 @@ struct Nanoseconds(u32); #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SystemTime { - pub(in crate::sys::unix) t: Timespec, + pub(crate) t: Timespec, } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(in crate::sys::unix) struct Timespec { +pub(crate) struct Timespec { tv_sec: i64, tv_nsec: Nanoseconds, } @@ -239,11 +239,11 @@ impl From<libc::timespec> for Timespec { not(target_arch = "riscv32") ))] #[repr(C)] -pub(in crate::sys::unix) struct __timespec64 { - pub(in crate::sys::unix) tv_sec: i64, +pub(crate) struct __timespec64 { + pub(crate) tv_sec: i64, #[cfg(target_endian = "big")] _padding: i32, - pub(in crate::sys::unix) tv_nsec: i32, + pub(crate) tv_nsec: i32, #[cfg(target_endian = "little")] _padding: i32, } @@ -255,7 +255,7 @@ pub(in crate::sys::unix) struct __timespec64 { not(target_arch = "riscv32") ))] impl __timespec64 { - pub(in crate::sys::unix) fn new(tv_sec: i64, tv_nsec: i32) -> Self { + pub(crate) fn new(tv_sec: i64, tv_nsec: i32) -> Self { Self { tv_sec, tv_nsec, _padding: 0 } } } diff --git a/library/std/src/sys/windows/api.rs b/library/std/src/sys/windows/api.rs index 72ecb950341..a7ea59e85f7 100644 --- a/library/std/src/sys/windows/api.rs +++ b/library/std/src/sys/windows/api.rs @@ -48,7 +48,7 @@ use super::c; /// converted to a `u32`. Clippy would warn about this but, alas, it's not run /// on the standard library. const fn win32_size_of<T: Sized>() -> u32 { - // Const assert that the size is less than u32::MAX. + // Const assert that the size does not exceed u32::MAX. // Uses a trait to workaround restriction on using generic types in inner items. trait Win32SizeOf: Sized { const WIN32_SIZE_OF: u32 = { diff --git a/library/std/src/sys/xous/os.rs b/library/std/src/sys/xous/os.rs index 3d19fa4b31a..8d2eaee8aa6 100644 --- a/library/std/src/sys/xous/os.rs +++ b/library/std/src/sys/xous/os.rs @@ -8,6 +8,28 @@ use crate::os::xous::ffi::Error as XousError; use crate::path::{self, PathBuf}; #[cfg(not(test))] +#[cfg(feature = "panic_unwind")] +mod eh_unwinding { + pub(crate) struct EhFrameFinder(usize /* eh_frame */); + pub(crate) static mut EH_FRAME_SETTINGS: EhFrameFinder = EhFrameFinder(0); + impl EhFrameFinder { + pub(crate) unsafe fn init(&mut self, eh_frame: usize) { + unsafe { + EH_FRAME_SETTINGS.0 = eh_frame; + } + } + } + unsafe impl unwind::EhFrameFinder for EhFrameFinder { + fn find(&self, _pc: usize) -> Option<unwind::FrameInfo> { + Some(unwind::FrameInfo { + text_base: None, + kind: unwind::FrameInfoKind::EhFrame(self.0), + }) + } + } +} + +#[cfg(not(test))] mod c_compat { use crate::os::xous::ffi::exit; extern "C" { @@ -20,7 +42,12 @@ mod c_compat { } #[no_mangle] - pub extern "C" fn _start() { + pub extern "C" fn _start(eh_frame: usize) { + #[cfg(feature = "panic_unwind")] + unsafe { + super::eh_unwinding::EH_FRAME_SETTINGS.init(eh_frame); + unwind::set_custom_eh_frame_finder(&super::eh_unwinding::EH_FRAME_SETTINGS).ok(); + } exit(unsafe { main() }); } diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index e18638f2a5f..851832a377c 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -43,15 +43,15 @@ cfg_if::cfg_if! { } cfg_if::cfg_if! { - if #[cfg(any(target_os = "l4re", - target_os = "uefi", - feature = "restricted-std", - all(target_family = "wasm", not(target_os = "emscripten")), - target_os = "xous", - all(target_vendor = "fortanix", target_env = "sgx")))] { - pub use crate::sys::net; - } else { + if #[cfg(any( + all(unix, not(target_os = "l4re")), + windows, + target_os = "hermit", + target_os = "solid_asp3" + ))] { pub mod net; + } else { + pub use crate::sys::net; } } diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 4b9ddd5aba1..8498937809e 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -1581,6 +1581,7 @@ impl<'scope, T> JoinInner<'scope, T> { /// [`thread::Builder::spawn`]: Builder::spawn /// [`thread::spawn`]: spawn #[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(target_os = "teeos", must_use)] pub struct JoinHandle<T>(JoinInner<'static, T>); #[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")] diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml index 9aa552ed81a..b7418d1189c 100644 --- a/library/unwind/Cargo.toml +++ b/library/unwind/Cargo.toml @@ -15,10 +15,13 @@ doc = false [dependencies] core = { path = "../core" } -libc = { version = "0.2.79", features = ['rustc-dep-of-std'], default-features = false } +libc = { version = "0.2.140", features = ['rustc-dep-of-std'], default-features = false } compiler_builtins = "0.1.0" cfg-if = "1.0" +[target.'cfg(target_os = "xous")'.dependencies] +unwinding = { version = "0.2.1", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false } + [features] # Only applies for Linux and Fuchsia targets diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 335bded71c1..eeee98f754e 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -26,6 +26,9 @@ cfg_if::cfg_if! { ))] { mod libunwind; pub use libunwind::*; + } else if #[cfg(target_os = "xous")] { + mod unwinding; + pub use unwinding::*; } else { // no unwinder on the system! // - wasm32 (not emscripten, which is "unix" family) diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index dba64aa74ce..1b5f6f9dde3 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -103,7 +103,10 @@ pub type _Unwind_Exception_Cleanup_Fn = // and RFC 2841 #[cfg_attr( any( - all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), + all( + feature = "llvm-libunwind", + any(target_os = "fuchsia", target_os = "linux", target_os = "xous") + ), all(target_os = "windows", target_env = "gnu", target_abi = "llvm") ), link(name = "unwind", kind = "static", modifiers = "-bundle") @@ -134,7 +137,7 @@ if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos", targe pub use _Unwind_Action::*; #[cfg_attr( - all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), + all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")), link(name = "unwind", kind = "static", modifiers = "-bundle") )] extern "C" { @@ -192,7 +195,7 @@ if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos", targe pub const UNWIND_IP_REG: c_int = 15; #[cfg_attr( - all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), + all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")), link(name = "unwind", kind = "static", modifiers = "-bundle") )] extern "C" { @@ -258,14 +261,14 @@ cfg_if::cfg_if! { if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] { // Not 32-bit iOS #[cfg_attr( - all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), + all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")), link(name = "unwind", kind = "static", modifiers = "-bundle") )] extern "C-unwind" { pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code; } #[cfg_attr( - all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")), + all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux", target_os = "xous")), link(name = "unwind", kind = "static", modifiers = "-bundle") )] extern "C" { diff --git a/library/unwind/src/unwinding.rs b/library/unwind/src/unwinding.rs new file mode 100644 index 00000000000..1a4187b2220 --- /dev/null +++ b/library/unwind/src/unwinding.rs @@ -0,0 +1,105 @@ +#![allow(nonstandard_style)] + +use libc::{c_int, c_void}; + +#[repr(C)] +#[derive(Copy, Clone, PartialEq)] +pub enum _Unwind_Action { + _UA_SEARCH_PHASE = 1, + _UA_CLEANUP_PHASE = 2, + _UA_HANDLER_FRAME = 4, + _UA_FORCE_UNWIND = 8, + _UA_END_OF_STACK = 16, +} +pub use _Unwind_Action::*; + +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum _Unwind_Reason_Code { + _URC_NO_REASON = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8, + _URC_FAILURE = 9, // used only by ARM EHABI +} +pub use _Unwind_Reason_Code::*; + +pub use unwinding::abi::UnwindContext; +pub use unwinding::abi::UnwindException; +pub enum _Unwind_Context {} + +pub use unwinding::custom_eh_frame_finder::{ + set_custom_eh_frame_finder, EhFrameFinder, FrameInfo, FrameInfoKind, +}; + +pub type _Unwind_Exception_Class = u64; +pub type _Unwind_Word = *const u8; +pub type _Unwind_Ptr = *const u8; + +pub const unwinder_private_data_size: usize = core::mem::size_of::<UnwindException>() + - core::mem::size_of::<_Unwind_Exception_Class>() + - core::mem::size_of::<_Unwind_Exception_Cleanup_Fn>(); + +pub type _Unwind_Exception_Cleanup_Fn = + extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception); + +#[repr(C)] +pub struct _Unwind_Exception { + pub exception_class: _Unwind_Exception_Class, + pub exception_cleanup: _Unwind_Exception_Cleanup_Fn, + pub private: [_Unwind_Word; unwinder_private_data_size], +} + +pub unsafe fn _Unwind_GetDataRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr { + let ctx = unsafe { &mut *(ctx as *mut UnwindContext<'_>) }; + unwinding::abi::_Unwind_GetDataRelBase(ctx) as _Unwind_Ptr +} + +pub unsafe fn _Unwind_GetTextRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr { + let ctx = unsafe { &mut *(ctx as *mut UnwindContext<'_>) }; + unwinding::abi::_Unwind_GetTextRelBase(ctx) as _Unwind_Ptr +} + +pub unsafe fn _Unwind_GetRegionStart(ctx: *mut _Unwind_Context) -> _Unwind_Ptr { + let ctx = unsafe { &mut *(ctx as *mut UnwindContext<'_>) }; + unwinding::abi::_Unwind_GetRegionStart(ctx) as _Unwind_Ptr +} + +pub unsafe fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) { + let ctx = unsafe { &mut *(ctx as *mut UnwindContext<'_>) }; + unwinding::abi::_Unwind_SetGR(ctx, reg_index, value as usize) +} + +pub unsafe fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Word) { + let ctx = unsafe { &mut *(ctx as *mut UnwindContext<'_>) }; + unwinding::abi::_Unwind_SetIP(ctx, value as usize) +} + +pub unsafe fn _Unwind_GetIPInfo( + ctx: *mut _Unwind_Context, + ip_before_insn: *mut c_int, +) -> _Unwind_Word { + let ctx = unsafe { &mut *(ctx as *mut UnwindContext<'_>) }; + let ip_before_insn = unsafe { &mut *(ip_before_insn as *mut c_int) }; + unsafe { &*(unwinding::abi::_Unwind_GetIPInfo(ctx, ip_before_insn) as _Unwind_Word) } +} + +pub unsafe fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void { + let ctx = unsafe { &mut *(ctx as *mut UnwindContext<'_>) }; + unwinding::abi::_Unwind_GetLanguageSpecificData(ctx) +} + +pub unsafe fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code { + let exception = unsafe { &mut *(exception as *mut UnwindException) }; + unsafe { core::mem::transmute(unwinding::abi::_Unwind_RaiseException(exception)) } +} + +pub unsafe fn _Unwind_DeleteException(exception: *mut _Unwind_Exception) { + let exception = unsafe { &mut *(exception as *mut UnwindException) }; + unsafe { unwinding::abi::_Unwind_DeleteException(exception) } +} diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 57113b0ec62..f452b944e75 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -370,9 +370,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.149" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "linux-raw-sys" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index e4d359141ce..24951cf20fa 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -42,7 +42,7 @@ filetime = "0.2" hex = "0.4" home = "0.5.4" ignore = "0.4.10" -libc = "0.2" +libc = "0.2.150" object = { version = "0.32.0", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] } once_cell = "1.7.2" opener = "0.5" diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 4691fb3ad6f..2328dd822af 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -946,6 +946,8 @@ class RustBuild(object): target_linker = self.get_toml("linker", build_section) if target_linker is not None: env["RUSTFLAGS"] += " -C linker=" + target_linker + # When changing this list, also update the corresponding list in `Builder::cargo` + # in `src/bootstrap/src/core/builder.rs`. env["RUSTFLAGS"] += " -Wrust_2018_idioms -Wunused_lifetimes" if self.warnings == "default": deny_warnings = self.get_toml("deny-warnings", "rust") != "false" diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 49373177abe..fe84b95f90c 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -549,12 +549,13 @@ impl Step for Vscode { if config.dry_run() { return; } - t!(create_vscode_settings_maybe(&config)); + while !t!(create_vscode_settings_maybe(&config)) {} } } /// Create a `.vscode/settings.json` file for rustc development, or just print it -fn create_vscode_settings_maybe(config: &Config) -> io::Result<()> { +/// If this method should be re-called, it returns `false`. +fn create_vscode_settings_maybe(config: &Config) -> io::Result<bool> { let (current_hash, historical_hashes) = SETTINGS_HASHES.split_last().unwrap(); let vscode_settings = config.src.join(".vscode").join("settings.json"); // If None, no settings.json exists @@ -567,7 +568,7 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result<()> { hasher.update(¤t); let hash = hex::encode(hasher.finalize().as_slice()); if hash == *current_hash { - return Ok(()); + return Ok(true); } else if historical_hashes.contains(&hash.as_str()) { mismatched_settings = Some(true); } else { @@ -587,13 +588,13 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result<()> { _ => (), } let should_create = match prompt_user( - "Would you like to create/update `settings.json`, or only print suggested settings?: [y/p/N]", + "Would you like to create/update settings.json? (Press 'p' to preview values): [y/N]", )? { Some(PromptResult::Yes) => true, Some(PromptResult::Print) => false, _ => { println!("Ok, skipping settings!"); - return Ok(()); + return Ok(true); } }; if should_create { @@ -620,5 +621,5 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result<()> { } else { println!("\n{RUST_ANALYZER_SETTINGS}"); } - Ok(()) + Ok(should_create) } diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 65af2aed6de..80dc5439b3b 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1872,7 +1872,6 @@ impl<'a> Builder<'a> { // some code doesn't go through this `rustc` wrapper. lint_flags.push("-Wrust_2018_idioms"); lint_flags.push("-Wunused_lifetimes"); - lint_flags.push("-Wsemicolon_in_expressions_from_macros"); if self.config.deny_warnings { lint_flags.push("-Dwarnings"); diff --git a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile index 341e2de223a..adf3c67479b 100644 --- a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile @@ -95,6 +95,7 @@ ENV TARGETS=$TARGETS,thumbv8m.main-none-eabihf ENV TARGETS=$TARGETS,riscv32i-unknown-none-elf ENV TARGETS=$TARGETS,riscv32imc-unknown-none-elf ENV TARGETS=$TARGETS,riscv32imac-unknown-none-elf +ENV TARGETS=$TARGETS,riscv32imafc-unknown-none-elf ENV TARGETS=$TARGETS,riscv64imac-unknown-none-elf ENV TARGETS=$TARGETS,riscv64gc-unknown-none-elf ENV TARGETS=$TARGETS,armebv7r-none-eabi diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile index 4757c3e7329..f4850715e82 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile @@ -24,8 +24,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils \ nodejs \ mingw-w64 \ + libgccjit-12-dev \ && rm -rf /var/lib/apt/lists/* +# Note: libgccjit needs to match the default gcc version for the linker to find it. + # Install powershell (universal package) so we can test x.ps1 on Linux RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \ dpkg -i powershell.deb && \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile index dc5a04d4e06..f1d6b9a4ef2 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile @@ -24,8 +24,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils \ nodejs \ mingw-w64 \ + libgccjit-13-dev \ && rm -rf /var/lib/apt/lists/* +# Note: libgccjit needs to match the default gcc version for the linker to find it. + # Install powershell (universal package) so we can test x.ps1 on Linux RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \ dpkg -i powershell.deb && \ diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index cedbc0390f8..636692a0954 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -269,14 +269,9 @@ touch $objdir/${SUMMARY_FILE} extra_env="" if [ "$ENABLE_GCC_CODEGEN" = "1" ]; then - extra_env="$EXTRA_ENV --env ENABLE_GCC_CODEGEN=1" - # If `ENABLE_GCC_CODEGEN` is set and not empty, we add the `--enable-new-symbol-mangling` - # argument to `RUST_CONFIGURE_ARGS` and set the `GCC_EXEC_PREFIX` environment variable. - # `cg_gcc` doesn't support the legacy mangling so we need to enforce the new one - # if we run `cg_gcc` tests. - extra_env="$EXTRA_ENV --env USE_NEW_MANGLING=--enable-new-symbol-mangling" + extra_env="$extra_env --env ENABLE_GCC_CODEGEN=1" # Fix rustc_codegen_gcc lto issues. - extra_env="$EXTRA_ENV --env GCC_EXEC_PREFIX=/usr/lib/gcc/" + extra_env="$extra_env --env GCC_EXEC_PREFIX=/usr/lib/gcc/" echo "Setting extra environment values for docker: $extra_env" fi diff --git a/src/ci/run.sh b/src/ci/run.sh index fa786c6c7e7..5700172fd3e 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -163,6 +163,14 @@ if [ "$IS_NOT_LATEST_LLVM" = "" ]; then export COMPILETEST_NEEDS_ALL_LLVM_COMPONENTS=1 fi +if [ "$ENABLE_GCC_CODEGEN" = "1" ]; then + # If `ENABLE_GCC_CODEGEN` is set and not empty, we add the `--enable-new-symbol-mangling` + # argument to `RUST_CONFIGURE_ARGS` and set the `GCC_EXEC_PREFIX` environment variable. + # `cg_gcc` doesn't support the legacy mangling so we need to enforce the new one + # if we run `cg_gcc` tests. + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-new-symbol-mangling" +fi + # Print the date from the local machine and the date from an external source to # check for clock drifts. An HTTP URL is used instead of HTTPS since on Azure # Pipelines it happened that the certificates were marked as expired. diff --git a/src/doc/nomicon b/src/doc/nomicon -Subproject 1842257814919fa62e81bdecd5e8f95be2839db +Subproject 83d015105e6d490fc30d6c95da1e56152a50e22 diff --git a/src/doc/reference b/src/doc/reference -Subproject cd8193e972f61b92117095fc73b67af767b4d6b +Subproject 692d216f5a1151e8852ddb308ba64040e634c87 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject a6581246f96837113968c02187db24f742af390 +Subproject da0a06aada31a324ae84a9eaee344f6a944b968 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject ddb8b1309f9e905804cea1e248a4572fed6b464 +Subproject 904bb5aa7b21adad58ffae610e2830c7b0f813b diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 3bd90f7062d..ad335389514 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -45,6 +45,7 @@ - [nvptx64-nvidia-cuda](platform-support/nvptx64-nvidia-cuda.md) - [powerpc64-ibm-aix](platform-support/aix.md) - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md) + - [riscv32*-unknown-none-elf](platform-support/riscv32imac-unknown-none-elf.md) - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md) - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md) - [\*-nto-qnx-\*](platform-support/nto-qnx.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 3671fdd3fd2..457e8d90a43 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -159,9 +159,9 @@ target | std | notes [`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * | | LoongArch64 Bare-metal (LP64D ABI) [`loongarch64-unknown-none-softfloat`](platform-support/loongarch-none.md) | * | | LoongArch64 Bare-metal (LP64S ABI) [`nvptx64-nvidia-cuda`](platform-support/nvptx64-nvidia-cuda.md) | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs] -`riscv32i-unknown-none-elf` | * | Bare RISC-V (RV32I ISA) -`riscv32imac-unknown-none-elf` | * | Bare RISC-V (RV32IMAC ISA) -`riscv32imc-unknown-none-elf` | * | Bare RISC-V (RV32IMC ISA) +[`riscv32imac-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | Bare RISC-V (RV32IMAC ISA) +[`riscv32i-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | Bare RISC-V (RV32I ISA) +[`riscv32imc-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | Bare RISC-V (RV32IMC ISA) `riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA) `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA) `sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23) @@ -314,7 +314,8 @@ target | std | host | notes [`powerpc64-ibm-aix`](platform-support/aix.md) | ? | | 64-bit AIX (7.2 and newer) `riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33) `riscv32gc-unknown-linux-musl` | | | RISC-V Linux (kernel 5.4, musl + RISCV32 support patches) -`riscv32im-unknown-none-elf` | * | | Bare RISC-V (RV32IM ISA) +[`riscv32imafc-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | Bare RISC-V (RV32IMAFC ISA) +[`riscv32im-unknown-none-elf`](platform-support/riscv32imac-unknown-none-elf.md) | * | | Bare RISC-V (RV32IM ISA) [`riscv32imac-unknown-xous-elf`](platform-support/riscv32imac-unknown-xous-elf.md) | ? | | RISC-V Xous (RV32IMAC ISA) [`riscv32imc-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF [`riscv32imac-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF diff --git a/src/doc/rustc/src/platform-support/aarch64-unknown-teeos.md b/src/doc/rustc/src/platform-support/aarch64-unknown-teeos.md index 9233a36db3d..7a6609b2d76 100644 --- a/src/doc/rustc/src/platform-support/aarch64-unknown-teeos.md +++ b/src/doc/rustc/src/platform-support/aarch64-unknown-teeos.md @@ -39,7 +39,7 @@ Create the following shell scripts that wrap Clang from the OpenHarmony SDK: ```sh #!/bin/sh exec /path/to/ohos-sdk/linux/native/llvm/bin/clang \ - --target aarch64-linux-gnu \ + -target aarch64-linux-gnu \ "$@" ``` @@ -48,7 +48,7 @@ exec /path/to/ohos-sdk/linux/native/llvm/bin/clang \ ```sh #!/bin/sh exec /path/to/ohos-sdk/linux/native/llvm/bin/clang++ \ - --target aarch64-linux-gnu \ + -target aarch64-linux-gnu \ "$@" ``` @@ -81,6 +81,13 @@ ranlib = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ranlib" llvm-config = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-config" ``` +```text +note: You need to insert "/usr/include/x86_64-linux-gnu/" into environment variable: $C_INCLUDE_PATH + if some header files like bits/xxx.h not found. +note: You can install gcc-aarch64-linux-gnu,g++-aarch64-linux-gnu if some files like crti.o not found. +note: You may need to install libc6-dev-i386 libc6-dev if "gnu/stubs-32.h" not found. +``` + ## Building Rust programs Rust does not yet ship pre-compiled artifacts for this target. To compile for @@ -91,7 +98,7 @@ this target, you will either need to build Rust with the target enabled (see You will need to configure the linker to use in `~/.cargo/config`: ```toml [target.aarch64-unknown-teeos] -linker = "/path/to/aarch64-unknown-teeos-clang.sh" +linker = "/path/to/aarch64-unknown-teeos-clang.sh" # or aarch64-linux-gnu-ld ``` ## Testing diff --git a/src/doc/rustc/src/platform-support/riscv32i-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32i-unknown-none-elf.md new file mode 100644 index 00000000000..edfe07fc053 --- /dev/null +++ b/src/doc/rustc/src/platform-support/riscv32i-unknown-none-elf.md @@ -0,0 +1 @@ +riscv32imac-unknown-none-elf.md diff --git a/src/doc/rustc/src/platform-support/riscv32im-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32im-unknown-none-elf.md new file mode 100644 index 00000000000..edfe07fc053 --- /dev/null +++ b/src/doc/rustc/src/platform-support/riscv32im-unknown-none-elf.md @@ -0,0 +1 @@ +riscv32imac-unknown-none-elf.md diff --git a/src/doc/rustc/src/platform-support/riscv32imac-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32imac-unknown-none-elf.md new file mode 100644 index 00000000000..a069f3d3aa9 --- /dev/null +++ b/src/doc/rustc/src/platform-support/riscv32imac-unknown-none-elf.md @@ -0,0 +1,34 @@ +# `riscv32{i,im,imc,imac,imafc}-unknown-none-elf` + +**Tier: 2/3** + +Bare-metal target for RISC-V CPUs with the RV32I, RV32IM, RV32IMC, RV32IMAFC and RV32IMAC ISAs. + +## Target maintainers + +* Rust Embedded Working Group, [RISC-V team](https://github.com/rust-embedded/wg#the-risc-v-team) + +## Requirements + +The target is cross-compiled, and uses static linking. No external toolchain +is required and the default `rust-lld` linker works, but you must specify +a linker script. The [`riscv-rt`] crate provides a suitable one. The +[`riscv-rust-quickstart`] repository gives an example of an RV32 project. + +[`riscv-rt`]: https://crates.io/crates/riscv-rt +[`riscv-rust-quickstart`]: https://github.com/riscv-rust/riscv-rust-quickstart + +## Building the target + +This target is included in Rust and can be installed via `rustup`. + +## Testing + +This is a cross-compiled no-std target, which must be run either in a simulator +or by programming them onto suitable hardware. It is not possible to run the +Rust testsuite on this target. + +## Cross-compilation toolchains and C code + +This target supports C code. If interlinking with C or C++, you may need to use +riscv64-unknown-elf-gcc as a linker instead of rust-lld. diff --git a/src/doc/rustc/src/platform-support/riscv32imafc-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32imafc-unknown-none-elf.md new file mode 100644 index 00000000000..edfe07fc053 --- /dev/null +++ b/src/doc/rustc/src/platform-support/riscv32imafc-unknown-none-elf.md @@ -0,0 +1 @@ +riscv32imac-unknown-none-elf.md diff --git a/src/doc/rustc/src/platform-support/riscv32imc-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32imc-unknown-none-elf.md new file mode 100644 index 00000000000..edfe07fc053 --- /dev/null +++ b/src/doc/rustc/src/platform-support/riscv32imc-unknown-none-elf.md @@ -0,0 +1 @@ +riscv32imac-unknown-none-elf.md diff --git a/src/doc/unstable-book/src/compiler-flags/check-cfg.md b/src/doc/unstable-book/src/compiler-flags/check-cfg.md index bcfab790478..a5b9169c9f3 100644 --- a/src/doc/unstable-book/src/compiler-flags/check-cfg.md +++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md @@ -190,70 +190,3 @@ fn shoot_lasers() {} // the cfg(feature) list fn write_shakespeare() {} ``` - -## The deprecated `names(...)` form - -The `names(...)` form enables checking the names. This form uses a named list: - -```bash -rustc --check-cfg 'names(name1, name2, ... nameN)' -``` - -where each `name` is a bare identifier (has no quotes). The order of the names is not significant. - -If `--check-cfg names(...)` is specified at least once, then `rustc` will check all references to -condition names. `rustc` will check every `#[cfg]` attribute, `#[cfg_attr]` attribute, `cfg` clause -inside `#[link]` attribute and `cfg!(...)` call against the provided list of expected condition -names. If a name is not present in this list, then `rustc` will report an `unexpected_cfgs` lint -diagnostic. The default diagnostic level for this lint is `Warn`. - -If `--check-cfg names(...)` is not specified, then `rustc` will not check references to condition -names. - -`--check-cfg names(...)` may be specified more than once. The result is that the list of valid -condition names is merged across all options. It is legal for a condition name to be specified -more than once; redundantly specifying a condition name has no effect. - -To enable checking condition names with an empty set of valid condition names, use the following -form. The parentheses are required. - -```bash -rustc --check-cfg 'names()' -``` - -Note that `--check-cfg 'names()'` is _not_ equivalent to omitting the option entirely. -The first form enables checking condition names, while specifying that there are no valid -condition names (outside of the set of well-known names defined by `rustc`). Omitting the -`--check-cfg 'names(...)'` option does not enable checking condition names. - -## The deprecated `values(...)` form - -The `values(...)` form enables checking the values within list-valued conditions. It has this -form: - -```bash -rustc --check-cfg `values(name, "value1", "value2", ... "valueN")' -``` - -where `name` is a bare identifier (has no quotes) and each `"value"` term is a quoted literal -string. `name` specifies the name of the condition, such as `feature` or `target_os`. - -When the `values(...)` option is specified, `rustc` will check every `#[cfg(name = "value")]` -attribute, `#[cfg_attr(name = "value")]` attribute, `#[link(name = "a", cfg(name = "value"))]` -and `cfg!(name = "value")` call. It will check that the `"value"` specified is present in the -list of expected values. If `"value"` is not in it, then `rustc` will report an `unexpected_cfgs` -lint diagnostic. The default diagnostic level for this lint is `Warn`. - -To enable checking of values, but to provide an empty set of valid values, use this form: - -```bash -rustc --check-cfg `values(name)` -``` - -The `--check-cfg values(...)` option can be repeated, both for the same condition name and for -different names. If it is repeated for the same condition name, then the sets of values for that -condition are merged together. - -If `values()` is specified, then `rustc` will enable the checking of well-known values defined -by itself. Note that it's necessary to specify the `values()` form to enable the checking of -well known values, specifying the other forms doesn't implicitly enable it. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index fe1f43835ef..688751627f3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -595,13 +595,13 @@ fn clean_generic_param<'tcx>( }, ) } - hir::GenericParamKind::Const { ty, default } => ( + hir::GenericParamKind::Const { ty, default, is_host_effect } => ( param.name.ident().name, GenericParamDefKind::Const { ty: Box::new(clean_ty(ty, cx)), default: default .map(|ct| Box::new(ty::Const::from_anon_const(cx.tcx, ct.def_id).to_string())), - is_host_effect: cx.tcx.has_attr(param.def_id, sym::rustc_host), + is_host_effect, }, ), }; @@ -2536,11 +2536,12 @@ fn clean_generic_args<'tcx>( } hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()), hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)), - // Checking for `#[rustc_host]` on the `AnonConst` not only accounts for the case + // Checking for `is_desugared_from_effects` on the `AnonConst` not only accounts for the case // where the argument is `host` but for all possible cases (e.g., `true`, `false`). - hir::GenericArg::Const(ct) - if cx.tcx.has_attr(ct.value.def_id, sym::rustc_host) => - { + hir::GenericArg::Const(hir::ConstArg { + is_desugared_from_effects: true, + .. + }) => { return None; } hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))), diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index e076c1b92e6..58599de76ea 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -673,7 +673,7 @@ fn short_item_info( format!("Deprecating in {version}") } } - DeprecatedSince::Future => String::from("Deprecating in a future Rust version"), + DeprecatedSince::Future => String::from("Deprecating in a future version"), DeprecatedSince::NonStandard(since) => { format!("Deprecated since {}", Escape(since.as_str())) } diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 83c7ccc9ede..9ac97236f19 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -124,6 +124,7 @@ static TARGETS: &[&str] = &[ "riscv32im-unknown-none-elf", "riscv32imc-unknown-none-elf", "riscv32imac-unknown-none-elf", + "riscv32imafc-unknown-none-elf", "riscv32gc-unknown-linux-gnu", "riscv64imac-unknown-none-elf", "riscv64gc-unknown-hermit", diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 623b788496b3e51dc2f9282373cf0f6971a229b +Subproject 9787229614b27854cf73d57ffae430d7c1e6caa diff --git a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs index e50e83834c1..640d4a069ec 100644 --- a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs +++ b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs @@ -3,7 +3,7 @@ use std::{io, thread}; use crate::doc::{NEEDLESS_DOCTEST_MAIN, TEST_ATTR_IN_DOCTEST}; use clippy_utils::diagnostics::span_lint; -use rustc_ast::{Async, Fn, FnRetTy, Item, ItemKind}; +use rustc_ast::{CoroutineKind, Fn, FnRetTy, Item, ItemKind}; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::EmitterWriter; use rustc_errors::Handler; @@ -69,7 +69,7 @@ pub fn check( if !ignore { get_test_spans(&item, &mut test_attr_spans); } - let is_async = matches!(sig.header.asyncness, Async::Yes { .. }); + let is_async = matches!(sig.header.coro_kind, Some(CoroutineKind::Async { .. })); let returns_nothing = match &sig.decl.output { FnRetTy::Default(..) => true, FnRetTy::Ty(ty) if ty.kind.is_unit() => true, diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index a2c61e07b70..12403bbff3c 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -188,7 +188,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { Closure(box ast::Closure { binder: lb, capture_clause: lc, - asyncness: la, + coro_kind: la, movability: lm, fn_decl: lf, body: le, @@ -197,7 +197,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { Closure(box ast::Closure { binder: rb, capture_clause: rc, - asyncness: ra, + coro_kind: ra, movability: rm, fn_decl: rf, body: re, @@ -206,7 +206,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { ) => { eq_closure_binder(lb, rb) && lc == rc - && la.is_async() == ra.is_async() + && la.map_or(false, |la| la.is_async()) == ra.map_or(false, |ra| ra.is_async()) && lm == rm && eq_fn_decl(lf, rf) && eq_expr(le, re) @@ -563,9 +563,18 @@ pub fn eq_fn_sig(l: &FnSig, r: &FnSig) -> bool { eq_fn_decl(&l.decl, &r.decl) && eq_fn_header(&l.header, &r.header) } +fn eq_opt_coro_kind(l: Option<CoroutineKind>, r: Option<CoroutineKind>) -> bool { + match (l, r) { + (Some(CoroutineKind::Async { .. }), Some(CoroutineKind::Async { .. })) + | (Some(CoroutineKind::Gen { .. }), Some(CoroutineKind::Gen { .. })) => true, + (None, None) => true, + _ => false, + } +} + pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool { matches!(l.unsafety, Unsafe::No) == matches!(r.unsafety, Unsafe::No) - && l.asyncness.is_async() == r.asyncness.is_async() + && eq_opt_coro_kind(l.coro_kind, r.coro_kind) && matches!(l.constness, Const::No) == matches!(r.constness, Const::No) && eq_ext(&l.ext, &r.ext) } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index af224360319..055671afd14 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -4288,15 +4288,18 @@ impl<'test> TestCx<'test> { let mut seen_allocs = indexmap::IndexSet::new(); // The alloc-id appears in pretty-printed allocations. - let re = Regex::new(r"╾─*a(lloc)?([0-9]+)(\+0x[0-9]+)?─*╼").unwrap(); + let re = + Regex::new(r"╾─*a(lloc)?([0-9]+)(\+0x[0-9]+)?(<imm>)?( \([0-9]+ ptr bytes\))?─*╼") + .unwrap(); normalized = re .replace_all(&normalized, |caps: &Captures<'_>| { // Renumber the captured index. let index = caps.get(2).unwrap().as_str().to_string(); let (index, _) = seen_allocs.insert_full(index); let offset = caps.get(3).map_or("", |c| c.as_str()); + let imm = caps.get(4).map_or("", |c| c.as_str()); // Do not bother keeping it pretty, just make it deterministic. - format!("╾ALLOC{index}{offset}╼") + format!("╾ALLOC{index}{offset}{imm}╼") }) .into_owned(); diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 5cdeedafe95..504b6bd140e 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -165,6 +165,7 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { level: SymbolExportLevel::C, kind: SymbolExportKind::Text, used: false, + used_compiler: false, }, )) }), diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index fb90559f3d1..ef394b16310 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -44,7 +44,7 @@ pub enum TerminationInfo { }, DataRace { involves_non_atomic: bool, - ptr: Pointer, + ptr: Pointer<AllocId>, op1: RacingOp, op2: RacingOp, extra: Option<&'static str>, diff --git a/src/tools/miri/src/intptrcast.rs b/src/tools/miri/src/intptrcast.rs index cd4d1bcc464..68c9a7660eb 100644 --- a/src/tools/miri/src/intptrcast.rs +++ b/src/tools/miri/src/intptrcast.rs @@ -256,12 +256,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { /// Convert a relative (tcx) pointer to a Miri pointer. fn ptr_from_rel_ptr( &self, - ptr: Pointer<AllocId>, + ptr: Pointer<CtfeProvenance>, tag: BorTag, ) -> InterpResult<'tcx, Pointer<Provenance>> { let ecx = self.eval_context_ref(); - let (alloc_id, offset) = ptr.into_parts(); // offset is relative (AllocId provenance) + let (prov, offset) = ptr.into_parts(); // offset is relative (AllocId provenance) + let alloc_id = prov.alloc_id(); let base_addr = ecx.addr_from_alloc_id(alloc_id)?; // Add offset with the right kind of pointer-overflowing arithmetic. diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 243dc5e779b..4a878f4a36e 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -17,6 +17,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::static_assert_size; use rustc_middle::{ mir, + query::TyCtxtAt, ty::{ self, layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout}, @@ -259,6 +260,17 @@ impl interpret::Provenance for Provenance { } } + fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (prov, addr) = ptr.into_parts(); // address is absolute + write!(f, "{:#x}", addr.bytes())?; + if f.alternate() { + write!(f, "{prov:#?}")?; + } else { + write!(f, "{prov:?}")?; + } + Ok(()) + } + fn join(left: Option<Self>, right: Option<Self>) -> Option<Self> { match (left, right) { // If both are the *same* concrete tag, that is the result. @@ -1170,11 +1182,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { fn adjust_alloc_base_pointer( ecx: &MiriInterpCx<'mir, 'tcx>, - ptr: Pointer<AllocId>, + ptr: Pointer<CtfeProvenance>, ) -> InterpResult<'tcx, Pointer<Provenance>> { + let alloc_id = ptr.provenance.alloc_id(); if cfg!(debug_assertions) { // The machine promises to never call us on thread-local or extern statics. - let alloc_id = ptr.provenance; match ecx.tcx.try_get_global_alloc(alloc_id) { Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_thread_local_static(def_id) => { panic!("adjust_alloc_base_pointer called on thread-local static") @@ -1185,8 +1197,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { _ => {} } } + // FIXME: can we somehow preserve the immutability of `ptr`? let tag = if let Some(borrow_tracker) = &ecx.machine.borrow_tracker { - borrow_tracker.borrow_mut().base_ptr_tag(ptr.provenance, &ecx.machine) + borrow_tracker.borrow_mut().base_ptr_tag(alloc_id, &ecx.machine) } else { // Value does not matter, SB is disabled BorTag::default() @@ -1245,7 +1258,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { #[inline(always)] fn before_memory_read( - _tcx: TyCtxt<'tcx>, + _tcx: TyCtxtAt<'tcx>, machine: &Self, alloc_extra: &AllocExtra<'tcx>, (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra), @@ -1265,7 +1278,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { #[inline(always)] fn before_memory_write( - _tcx: TyCtxt<'tcx>, + _tcx: TyCtxtAt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra<'tcx>, (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra), @@ -1285,7 +1298,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { #[inline(always)] fn before_memory_deallocation( - _tcx: TyCtxt<'tcx>, + _tcx: TyCtxtAt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra<'tcx>, (alloc_id, prove_extra): (AllocId, Self::ProvenanceExtra), diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 84bd15efb8b..58833cb7e92 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -13,7 +13,7 @@ #![cfg(feature = "sysroot-abi")] #![feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span)] #![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] -#![allow(unreachable_pub)] +#![allow(unreachable_pub, internal_features)] extern crate proc_macro; diff --git a/src/tools/rustfmt/src/closures.rs b/src/tools/rustfmt/src/closures.rs index 8a4089a56f0..c1ce87eadcb 100644 --- a/src/tools/rustfmt/src/closures.rs +++ b/src/tools/rustfmt/src/closures.rs @@ -29,7 +29,7 @@ pub(crate) fn rewrite_closure( binder: &ast::ClosureBinder, constness: ast::Const, capture: ast::CaptureBy, - is_async: &ast::Async, + coro_kind: &Option<ast::CoroutineKind>, movability: ast::Movability, fn_decl: &ast::FnDecl, body: &ast::Expr, @@ -40,7 +40,7 @@ pub(crate) fn rewrite_closure( debug!("rewrite_closure {:?}", body); let (prefix, extra_offset) = rewrite_closure_fn_decl( - binder, constness, capture, is_async, movability, fn_decl, body, span, context, shape, + binder, constness, capture, coro_kind, movability, fn_decl, body, span, context, shape, )?; // 1 = space between `|...|` and body. let body_shape = shape.offset_left(extra_offset)?; @@ -233,7 +233,7 @@ fn rewrite_closure_fn_decl( binder: &ast::ClosureBinder, constness: ast::Const, capture: ast::CaptureBy, - asyncness: &ast::Async, + coro_kind: &Option<ast::CoroutineKind>, movability: ast::Movability, fn_decl: &ast::FnDecl, body: &ast::Expr, @@ -263,7 +263,11 @@ fn rewrite_closure_fn_decl( } else { "" }; - let is_async = if asyncness.is_async() { "async " } else { "" }; + let coro = match coro_kind { + Some(ast::CoroutineKind::Async { .. }) => "async ", + Some(ast::CoroutineKind::Gen { .. }) => "gen ", + None => "", + }; let mover = if matches!(capture, ast::CaptureBy::Value { .. }) { "move " } else { @@ -272,7 +276,7 @@ fn rewrite_closure_fn_decl( // 4 = "|| {".len(), which is overconservative when the closure consists of // a single expression. let nested_shape = shape - .shrink_left(binder.len() + const_.len() + immovable.len() + is_async.len() + mover.len())? + .shrink_left(binder.len() + const_.len() + immovable.len() + coro.len() + mover.len())? .sub_width(4)?; // 1 = | @@ -310,7 +314,7 @@ fn rewrite_closure_fn_decl( .tactic(tactic) .preserve_newline(true); let list_str = write_list(&item_vec, &fmt)?; - let mut prefix = format!("{binder}{const_}{immovable}{is_async}{mover}|{list_str}|"); + let mut prefix = format!("{binder}{const_}{immovable}{coro}{mover}|{list_str}|"); if !ret_str.is_empty() { if prefix.contains('\n') { @@ -339,7 +343,7 @@ pub(crate) fn rewrite_last_closure( ref binder, constness, capture_clause, - ref asyncness, + ref coro_kind, movability, ref fn_decl, ref body, @@ -360,7 +364,7 @@ pub(crate) fn rewrite_last_closure( binder, constness, capture_clause, - asyncness, + coro_kind, movability, fn_decl, body, diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 60e0e007b1d..4515c27be37 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -212,7 +212,7 @@ pub(crate) fn format_expr( &cl.binder, cl.constness, cl.capture_clause, - &cl.asyncness, + &cl.coro_kind, cl.movability, &cl.fn_decl, &cl.body, diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index edb5a5b629a..4dff65f8cd0 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -287,7 +287,7 @@ pub(crate) struct FnSig<'a> { decl: &'a ast::FnDecl, generics: &'a ast::Generics, ext: ast::Extern, - is_async: Cow<'a, ast::Async>, + coro_kind: Cow<'a, Option<ast::CoroutineKind>>, constness: ast::Const, defaultness: ast::Defaultness, unsafety: ast::Unsafe, @@ -302,7 +302,7 @@ impl<'a> FnSig<'a> { ) -> FnSig<'a> { FnSig { unsafety: method_sig.header.unsafety, - is_async: Cow::Borrowed(&method_sig.header.asyncness), + coro_kind: Cow::Borrowed(&method_sig.header.coro_kind), constness: method_sig.header.constness, defaultness: ast::Defaultness::Final, ext: method_sig.header.ext, @@ -328,7 +328,7 @@ impl<'a> FnSig<'a> { generics, ext: fn_sig.header.ext, constness: fn_sig.header.constness, - is_async: Cow::Borrowed(&fn_sig.header.asyncness), + coro_kind: Cow::Borrowed(&fn_sig.header.coro_kind), defaultness, unsafety: fn_sig.header.unsafety, visibility: vis, @@ -343,7 +343,8 @@ impl<'a> FnSig<'a> { result.push_str(&*format_visibility(context, self.visibility)); result.push_str(format_defaultness(self.defaultness)); result.push_str(format_constness(self.constness)); - result.push_str(format_async(&self.is_async)); + self.coro_kind + .map(|coro_kind| result.push_str(format_coro(&coro_kind))); result.push_str(format_unsafety(self.unsafety)); result.push_str(&format_extern( self.ext, diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index fd49030bf1b..5805e417c04 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -75,10 +75,10 @@ pub(crate) fn format_visibility( } #[inline] -pub(crate) fn format_async(is_async: &ast::Async) -> &'static str { - match is_async { - ast::Async::Yes { .. } => "async ", - ast::Async::No => "", +pub(crate) fn format_coro(coro_kind: &ast::CoroutineKind) -> &'static str { + match coro_kind { + ast::CoroutineKind::Async { .. } => "async ", + ast::CoroutineKind::Gen { .. } => "gen ", } } diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 6baf2e21604..b38d5436477 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -372,6 +372,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "unicode-security", "unicode-width", "unicode-xid", + "unwinding", "valuable", "version_check", "wasi", diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 40149f8f1c3..dfa386b49de 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -11,7 +11,7 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. const ISSUES_ENTRY_LIMIT: usize = 1852; -const ROOT_ENTRY_LIMIT: usize = 866; +const ROOT_ENTRY_LIMIT: usize = 867; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/codegen/sanitizer/cfi-normalize-integers.rs b/tests/codegen/sanitizer/cfi-normalize-integers.rs index 9663aa54c28..d3cece4c7b6 100644 --- a/tests/codegen/sanitizer/cfi-normalize-integers.rs +++ b/tests/codegen/sanitizer/cfi-normalize-integers.rs @@ -6,78 +6,41 @@ #![crate_type="lib"] extern crate core; -use core::ffi::*; pub fn foo0(_: bool) { } // CHECK: define{{.*}}foo0{{.*}}!type ![[TYPE0:[0-9]+]] !type !{{[0-9]+}} -pub fn foo1(_: bool, _: c_uchar) { } +pub fn foo1(_: bool, _: bool) { } // CHECK: define{{.*}}foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} -pub fn foo2(_: bool, _: c_uchar, _: c_uchar) { } +pub fn foo2(_: bool, _: bool, _: bool) { } // CHECK: define{{.*}}foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} -pub fn foo3(_: isize) { } +pub fn foo3(_: char) { } // CHECK: define{{.*}}foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} -pub fn foo4(_: isize, _: c_long) { } +pub fn foo4(_: char, _: char) { } // CHECK: define{{.*}}foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} -pub fn foo5(_: isize, _: c_long, _: c_longlong) { } +pub fn foo5(_: char, _: char, _: char) { } // CHECK: define{{.*}}foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} -pub fn foo6(_: usize) { } +pub fn foo6(_: isize) { } // CHECK: define{{.*}}foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} -pub fn foo7(_: usize, _: c_ulong) { } +pub fn foo7(_: isize, _: isize) { } // CHECK: define{{.*}}foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} -pub fn foo8(_: usize, _: c_ulong, _: c_ulonglong) { } +pub fn foo8(_: isize, _: isize, _: isize) { } // CHECK: define{{.*}}foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} -pub fn foo9(_: c_schar) { } +pub fn foo9(_: (), _: usize) { } // CHECK: define{{.*}}foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} -pub fn foo10(_: c_char, _: c_schar) { } +pub fn foo10(_: (), _: usize, _: usize) { } // CHECK: define{{.*}}foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} -pub fn foo11(_: c_char, _: c_schar, _: c_schar) { } +pub fn foo11(_: (), _: usize, _: usize, _: usize) { } // CHECK: define{{.*}}foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} -pub fn foo12(_: c_int) { } -// CHECK: define{{.*}}foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} -pub fn foo13(_: c_int, _: c_int) { } -// CHECK: define{{.*}}foo13{{.*}}!type ![[TYPE13:[0-9]+]] !type !{{[0-9]+}} -pub fn foo14(_: c_int, _: c_int, _: c_int) { } -// CHECK: define{{.*}}foo14{{.*}}!type ![[TYPE14:[0-9]+]] !type !{{[0-9]+}} -pub fn foo15(_: c_short) { } -// CHECK: define{{.*}}foo15{{.*}}!type ![[TYPE15:[0-9]+]] !type !{{[0-9]+}} -pub fn foo16(_: c_short, _: c_short) { } -// CHECK: define{{.*}}foo16{{.*}}!type ![[TYPE16:[0-9]+]] !type !{{[0-9]+}} -pub fn foo17(_: c_short, _: c_short, _: c_short) { } -// CHECK: define{{.*}}foo17{{.*}}!type ![[TYPE17:[0-9]+]] !type !{{[0-9]+}} -pub fn foo18(_: c_uint) { } -// CHECK: define{{.*}}foo18{{.*}}!type ![[TYPE18:[0-9]+]] !type !{{[0-9]+}} -pub fn foo19(_: c_uint, _: c_uint) { } -// CHECK: define{{.*}}foo19{{.*}}!type ![[TYPE19:[0-9]+]] !type !{{[0-9]+}} -pub fn foo20(_: c_uint, _: c_uint, _: c_uint) { } -// CHECK: define{{.*}}foo20{{.*}}!type ![[TYPE20:[0-9]+]] !type !{{[0-9]+}} -pub fn foo21(_: c_ushort) { } -// CHECK: define{{.*}}foo21{{.*}}!type ![[TYPE21:[0-9]+]] !type !{{[0-9]+}} -pub fn foo22(_: c_ushort, _: c_ushort) { } -// CHECK: define{{.*}}foo22{{.*}}!type ![[TYPE22:[0-9]+]] !type !{{[0-9]+}} -pub fn foo23(_: c_ushort, _: c_ushort, _: c_ushort) { } -// CHECK: define{{.*}}foo23{{.*}}!type ![[TYPE23:[0-9]+]] !type !{{[0-9]+}} // CHECK: ![[TYPE0]] = !{i64 0, !"_ZTSFvu2u8E.normalized"} // CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu2u8S_E.normalized"} // CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu2u8S_S_E.normalized"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64}}E.normalized"} -// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64}}{{u3i32|u3i64|S_}}E.normalized"} -// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64}}{{u3i32|u3i64|S_}}{{u3i64|S_|S0_}}E.normalized"} -// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64}}E.normalized"} -// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64}}{{u3u32|u3u64|S_}}E.normalized"} -// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64}}{{u3u32|u3u64|S_}}{{u3u64|S_|S0_}}E.normalized"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu2i8E.normalized"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFv{{u2i8S_|u2u8u2i8}}E.normalized"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFv{{u2i8S_S_|u2u8u2i8S0_}}E.normalized"} -// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64}}E.normalized"} -// CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64}}S_E.normalized"} -// CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64}}S_S_E.normalized"} -// CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvu3i16E.normalized"} -// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3i16S_E.normalized"} -// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3i16S_S_E.normalized"} -// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64}}E.normalized"} -// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64}}S_E.normalized"} -// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64}}S_S_E.normalized"} -// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3u16E.normalized"} -// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3u16S_E.normalized"} -// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3u16S_S_E.normalized"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3u32E.normalized"} +// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3u32S_E.normalized"} +// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3u32S_S_E.normalized"} +// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}E.normalized"} +// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}S_E.normalized"} +// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}S_S_E.normalized"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvv{{u3u16|u3u32|u3u64|u4u128}}E.normalized"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvv{{u3u16|u3u32|u3u64|u4u128}}S_E.normalized"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvv{{u3u16|u3u32|u3u64|u4u128}}S_S_E.normalized"} diff --git a/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir index f20bfef8c79..9cc4c7c4d76 100644 --- a/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir +++ b/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir @@ -18,19 +18,19 @@ fn main() -> () { } ALLOC9 (static: FOO, size: 8, align: 4) { - ╾ALLOC0╼ 03 00 00 00 │ ╾──╼.... + ╾ALLOC0<imm>╼ 03 00 00 00 │ ╾──╼.... } ALLOC0 (size: 48, align: 4) { - 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC1╼ 00 00 00 00 │ ....░░░░╾──╼.... - 0x10 │ 00 00 00 00 __ __ __ __ ╾ALLOC2╼ 02 00 00 00 │ ....░░░░╾──╼.... - 0x20 │ 01 00 00 00 2a 00 00 00 ╾ALLOC3╼ 03 00 00 00 │ ....*...╾──╼.... + 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC1<imm>╼ 00 00 00 00 │ ....░░░░╾──╼.... + 0x10 │ 00 00 00 00 __ __ __ __ ╾ALLOC2<imm>╼ 02 00 00 00 │ ....░░░░╾──╼.... + 0x20 │ 01 00 00 00 2a 00 00 00 ╾ALLOC3<imm>╼ 03 00 00 00 │ ....*...╾──╼.... } ALLOC1 (size: 0, align: 4) {} ALLOC2 (size: 16, align: 4) { - ╾ALLOC4╼ 03 00 00 00 ╾ALLOC5╼ 03 00 00 00 │ ╾──╼....╾──╼.... + ╾ALLOC4<imm>╼ 03 00 00 00 ╾ALLOC5<imm>╼ 03 00 00 00 │ ╾──╼....╾──╼.... } ALLOC4 (size: 3, align: 1) { @@ -42,8 +42,8 @@ ALLOC5 (size: 3, align: 1) { } ALLOC3 (size: 24, align: 4) { - 0x00 │ ╾ALLOC6╼ 03 00 00 00 ╾ALLOC7╼ 03 00 00 00 │ ╾──╼....╾──╼.... - 0x10 │ ╾ALLOC8╼ 04 00 00 00 │ ╾──╼.... + 0x00 │ ╾ALLOC6<imm>╼ 03 00 00 00 ╾ALLOC7<imm>╼ 03 00 00 00 │ ╾──╼....╾──╼.... + 0x10 │ ╾ALLOC8<imm>╼ 04 00 00 00 │ ╾──╼.... } ALLOC6 (size: 3, align: 1) { diff --git a/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir index 263cae2f3ea..faa9d20f2d5 100644 --- a/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir +++ b/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir @@ -18,22 +18,22 @@ fn main() -> () { } ALLOC9 (static: FOO, size: 16, align: 8) { - ╾ALLOC0╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + ╾ALLOC0<imm>╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ } ALLOC0 (size: 72, align: 8) { - 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC1╼ │ ....░░░░╾──────╼ + 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC1<imm>╼ │ ....░░░░╾──────╼ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............â–‘â–‘â–‘â–‘ - 0x20 │ ╾ALLOC2╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x30 │ 01 00 00 00 2a 00 00 00 ╾ALLOC3╼ │ ....*...╾──────╼ + 0x20 │ ╾ALLOC2<imm>╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x30 │ 01 00 00 00 2a 00 00 00 ╾ALLOC3<imm>╼ │ ....*...╾──────╼ 0x40 │ 03 00 00 00 00 00 00 00 │ ........ } ALLOC1 (size: 0, align: 8) {} ALLOC2 (size: 32, align: 8) { - 0x00 │ ╾ALLOC4╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x10 │ ╾ALLOC5╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x00 │ ╾ALLOC4<imm>╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x10 │ ╾ALLOC5<imm>╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ } ALLOC4 (size: 3, align: 1) { @@ -45,9 +45,9 @@ ALLOC5 (size: 3, align: 1) { } ALLOC3 (size: 48, align: 8) { - 0x00 │ ╾ALLOC6╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x10 │ ╾ALLOC7╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x20 │ ╾ALLOC8╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x00 │ ╾ALLOC6<imm>╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x10 │ ╾ALLOC7<imm>╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x20 │ ╾ALLOC8<imm>╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ } ALLOC6 (size: 3, align: 1) { diff --git a/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir index 713abb264a7..898835b46e4 100644 --- a/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir +++ b/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir @@ -18,19 +18,19 @@ fn main() -> () { } ALLOC9 (static: FOO, size: 8, align: 4) { - ╾ALLOC0╼ 03 00 00 00 │ ╾──╼.... + ╾ALLOC0<imm>╼ 03 00 00 00 │ ╾──╼.... } ALLOC0 (size: 48, align: 4) { - 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC1╼ 00 00 00 00 │ ....░░░░╾──╼.... - 0x10 │ 00 00 00 00 __ __ __ __ ╾ALLOC2╼ 02 00 00 00 │ ....░░░░╾──╼.... - 0x20 │ 01 00 00 00 2a 00 00 00 ╾ALLOC3╼ 03 00 00 00 │ ....*...╾──╼.... + 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC1<imm>╼ 00 00 00 00 │ ....░░░░╾──╼.... + 0x10 │ 00 00 00 00 __ __ __ __ ╾ALLOC2<imm>╼ 02 00 00 00 │ ....░░░░╾──╼.... + 0x20 │ 01 00 00 00 2a 00 00 00 ╾ALLOC3<imm>╼ 03 00 00 00 │ ....*...╾──╼.... } ALLOC1 (size: 0, align: 4) {} ALLOC2 (size: 8, align: 4) { - ╾ALLOC4╼ ╾ALLOC5╼ │ ╾──╼╾──╼ + ╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼ │ ╾──╼╾──╼ } ALLOC4 (size: 1, align: 1) { @@ -42,7 +42,7 @@ ALLOC5 (size: 1, align: 1) { } ALLOC3 (size: 12, align: 4) { - ╾ALLOC6+0x3╼ ╾ALLOC7╼ ╾ALLOC8+0x2╼ │ ╾──╼╾──╼╾──╼ + ╾ALLOC6+0x3<imm>╼ ╾ALLOC7<imm>╼ ╾ALLOC8+0x2<imm>╼ │ ╾──╼╾──╼╾──╼ } ALLOC6 (size: 4, align: 1) { diff --git a/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir index e9d61ef120c..f5352c2aebb 100644 --- a/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir +++ b/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir @@ -18,21 +18,21 @@ fn main() -> () { } ALLOC9 (static: FOO, size: 16, align: 8) { - ╾ALLOC0╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + ╾ALLOC0<imm>╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ } ALLOC0 (size: 72, align: 8) { - 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC1╼ │ ....░░░░╾──────╼ + 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC1<imm>╼ │ ....░░░░╾──────╼ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............â–‘â–‘â–‘â–‘ - 0x20 │ ╾ALLOC2╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x30 │ 01 00 00 00 2a 00 00 00 ╾ALLOC3╼ │ ....*...╾──────╼ + 0x20 │ ╾ALLOC2<imm>╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x30 │ 01 00 00 00 2a 00 00 00 ╾ALLOC3<imm>╼ │ ....*...╾──────╼ 0x40 │ 03 00 00 00 00 00 00 00 │ ........ } ALLOC1 (size: 0, align: 8) {} ALLOC2 (size: 16, align: 8) { - ╾ALLOC4╼ ╾ALLOC5╼ │ ╾──────╼╾──────╼ + ╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼ │ ╾──────╼╾──────╼ } ALLOC4 (size: 1, align: 1) { @@ -44,8 +44,8 @@ ALLOC5 (size: 1, align: 1) { } ALLOC3 (size: 24, align: 8) { - 0x00 │ ╾ALLOC6+0x3╼ ╾ALLOC7╼ │ ╾──────╼╾──────╼ - 0x10 │ ╾ALLOC8+0x2╼ │ ╾──────╼ + 0x00 │ ╾ALLOC6+0x3<imm>╼ ╾ALLOC7<imm>╼ │ ╾──────╼╾──────╼ + 0x10 │ ╾ALLOC8+0x2<imm>╼ │ ╾──────╼ } ALLOC6 (size: 4, align: 1) { diff --git a/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir index c18c067c72e..624047f5b6f 100644 --- a/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir +++ b/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir @@ -18,12 +18,12 @@ fn main() -> () { } ALLOC4 (static: FOO, size: 4, align: 4) { - ╾ALLOC0╼ │ ╾──╼ + ╾ALLOC0<imm>╼ │ ╾──╼ } ALLOC0 (size: 168, align: 1) { 0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................ - 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾ALLOC1╼ │ ............╾──╼ + 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾ALLOC1<imm>╼ │ ............╾──╼ 0x20 │ 01 ef cd ab 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ @@ -31,7 +31,7 @@ ALLOC0 (size: 168, align: 1) { 0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾ALLOC2╼ 00 00 │ ..........╾──╼.. - 0x90 │ ╾ALLOC3+0x63╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............ + 0x90 │ ╾ALLOC3+0x63<imm>╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............ 0xa0 │ 00 00 00 00 00 00 00 00 │ ........ } diff --git a/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir index 6af0e3cbd94..cdd4758e153 100644 --- a/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir +++ b/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir @@ -18,12 +18,12 @@ fn main() -> () { } ALLOC2 (static: FOO, size: 8, align: 8) { - ╾ALLOC0╼ │ ╾──────╼ + ╾ALLOC0<imm>╼ │ ╾──────╼ } ALLOC0 (size: 180, align: 1) { 0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................ - 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──ALLOC3── │ ............╾─── + 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾ALLOC3<imm> (8 ptr bytes) │ ............╾─── 0x20 │ ──────────╼ 01 ef cd ab 00 00 00 00 00 00 00 00 │ ───╼............ 0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ @@ -31,7 +31,7 @@ ALLOC0 (size: 180, align: 1) { 0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x80 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ╾──── │ ..............╾─ - 0x90 │ ─────ALLOC4─────╼ 00 00 ╾ALLOC1+0x63╼ │ ─────╼..╾──────╼ + 0x90 │ ─────ALLOC4─────╼ 00 00 ╾ALLOC1+0x63<imm>╼ │ ─────╼..╾──────╼ 0xa0 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0xb0 │ 00 00 00 00 │ .... } diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff index d502b198239..053981abea3 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff @@ -118,7 +118,7 @@ } ALLOC2 (static: RC, size: 4, align: 4) { - ╾ALLOC0╼ │ ╾──╼ + ╾ALLOC0<imm>╼ │ ╾──╼ } ALLOC0 (size: 8, align: 4) { diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff index 5d69572b507..d862bd93ff5 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff @@ -118,7 +118,7 @@ } ALLOC2 (static: RC, size: 8, align: 8) { - ╾ALLOC0╼ │ ╾──────╼ + ╾ALLOC0<imm>╼ │ ╾──────╼ } ALLOC0 (size: 8, align: 4) { diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff index 8499d0a89c3..0f461f515fd 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff @@ -220,11 +220,11 @@ } ALLOC5 (static: BIG_STAT, size: 4, align: 4) { - ╾ALLOC0╼ │ ╾──╼ + ╾ALLOC0<imm>╼ │ ╾──╼ } ALLOC0 (size: 20, align: 4) { - 0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1╼ 02 00 00 00 │ ....#...╾──╼.... + 0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1<imm>╼ 02 00 00 00 │ ....#...╾──╼.... 0x10 │ 00 00 a4 42 │ ...B } @@ -233,11 +233,11 @@ } ALLOC4 (static: SMALL_STAT, size: 4, align: 4) { - ╾ALLOC2╼ │ ╾──╼ + ╾ALLOC2<imm>╼ │ ╾──╼ } ALLOC2 (size: 20, align: 4) { - 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3╼ 01 00 00 00 │ ....░░░░╾──╼.... + 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3<imm>╼ 01 00 00 00 │ ....░░░░╾──╼.... 0x10 │ 00 00 10 41 │ ...A } diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff index 01ec3f623d1..3c40ec8bfb4 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff @@ -220,11 +220,11 @@ } ALLOC5 (static: BIG_STAT, size: 8, align: 8) { - ╾ALLOC0╼ │ ╾──────╼ + ╾ALLOC0<imm>╼ │ ╾──────╼ } ALLOC0 (size: 32, align: 8) { - 0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1╼ │ ....#...╾──────╼ + 0x00 │ 01 00 00 00 23 00 00 00 ╾ALLOC1<imm>╼ │ ....#...╾──────╼ 0x10 │ 02 00 00 00 00 00 00 00 00 00 a4 42 __ __ __ __ │ ...........Bâ–‘â–‘â–‘â–‘ } @@ -233,11 +233,11 @@ } ALLOC4 (static: SMALL_STAT, size: 8, align: 8) { - ╾ALLOC2╼ │ ╾──────╼ + ╾ALLOC2<imm>╼ │ ╾──────╼ } ALLOC2 (size: 32, align: 8) { - 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3╼ │ ....░░░░╾──────╼ + 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC3<imm>╼ │ ....░░░░╾──────╼ 0x10 │ 01 00 00 00 00 00 00 00 00 00 10 41 __ __ __ __ │ ...........Aâ–‘â–‘â–‘â–‘ } diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff index eaea5db77c9..d5628dc7a6e 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff @@ -78,7 +78,7 @@ StorageLive(_6); _9 = const _; - _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb4, unwind unreachable]; -+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb4, unwind unreachable]; ++ _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb4, unwind unreachable]; } bb4: { diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff index f2c2504f802..d28059458ae 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff @@ -76,7 +76,7 @@ StorageLive(_6); _9 = const _; - _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb5, unwind continue]; -+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb5, unwind continue]; ++ _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(4 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x00000000): std::ptr::alignment::AlignmentEnum32) }}, const false) -> [return: bb5, unwind continue]; } bb5: { diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff index d31a9a5c079..d139fc73e21 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff @@ -78,7 +78,7 @@ StorageLive(_6); _9 = const _; - _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb4, unwind unreachable]; -+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb4, unwind unreachable]; ++ _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb4, unwind unreachable]; } bb4: { diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff index 62e05a68955..63db9553b37 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff @@ -76,7 +76,7 @@ StorageLive(_6); _9 = const _; - _6 = std::alloc::Global::alloc_impl(_9, _1, const false) -> [return: bb5, unwind continue]; -+ _6 = std::alloc::Global::alloc_impl(const {ALLOC1: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb5, unwind continue]; ++ _6 = std::alloc::Global::alloc_impl(const {ALLOC1<imm>: &std::alloc::Global}, const Layout {{ size: Indirect { alloc_id: ALLOC0, offset: Size(8 bytes) }: usize, align: std::ptr::Alignment(Scalar(0x0000000000000000): std::ptr::alignment::AlignmentEnum64) }}, const false) -> [return: bb5, unwind continue]; } bb5: { diff --git a/tests/run-make/jobserver-error/cannot_open_fd.stderr b/tests/run-make/jobserver-error/cannot_open_fd.stderr index 343de5cd52c..a2f77a94e4f 100644 --- a/tests/run-make/jobserver-error/cannot_open_fd.stderr +++ b/tests/run-make/jobserver-error/cannot_open_fd.stderr @@ -4,3 +4,5 @@ warning: failed to connect to jobserver from environment variable `MAKEFLAGS="-- error: no input filename given +warning: 1 warning emitted + diff --git a/tests/run-make/jobserver-error/not_a_pipe.stderr b/tests/run-make/jobserver-error/not_a_pipe.stderr index 536c04576b9..9158fda6e47 100644 --- a/tests/run-make/jobserver-error/not_a_pipe.stderr +++ b/tests/run-make/jobserver-error/not_a_pipe.stderr @@ -2,3 +2,5 @@ warning: failed to connect to jobserver from environment variable `MAKEFLAGS="-- | = note: the build environment is likely misconfigured +warning: 1 warning emitted + diff --git a/tests/run-make/no-builtins-symbols/Makefile b/tests/run-make/no-builtins-symbols/Makefile new file mode 100644 index 00000000000..4bb35c1d486 --- /dev/null +++ b/tests/run-make/no-builtins-symbols/Makefile @@ -0,0 +1,7 @@ +include ../tools.mk + +# only-x86_64-unknown-linux-gnu + +all: + $(RUSTC) main.rs -o $(TMPDIR)/main + [ "$$("$(LLVM_BIN_DIR)"/llvm-nm -U $(TMPDIR)/main | grep -c __fixunssfti)" -eq "0" ] diff --git a/tests/run-make/no-builtins-symbols/main.rs b/tests/run-make/no-builtins-symbols/main.rs new file mode 100644 index 00000000000..f328e4d9d04 --- /dev/null +++ b/tests/run-make/no-builtins-symbols/main.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/rustdoc/deprecated-future-staged-api.rs b/tests/rustdoc/deprecated-future-staged-api.rs index 09120b8d411..64dfd893050 100644 --- a/tests/rustdoc/deprecated-future-staged-api.rs +++ b/tests/rustdoc/deprecated-future-staged-api.rs @@ -12,7 +12,7 @@ pub struct S1; // @has deprecated_future_staged_api/index.html '//*[@class="stab deprecated"]' \ // 'Deprecation planned' // @has deprecated_future_staged_api/struct.S2.html '//*[@class="stab deprecated"]' \ -// 'Deprecating in a future Rust version: literally never' +// 'Deprecating in a future version: literally never' #[deprecated(since = "TBD", note = "literally never")] #[stable(feature = "deprecated_future_staged_api", since = "1.0.0")] pub struct S2; diff --git a/tests/ui-fulldeps/pprust-expr-roundtrip.rs b/tests/ui-fulldeps/pprust-expr-roundtrip.rs index 685a029dcb2..9e581620ec1 100644 --- a/tests/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/tests/ui-fulldeps/pprust-expr-roundtrip.rs @@ -132,7 +132,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) { binder: ClosureBinder::NotPresent, capture_clause: CaptureBy::Value { move_kw: DUMMY_SP }, constness: Const::No, - asyncness: Async::No, + coro_kind: None, movability: Movability::Movable, fn_decl: decl.clone(), body: e, diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs index 976dfee774b..5cb07eabf41 100644 --- a/tests/ui-fulldeps/stable-mir/check_instance.rs +++ b/tests/ui-fulldeps/stable-mir/check_instance.rs @@ -64,8 +64,12 @@ fn test_body(body: mir::Body) { let RigidTy::FnDef(def, args) = ty else { unreachable!() }; let instance = Instance::resolve(def, &args).unwrap(); let mangled_name = instance.mangled_name(); - let body = instance.body(); - assert!(body.is_some() || mangled_name == "setpwent", "Failed: {func:?}"); + assert!(instance.has_body() || (mangled_name == "setpwent"), "Failed: {func:?}"); + assert!(instance.has_body() ^ instance.is_foreign_item()); + if instance.has_body() { + let body = instance.body().unwrap(); + assert!(!body.locals().is_empty(), "Body must at least have a return local"); + } } Goto { .. } | Assert { .. } | SwitchInt { .. } | Return | Drop { .. } => { /* Do nothing */ diff --git a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs new file mode 100644 index 00000000000..b90d47d4540 --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs @@ -0,0 +1,115 @@ +// run-pass +//! Test that users are able to use stable mir APIs to retrieve monomorphized types, and that +//! we have an error handling for trying to instantiate types with incorrect arguments. + +// ignore-stage1 +// ignore-cross-compile +// ignore-remote +// ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 +// edition: 2021 + +#![feature(rustc_private)] +#![feature(assert_matches)] +#![feature(control_flow_enum)] + +extern crate rustc_middle; +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate stable_mir; + +use rustc_middle::ty::TyCtxt; +use rustc_smir::rustc_internal; +use stable_mir::ty::{RigidTy, TyKind, Ty, }; +use stable_mir::mir::{Body, MirVisitor, FieldIdx, Place, ProjectionElem, visit::{Location, + PlaceContext}}; +use std::io::Write; +use std::ops::ControlFlow; + +const CRATE_NAME: &str = "input"; + +/// This function uses the Stable MIR APIs to get information about the test crate. +fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { + let main_fn = stable_mir::entry_fn(); + let body = main_fn.unwrap().body(); + let mut visitor = PlaceVisitor{ body: &body, tested: false}; + visitor.visit_body(&body); + assert!(visitor.tested); + ControlFlow::Continue(()) +} + +struct PlaceVisitor<'a> { + body: &'a Body, + /// Used to ensure that the test was reachable. Otherwise this test would vacuously succeed. + tested: bool, +} + +/// Check that `wrapper.inner` place projection can be correctly interpreted. +/// Ensure that instantiation is correct. +fn check_tys(local_ty: Ty, idx: FieldIdx, expected_ty: Ty) { + let TyKind::RigidTy(RigidTy::Adt(def, args)) = local_ty.kind() else { unreachable!() }; + assert_eq!(def.ty_with_args(&args), local_ty); + + let field_def = &def.variants_iter().next().unwrap().fields()[idx]; + let field_ty = field_def.ty_with_args(&args); + assert_eq!(field_ty, expected_ty); + + // Check that the generic version is different than the instantiated one. + let field_ty_gen = field_def.ty(); + assert_ne!(field_ty_gen, field_ty); +} + +impl<'a> MirVisitor for PlaceVisitor<'a> { + fn visit_place(&mut self, place: &Place, _ptx: PlaceContext, _loc: Location) { + let start_ty = self.body.locals()[place.local].ty; + match place.projection.as_slice() { + [ProjectionElem::Field(idx, ty)] => { + check_tys(start_ty, *idx, *ty); + self.tested = true; + } + _ => {} + } + } +} + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "ty_fold_input.rs"; + generate_input(&path).unwrap(); + let args = vec![ + "rustc".to_string(), + "-Cpanic=abort".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + run!(args, tcx, test_stable_mir(tcx)).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + struct Wrapper<T: Default> {{ + pub inner: T + }} + + impl<T: Default> Wrapper<T> {{ + pub fn new() -> Wrapper<T> {{ + Wrapper {{ inner: T::default() }} + }} + }} + + fn main() {{ + let wrapper = Wrapper::<u8>::new(); + let _inner = wrapper.inner; + }} + "# + )?; + Ok(()) +} diff --git a/tests/ui/associated-types/associated-type-shadowed-from-non-local-supertrait.rs b/tests/ui/associated-types/associated-type-shadowed-from-non-local-supertrait.rs new file mode 100644 index 00000000000..045a43548dc --- /dev/null +++ b/tests/ui/associated-types/associated-type-shadowed-from-non-local-supertrait.rs @@ -0,0 +1,15 @@ +// Test that no help message is emitted that suggests renaming the +// associated type from a non-local trait + +pub trait NewIter: Iterator { + type Item; +} + +impl<T> Clone for Box<dyn NewIter<Item = T>> { + //~^ ERROR the value of the associated type `Item` in `Iterator` must be specified + fn clone(&self) -> Self { + unimplemented!(); + } +} + +pub fn main() {} diff --git a/tests/ui/associated-types/associated-type-shadowed-from-non-local-supertrait.stderr b/tests/ui/associated-types/associated-type-shadowed-from-non-local-supertrait.stderr new file mode 100644 index 00000000000..fdb4e4fc1a8 --- /dev/null +++ b/tests/ui/associated-types/associated-type-shadowed-from-non-local-supertrait.stderr @@ -0,0 +1,12 @@ +error[E0191]: the value of the associated type `Item` in `Iterator` must be specified + --> $DIR/associated-type-shadowed-from-non-local-supertrait.rs:8:27 + | +LL | type Item; + | --------- `Iterator::Item` shadowed here, consider renaming it +... +LL | impl<T> Clone for Box<dyn NewIter<Item = T>> { + | ^^^^^^^^^^^^^^^^^ associated type `Item` must be specified + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0191`. diff --git a/tests/ui/associated-types/associated-type-shadowed-from-supertrait.rs b/tests/ui/associated-types/associated-type-shadowed-from-supertrait.rs new file mode 100644 index 00000000000..95d03892838 --- /dev/null +++ b/tests/ui/associated-types/associated-type-shadowed-from-supertrait.rs @@ -0,0 +1,19 @@ +// Test Setting the value of an associated type +// that is shadowed from a supertrait + +pub trait Super { + type X; +} + +pub trait Sub: Super { + type X; +} + +impl<T> Clone for Box<dyn Sub<X = T>> { + //~^ ERROR value of the associated type `X` in `Super` must be specified + fn clone(&self) -> Self { + unimplemented!(); + } +} + +pub fn main() {} diff --git a/tests/ui/associated-types/associated-type-shadowed-from-supertrait.stderr b/tests/ui/associated-types/associated-type-shadowed-from-supertrait.stderr new file mode 100644 index 00000000000..e6cec255eee --- /dev/null +++ b/tests/ui/associated-types/associated-type-shadowed-from-supertrait.stderr @@ -0,0 +1,15 @@ +error[E0191]: the value of the associated type `X` in `Super` must be specified + --> $DIR/associated-type-shadowed-from-supertrait.rs:12:27 + | +LL | type X; + | ------ `Super::X` defined here, consider renaming it +... +LL | type X; + | ------ `Super::X` shadowed here, consider renaming it +... +LL | impl<T> Clone for Box<dyn Sub<X = T>> { + | ^^^^^^^^^^ associated type `X` must be specified + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0191`. diff --git a/tests/ui/borrowck/accidentally-cloning-ref-borrow-error.rs b/tests/ui/borrowck/accidentally-cloning-ref-borrow-error.rs new file mode 100644 index 00000000000..2b25a5b2348 --- /dev/null +++ b/tests/ui/borrowck/accidentally-cloning-ref-borrow-error.rs @@ -0,0 +1,38 @@ +#[derive(Debug)] +struct X<T>(T); + +impl<T: Clone> Clone for X<T> { + fn clone(&self) -> X<T> { + X(self.0.clone()) + } +} + +#[derive(Debug)] +struct Y; + +#[derive(Debug)] +struct Str { + x: Option<i32>, +} + +fn foo(s: &mut Option<i32>) { + if s.is_none() { + *s = Some(0); + } + println!("{:?}", s); +} + +fn bar<T: std::fmt::Debug>(s: &mut X<T>) { + println!("{:?}", s); +} +fn main() { + let s = Str { x: None }; + let sr = &s; + let mut sm = sr.clone(); + foo(&mut sm.x); //~ ERROR cannot borrow `sm.x` as mutable, as it is behind a `&` reference + + let x = X(Y); + let xr = &x; + let mut xm = xr.clone(); + bar(&mut xm); //~ ERROR cannot borrow data in a `&` reference as mutable +} diff --git a/tests/ui/borrowck/accidentally-cloning-ref-borrow-error.stderr b/tests/ui/borrowck/accidentally-cloning-ref-borrow-error.stderr new file mode 100644 index 00000000000..7e51a4819ee --- /dev/null +++ b/tests/ui/borrowck/accidentally-cloning-ref-borrow-error.stderr @@ -0,0 +1,30 @@ +error[E0596]: cannot borrow `sm.x` as mutable, as it is behind a `&` reference + --> $DIR/accidentally-cloning-ref-borrow-error.rs:32:9 + | +LL | foo(&mut sm.x); + | ^^^^^^^^^ `sm` is a `&` reference, so the data it refers to cannot be borrowed as mutable + | +help: `Str` doesn't implement `Clone`, so this call clones the reference `&Str` + --> $DIR/accidentally-cloning-ref-borrow-error.rs:31:21 + | +LL | let mut sm = sr.clone(); + | ^^^^^^^ +help: consider annotating `Str` with `#[derive(Clone)]` + | +LL + #[derive(Clone)] +LL | struct Str { + | +help: consider specifying this binding's type + | +LL | let mut sm: &mut Str = sr.clone(); + | ++++++++++ + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/accidentally-cloning-ref-borrow-error.rs:37:9 + | +LL | bar(&mut xm); + | ^^^^^^^ cannot borrow as mutable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.fixed b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.fixed new file mode 100644 index 00000000000..0b7551b97af --- /dev/null +++ b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.fixed @@ -0,0 +1,7 @@ +// run-rustfix +use std::rc::Rc; + +pub fn main() { + let _x = <Vec<i32> as Clone>::clone(&Rc::new(vec![1, 2])).into_iter(); + //~^ ERROR [E0507] +} diff --git a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs index 0b9e7102cd5..5cb8ceaca08 100644 --- a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs +++ b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.rs @@ -1,3 +1,4 @@ +// run-rustfix use std::rc::Rc; pub fn main() { diff --git a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr index 02794a12fad..076f0ce3440 100644 --- a/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr +++ b/tests/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of an `Rc` - --> $DIR/borrowck-move-out-of-overloaded-auto-deref.rs:4:14 + --> $DIR/borrowck-move-out-of-overloaded-auto-deref.rs:5:14 | LL | let _x = Rc::new(vec![1, 2]).into_iter(); | ^^^^^^^^^^^^^^^^^^^ ----------- value moved due to this method call @@ -10,8 +10,8 @@ note: `into_iter` takes ownership of the receiver `self`, which moves value --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL help: you can `clone` the value and consume it, but this might not be your desired behavior | -LL | let _x = Rc::new(vec![1, 2]).clone().into_iter(); - | ++++++++ +LL | let _x = <Vec<i32> as Clone>::clone(&Rc::new(vec![1, 2])).into_iter(); + | ++++++++++++++++++++++++++++ + error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/clone-span-on-try-operator.fixed b/tests/ui/borrowck/clone-span-on-try-operator.fixed index 52f66e43a93..4fad75b9a3d 100644 --- a/tests/ui/borrowck/clone-span-on-try-operator.fixed +++ b/tests/ui/borrowck/clone-span-on-try-operator.fixed @@ -7,5 +7,5 @@ impl Foo { } fn main() { let foo = &Foo; - (*foo).clone().foo(); //~ ERROR cannot move out + <Foo as Clone>::clone(&(*foo)).foo(); //~ ERROR cannot move out } diff --git a/tests/ui/borrowck/clone-span-on-try-operator.stderr b/tests/ui/borrowck/clone-span-on-try-operator.stderr index 5a55088d67a..adf84e49a9f 100644 --- a/tests/ui/borrowck/clone-span-on-try-operator.stderr +++ b/tests/ui/borrowck/clone-span-on-try-operator.stderr @@ -13,8 +13,8 @@ LL | fn foo(self) {} | ^^^^ help: you can `clone` the value and consume it, but this might not be your desired behavior | -LL | (*foo).clone().foo(); - | ++++++++ +LL | <Foo as Clone>::clone(&(*foo)).foo(); + | +++++++++++++++++++++++ + error: aborting due to 1 previous error diff --git a/tests/ui/borrowck/issue-83760.fixed b/tests/ui/borrowck/issue-83760.fixed new file mode 100644 index 00000000000..4544eeb6e19 --- /dev/null +++ b/tests/ui/borrowck/issue-83760.fixed @@ -0,0 +1,47 @@ +// run-rustfix +#![allow(unused_variables, dead_code)] +#[derive(Clone)] +struct Struct; +#[derive(Clone)] +struct Struct2; +// We use a second one here because otherwise when applying suggestions we'd end up with two +// `#[derive(Clone)]` annotations. + +fn test1() { + let mut val = Some(Struct); + while let Some(ref foo) = val { //~ ERROR use of moved value + if true { + val = None; + } else { + + } + } +} + +fn test2() { + let mut foo = Some(Struct); + let _x = foo.clone().unwrap(); + if true { + foo = Some(Struct); + } else { + } + let _y = foo; //~ ERROR use of moved value: `foo` +} + +fn test3() { + let mut foo = Some(Struct2); + let _x = foo.clone().unwrap(); + if true { + foo = Some(Struct2); + } else if true { + foo = Some(Struct2); + } else if true { + foo = Some(Struct2); + } else if true { + foo = Some(Struct2); + } else { + } + let _y = foo; //~ ERROR use of moved value: `foo` +} + +fn main() {} diff --git a/tests/ui/borrowck/issue-83760.rs b/tests/ui/borrowck/issue-83760.rs index e25b4f72785..81bfdf0fcc7 100644 --- a/tests/ui/borrowck/issue-83760.rs +++ b/tests/ui/borrowck/issue-83760.rs @@ -1,4 +1,9 @@ +// run-rustfix +#![allow(unused_variables, dead_code)] struct Struct; +struct Struct2; +// We use a second one here because otherwise when applying suggestions we'd end up with two +// `#[derive(Clone)]` annotations. fn test1() { let mut val = Some(Struct); @@ -22,16 +27,16 @@ fn test2() { } fn test3() { - let mut foo = Some(Struct); + let mut foo = Some(Struct2); let _x = foo.unwrap(); if true { - foo = Some(Struct); + foo = Some(Struct2); } else if true { - foo = Some(Struct); + foo = Some(Struct2); } else if true { - foo = Some(Struct); + foo = Some(Struct2); } else if true { - foo = Some(Struct); + foo = Some(Struct2); } else { } let _y = foo; //~ ERROR use of moved value: `foo` diff --git a/tests/ui/borrowck/issue-83760.stderr b/tests/ui/borrowck/issue-83760.stderr index a585bff0c65..d120adbc03b 100644 --- a/tests/ui/borrowck/issue-83760.stderr +++ b/tests/ui/borrowck/issue-83760.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value - --> $DIR/issue-83760.rs:5:20 + --> $DIR/issue-83760.rs:10:20 | LL | while let Some(foo) = val { | ^^^ value moved here, in previous iteration of loop @@ -14,7 +14,7 @@ LL | while let Some(ref foo) = val { | +++ error[E0382]: use of moved value: `foo` - --> $DIR/issue-83760.rs:21:14 + --> $DIR/issue-83760.rs:26:14 | LL | let mut foo = Some(Struct); | ------- move occurs because `foo` has type `Option<Struct>`, which does not implement the `Copy` trait @@ -29,12 +29,21 @@ LL | let _y = foo; | note: `Option::<T>::unwrap` takes ownership of the receiver `self`, which moves `foo` --> $SRC_DIR/core/src/option.rs:LL:COL +help: you could `clone` the value and consume it, if the `Struct: Clone` trait bound could be satisfied + | +LL | let _x = foo.clone().unwrap(); + | ++++++++ +help: consider annotating `Struct` with `#[derive(Clone)]` + | +LL + #[derive(Clone)] +LL | struct Struct; + | error[E0382]: use of moved value: `foo` - --> $DIR/issue-83760.rs:37:14 + --> $DIR/issue-83760.rs:42:14 | -LL | let mut foo = Some(Struct); - | ------- move occurs because `foo` has type `Option<Struct>`, which does not implement the `Copy` trait +LL | let mut foo = Some(Struct2); + | ------- move occurs because `foo` has type `Option<Struct2>`, which does not implement the `Copy` trait LL | let _x = foo.unwrap(); | -------- `foo` moved due to this method call ... @@ -42,18 +51,27 @@ LL | let _y = foo; | ^^^ value used here after move | note: these 3 reinitializations and 1 other might get skipped - --> $DIR/issue-83760.rs:30:9 + --> $DIR/issue-83760.rs:35:9 | -LL | foo = Some(Struct); - | ^^^^^^^^^^^^^^^^^^ +LL | foo = Some(Struct2); + | ^^^^^^^^^^^^^^^^^^^ LL | } else if true { -LL | foo = Some(Struct); - | ^^^^^^^^^^^^^^^^^^ +LL | foo = Some(Struct2); + | ^^^^^^^^^^^^^^^^^^^ LL | } else if true { -LL | foo = Some(Struct); - | ^^^^^^^^^^^^^^^^^^ +LL | foo = Some(Struct2); + | ^^^^^^^^^^^^^^^^^^^ note: `Option::<T>::unwrap` takes ownership of the receiver `self`, which moves `foo` --> $SRC_DIR/core/src/option.rs:LL:COL +help: you could `clone` the value and consume it, if the `Struct2: Clone` trait bound could be satisfied + | +LL | let _x = foo.clone().unwrap(); + | ++++++++ +help: consider annotating `Struct2` with `#[derive(Clone)]` + | +LL + #[derive(Clone)] +LL | struct Struct2; + | error: aborting due to 3 previous errors diff --git a/tests/ui/borrowck/issue-85765-closure.rs b/tests/ui/borrowck/issue-85765-closure.rs index f2d1dd0fbc3..edc9eeaffb5 100644 --- a/tests/ui/borrowck/issue-85765-closure.rs +++ b/tests/ui/borrowck/issue-85765-closure.rs @@ -3,6 +3,7 @@ fn main() { let mut test = Vec::new(); let rofl: &Vec<Vec<i32>> = &mut test; //~^ HELP consider changing this binding's type + //~| HELP you can `clone` the `Vec<Vec<i32>>` value and consume it, but this might not be your desired behavior rofl.push(Vec::new()); //~^ ERROR cannot borrow `*rofl` as mutable, as it is behind a `&` reference //~| NOTE `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable diff --git a/tests/ui/borrowck/issue-85765-closure.stderr b/tests/ui/borrowck/issue-85765-closure.stderr index 936ddd67bcd..4a6a0e94bec 100644 --- a/tests/ui/borrowck/issue-85765-closure.stderr +++ b/tests/ui/borrowck/issue-85765-closure.stderr @@ -1,16 +1,21 @@ error[E0596]: cannot borrow `*rofl` as mutable, as it is behind a `&` reference - --> $DIR/issue-85765-closure.rs:6:9 + --> $DIR/issue-85765-closure.rs:7:9 | LL | rofl.push(Vec::new()); | ^^^^ `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable | +help: you can `clone` the `Vec<Vec<i32>>` value and consume it, but this might not be your desired behavior + --> $DIR/issue-85765-closure.rs:4:36 + | +LL | let rofl: &Vec<Vec<i32>> = &mut test; + | ^^^^^^^^^ help: consider changing this binding's type | LL | let rofl: &mut Vec<Vec<i32>> = &mut test; | ~~~~~~~~~~~~~~~~~~ error[E0594]: cannot assign to `*r`, which is behind a `&` reference - --> $DIR/issue-85765-closure.rs:13:9 + --> $DIR/issue-85765-closure.rs:14:9 | LL | *r = 0; | ^^^^^^ `r` is a `&` reference, so the data it refers to cannot be written @@ -21,7 +26,7 @@ LL | let r = &mut mutvar; | +++ error[E0594]: cannot assign to `*x`, which is behind a `&` reference - --> $DIR/issue-85765-closure.rs:20:9 + --> $DIR/issue-85765-closure.rs:21:9 | LL | *x = 1; | ^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written @@ -32,7 +37,7 @@ LL | let x: &mut usize = &mut{0}; | ~~~~~~~~~~ error[E0594]: cannot assign to `*y`, which is behind a `&` reference - --> $DIR/issue-85765-closure.rs:27:9 + --> $DIR/issue-85765-closure.rs:28:9 | LL | *y = 1; | ^^^^^^ `y` is a `&` reference, so the data it refers to cannot be written diff --git a/tests/ui/borrowck/issue-85765.rs b/tests/ui/borrowck/issue-85765.rs index 76e0b517354..ce5740bc0e7 100644 --- a/tests/ui/borrowck/issue-85765.rs +++ b/tests/ui/borrowck/issue-85765.rs @@ -2,6 +2,7 @@ fn main() { let mut test = Vec::new(); let rofl: &Vec<Vec<i32>> = &mut test; //~^ HELP consider changing this binding's type + //~| HELP you can `clone` the `Vec<Vec<i32>>` value and consume it, but this might not be your desired behavior rofl.push(Vec::new()); //~^ ERROR cannot borrow `*rofl` as mutable, as it is behind a `&` reference //~| NOTE `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable diff --git a/tests/ui/borrowck/issue-85765.stderr b/tests/ui/borrowck/issue-85765.stderr index 57900bfb612..4889f774afa 100644 --- a/tests/ui/borrowck/issue-85765.stderr +++ b/tests/ui/borrowck/issue-85765.stderr @@ -1,16 +1,21 @@ error[E0596]: cannot borrow `*rofl` as mutable, as it is behind a `&` reference - --> $DIR/issue-85765.rs:5:5 + --> $DIR/issue-85765.rs:6:5 | LL | rofl.push(Vec::new()); | ^^^^ `rofl` is a `&` reference, so the data it refers to cannot be borrowed as mutable | +help: you can `clone` the `Vec<Vec<i32>>` value and consume it, but this might not be your desired behavior + --> $DIR/issue-85765.rs:3:32 + | +LL | let rofl: &Vec<Vec<i32>> = &mut test; + | ^^^^^^^^^ help: consider changing this binding's type | LL | let rofl: &mut Vec<Vec<i32>> = &mut test; | ~~~~~~~~~~~~~~~~~~ error[E0594]: cannot assign to `*r`, which is behind a `&` reference - --> $DIR/issue-85765.rs:12:5 + --> $DIR/issue-85765.rs:13:5 | LL | *r = 0; | ^^^^^^ `r` is a `&` reference, so the data it refers to cannot be written @@ -21,7 +26,7 @@ LL | let r = &mut mutvar; | +++ error[E0594]: cannot assign to `*x`, which is behind a `&` reference - --> $DIR/issue-85765.rs:19:5 + --> $DIR/issue-85765.rs:20:5 | LL | *x = 1; | ^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written @@ -32,7 +37,7 @@ LL | let x: &mut usize = &mut{0}; | ~~~~~~~~~~ error[E0594]: cannot assign to `*y`, which is behind a `&` reference - --> $DIR/issue-85765.rs:26:5 + --> $DIR/issue-85765.rs:27:5 | LL | *y = 1; | ^^^^^^ `y` is a `&` reference, so the data it refers to cannot be written diff --git a/tests/ui/borrowck/issue-91206.rs b/tests/ui/borrowck/issue-91206.rs index e062a253767..c60ac62fa34 100644 --- a/tests/ui/borrowck/issue-91206.rs +++ b/tests/ui/borrowck/issue-91206.rs @@ -10,6 +10,7 @@ fn main() { let client = TestClient; let inner = client.get_inner_ref(); //~^ HELP consider specifying this binding's type + //~| HELP you can `clone` the `Vec<usize>` value and consume it, but this might not be your desired behavior inner.clear(); //~^ ERROR cannot borrow `*inner` as mutable, as it is behind a `&` reference [E0596] //~| NOTE `inner` is a `&` reference, so the data it refers to cannot be borrowed as mutable diff --git a/tests/ui/borrowck/issue-91206.stderr b/tests/ui/borrowck/issue-91206.stderr index f96b0c7d9e1..e3dd65b6419 100644 --- a/tests/ui/borrowck/issue-91206.stderr +++ b/tests/ui/borrowck/issue-91206.stderr @@ -1,9 +1,14 @@ error[E0596]: cannot borrow `*inner` as mutable, as it is behind a `&` reference - --> $DIR/issue-91206.rs:13:5 + --> $DIR/issue-91206.rs:14:5 | LL | inner.clear(); | ^^^^^ `inner` is a `&` reference, so the data it refers to cannot be borrowed as mutable | +help: you can `clone` the `Vec<usize>` value and consume it, but this might not be your desired behavior + --> $DIR/issue-91206.rs:11:17 + | +LL | let inner = client.get_inner_ref(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider specifying this binding's type | LL | let inner: &mut Vec<usize> = client.get_inner_ref(); diff --git a/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr b/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr index bada08368fc..1e98006a9a7 100644 --- a/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr +++ b/tests/ui/borrowck/suggest-as-ref-on-mut-closure.stderr @@ -9,6 +9,10 @@ LL | cb.map(|cb| cb()); | note: `Option::<T>::map` takes ownership of the receiver `self`, which moves `*cb` --> $SRC_DIR/core/src/option.rs:LL:COL +help: you could `clone` the value and consume it, if the `&mut dyn FnMut(): Clone` trait bound could be satisfied + | +LL | <Option<&mut dyn FnMut()> as Clone>::clone(&cb).map(|cb| cb()); + | ++++++++++++++++++++++++++++++++++++++++++++ + error[E0596]: cannot borrow `*cb` as mutable, as it is behind a `&` reference --> $DIR/suggest-as-ref-on-mut-closure.rs:12:26 diff --git a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed index b0c5376105b..85acafd88f6 100644 --- a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed +++ b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.fixed @@ -9,7 +9,7 @@ fn call<F>(f: F) where F : Fn() { fn main() { let y = vec![format!("World")]; call(|| { - y.clone().into_iter(); + <Vec<String> as Clone>::clone(&y).into_iter(); //~^ ERROR cannot move out of `y`, a captured variable in an `Fn` closure }); } diff --git a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr index fd168b43ac5..a2ff70255f5 100644 --- a/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr +++ b/tests/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr @@ -14,8 +14,8 @@ note: `into_iter` takes ownership of the receiver `self`, which moves `y` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL help: you can `clone` the value and consume it, but this might not be your desired behavior | -LL | y.clone().into_iter(); - | ++++++++ +LL | <Vec<String> as Clone>::clone(&y).into_iter(); + | +++++++++++++++++++++++++++++++ + error: aborting due to 1 previous error diff --git a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr index 971abb1a21a..9efc77fb43f 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr @@ -1,5 +1,5 @@ warning: unexpected `cfg` condition name: `unknown_key` - --> $DIR/exhaustive-names-values.rs:11:7 + --> $DIR/exhaustive-names-values.rs:10:7 | LL | #[cfg(unknown_key = "value")] | ^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #[cfg(unknown_key = "value")] = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition value: `value` - --> $DIR/exhaustive-names-values.rs:15:7 + --> $DIR/exhaustive-names-values.rs:14:7 | LL | #[cfg(test = "value")] | ^^^^---------- @@ -18,13 +18,13 @@ LL | #[cfg(test = "value")] = note: no expected value for `test` warning: unexpected `cfg` condition name: `feature` - --> $DIR/exhaustive-names-values.rs:19:7 + --> $DIR/exhaustive-names-values.rs:18:7 | LL | #[cfg(feature = "unk")] | ^^^^^^^^^^^^^^^ warning: unexpected `cfg` condition name: `feature` - --> $DIR/exhaustive-names-values.rs:26:7 + --> $DIR/exhaustive-names-values.rs:25:7 | LL | #[cfg(feature = "std")] | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr index d71ca095894..4549482abcb 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr @@ -1,5 +1,5 @@ warning: unexpected `cfg` condition name: `unknown_key` - --> $DIR/exhaustive-names-values.rs:11:7 + --> $DIR/exhaustive-names-values.rs:10:7 | LL | #[cfg(unknown_key = "value")] | ^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #[cfg(unknown_key = "value")] = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition value: `value` - --> $DIR/exhaustive-names-values.rs:15:7 + --> $DIR/exhaustive-names-values.rs:14:7 | LL | #[cfg(test = "value")] | ^^^^---------- @@ -18,7 +18,7 @@ LL | #[cfg(test = "value")] = note: no expected value for `test` warning: unexpected `cfg` condition value: `unk` - --> $DIR/exhaustive-names-values.rs:19:7 + --> $DIR/exhaustive-names-values.rs:18:7 | LL | #[cfg(feature = "unk")] | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/check-cfg/exhaustive-names-values.full.stderr b/tests/ui/check-cfg/exhaustive-names-values.full.stderr index d71ca095894..4549482abcb 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.full.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.full.stderr @@ -1,5 +1,5 @@ warning: unexpected `cfg` condition name: `unknown_key` - --> $DIR/exhaustive-names-values.rs:11:7 + --> $DIR/exhaustive-names-values.rs:10:7 | LL | #[cfg(unknown_key = "value")] | ^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #[cfg(unknown_key = "value")] = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition value: `value` - --> $DIR/exhaustive-names-values.rs:15:7 + --> $DIR/exhaustive-names-values.rs:14:7 | LL | #[cfg(test = "value")] | ^^^^---------- @@ -18,7 +18,7 @@ LL | #[cfg(test = "value")] = note: no expected value for `test` warning: unexpected `cfg` condition value: `unk` - --> $DIR/exhaustive-names-values.rs:19:7 + --> $DIR/exhaustive-names-values.rs:18:7 | LL | #[cfg(feature = "unk")] | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/check-cfg/exhaustive-names-values.rs b/tests/ui/check-cfg/exhaustive-names-values.rs index ceb4831e22d..956992a1e77 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.rs +++ b/tests/ui/check-cfg/exhaustive-names-values.rs @@ -1,9 +1,8 @@ // Check warning for unexpected cfg in the code. // // check-pass -// revisions: empty_names_values empty_cfg feature full +// revisions: empty_cfg feature full // compile-flags: -Z unstable-options -// [empty_names_values]compile-flags: --check-cfg=names() --check-cfg=values() // [empty_cfg]compile-flags: --check-cfg=cfg() // [feature]compile-flags: --check-cfg=cfg(feature,values("std")) // [full]compile-flags: --check-cfg=cfg(feature,values("std")) --check-cfg=cfg() diff --git a/tests/ui/check-cfg/exhaustive-names.rs b/tests/ui/check-cfg/exhaustive-names.rs index b86a7f84eb4..80668020699 100644 --- a/tests/ui/check-cfg/exhaustive-names.rs +++ b/tests/ui/check-cfg/exhaustive-names.rs @@ -1,9 +1,7 @@ // Check warning for unexpected cfg // // check-pass -// revisions: empty_names exhaustive_names -// [empty_names]compile-flags: --check-cfg=names() -Z unstable-options -// [exhaustive_names]compile-flags: --check-cfg=cfg() -Z unstable-options +// compile-flags: --check-cfg=cfg() -Z unstable-options #[cfg(unknown_key = "value")] //~^ WARNING unexpected `cfg` condition name diff --git a/tests/ui/check-cfg/exhaustive-names.empty_names.stderr b/tests/ui/check-cfg/exhaustive-names.stderr index 7d01c73cc09..866595b1213 100644 --- a/tests/ui/check-cfg/exhaustive-names.empty_names.stderr +++ b/tests/ui/check-cfg/exhaustive-names.stderr @@ -1,5 +1,5 @@ warning: unexpected `cfg` condition name: `unknown_key` - --> $DIR/exhaustive-names.rs:8:7 + --> $DIR/exhaustive-names.rs:6:7 | LL | #[cfg(unknown_key = "value")] | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/check-cfg/exhaustive-values.empty_cfg.stderr b/tests/ui/check-cfg/exhaustive-values.empty_cfg.stderr index 77ddc35100a..745646bda1c 100644 --- a/tests/ui/check-cfg/exhaustive-values.empty_cfg.stderr +++ b/tests/ui/check-cfg/exhaustive-values.empty_cfg.stderr @@ -1,5 +1,5 @@ warning: unexpected `cfg` condition value: `value` - --> $DIR/exhaustive-values.rs:9:7 + --> $DIR/exhaustive-values.rs:8:7 | LL | #[cfg(test = "value")] | ^^^^---------- diff --git a/tests/ui/check-cfg/exhaustive-values.empty_values.stderr b/tests/ui/check-cfg/exhaustive-values.empty_values.stderr deleted file mode 100644 index 77ddc35100a..00000000000 --- a/tests/ui/check-cfg/exhaustive-values.empty_values.stderr +++ /dev/null @@ -1,13 +0,0 @@ -warning: unexpected `cfg` condition value: `value` - --> $DIR/exhaustive-values.rs:9:7 - | -LL | #[cfg(test = "value")] - | ^^^^---------- - | | - | help: remove the value - | - = note: no expected value for `test` - = note: `#[warn(unexpected_cfgs)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/check-cfg/exhaustive-values.rs b/tests/ui/check-cfg/exhaustive-values.rs index 8a1689ba86b..430d3b89e7a 100644 --- a/tests/ui/check-cfg/exhaustive-values.rs +++ b/tests/ui/check-cfg/exhaustive-values.rs @@ -1,8 +1,7 @@ // Check warning for unexpected cfg value // // check-pass -// revisions: empty_values empty_cfg without_names -// [empty_values]compile-flags: --check-cfg=values() -Z unstable-options +// revisions: empty_cfg without_names // [empty_cfg]compile-flags: --check-cfg=cfg() -Z unstable-options // [without_names]compile-flags: --check-cfg=cfg(any()) -Z unstable-options diff --git a/tests/ui/check-cfg/exhaustive-values.without_names.stderr b/tests/ui/check-cfg/exhaustive-values.without_names.stderr index 77ddc35100a..745646bda1c 100644 --- a/tests/ui/check-cfg/exhaustive-values.without_names.stderr +++ b/tests/ui/check-cfg/exhaustive-values.without_names.stderr @@ -1,5 +1,5 @@ warning: unexpected `cfg` condition value: `value` - --> $DIR/exhaustive-values.rs:9:7 + --> $DIR/exhaustive-values.rs:8:7 | LL | #[cfg(test = "value")] | ^^^^---------- diff --git a/tests/ui/check-cfg/invalid-arguments.names_simple_ident.stderr b/tests/ui/check-cfg/invalid-arguments.names_simple_ident.stderr deleted file mode 100644 index 8fadcc1f9f0..00000000000 --- a/tests/ui/check-cfg/invalid-arguments.names_simple_ident.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: invalid `--check-cfg` argument: `names("NOT_IDENT")` (`names()` arguments must be simple identifiers) - diff --git a/tests/ui/check-cfg/invalid-arguments.rs b/tests/ui/check-cfg/invalid-arguments.rs index a56f48e0af9..90c62fa3807 100644 --- a/tests/ui/check-cfg/invalid-arguments.rs +++ b/tests/ui/check-cfg/invalid-arguments.rs @@ -1,7 +1,7 @@ // Check that invalid --check-cfg are rejected // // check-fail -// revisions: anything_else names_simple_ident values_simple_ident values_string_literals +// revisions: anything_else // revisions: string_for_name_1 string_for_name_2 multiple_any multiple_values // revisions: multiple_values_any not_empty_any not_empty_values_any // revisions: values_any_missing_values values_any_before_ident ident_in_values_1 @@ -10,9 +10,6 @@ // // compile-flags: -Z unstable-options // [anything_else]compile-flags: --check-cfg=anything_else(...) -// [names_simple_ident]compile-flags: --check-cfg=names("NOT_IDENT") -// [values_simple_ident]compile-flags: --check-cfg=values("NOT_IDENT") -// [values_string_literals]compile-flags: --check-cfg=values(test,12) // [string_for_name_1]compile-flags: --check-cfg=cfg("NOT_IDENT") // [string_for_name_2]compile-flags: --check-cfg=cfg(foo,"NOT_IDENT",bar) // [multiple_any]compile-flags: --check-cfg=cfg(any(),any()) diff --git a/tests/ui/check-cfg/invalid-arguments.values_simple_ident.stderr b/tests/ui/check-cfg/invalid-arguments.values_simple_ident.stderr deleted file mode 100644 index 061d3f0e971..00000000000 --- a/tests/ui/check-cfg/invalid-arguments.values_simple_ident.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: invalid `--check-cfg` argument: `values("NOT_IDENT")` (`values()` first argument must be a simple identifier) - diff --git a/tests/ui/check-cfg/invalid-arguments.values_string_literals.stderr b/tests/ui/check-cfg/invalid-arguments.values_string_literals.stderr deleted file mode 100644 index 5853b4741a6..00000000000 --- a/tests/ui/check-cfg/invalid-arguments.values_string_literals.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: invalid `--check-cfg` argument: `values(test,12)` (`values()` arguments must be string literals) - diff --git a/tests/ui/check-cfg/mix.rs b/tests/ui/check-cfg/mix.rs index d7b3b4953b7..a6c3efee611 100644 --- a/tests/ui/check-cfg/mix.rs +++ b/tests/ui/check-cfg/mix.rs @@ -1,13 +1,10 @@ -// This test checks the combination of well known names, their activation via names(), -// the usage of values(), and that no implicit is done with --cfg while also testing that +// This test checks the combination of well known names, the usage of cfg(), +// and that no implicit cfgs is added from --cfg while also testing that // we correctly lint on the `cfg!` macro and `cfg_attr` attribute. // // check-pass -// revisions: names_values cfg // compile-flags: --cfg feature="bar" --cfg unknown_name -Z unstable-options -// compile-flags: --check-cfg=cfg(names_values,cfg) -// [names_values]compile-flags: --check-cfg=names() --check-cfg=values(feature,"foo") -// [cfg]compile-flags: --check-cfg=cfg(feature,values("foo")) +// compile-flags: --check-cfg=cfg(feature,values("foo")) #[cfg(windows)] fn do_windows_stuff() {} diff --git a/tests/ui/check-cfg/mix.names_values.stderr b/tests/ui/check-cfg/mix.stderr index 21c0c7da1dd..eefdbd6af30 100644 --- a/tests/ui/check-cfg/mix.names_values.stderr +++ b/tests/ui/check-cfg/mix.stderr @@ -1,5 +1,5 @@ warning: unexpected `cfg` condition name: `widnows` - --> $DIR/mix.rs:15:7 + --> $DIR/mix.rs:12:7 | LL | #[cfg(widnows)] | ^^^^^^^ help: there is a config with a similar name: `windows` @@ -7,7 +7,7 @@ LL | #[cfg(widnows)] = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition value: (none) - --> $DIR/mix.rs:19:7 + --> $DIR/mix.rs:16:7 | LL | #[cfg(feature)] | ^^^^^^^- help: specify a config value: `= "foo"` @@ -15,7 +15,7 @@ LL | #[cfg(feature)] = note: expected values for `feature` are: `foo` warning: unexpected `cfg` condition value: `bar` - --> $DIR/mix.rs:26:7 + --> $DIR/mix.rs:23:7 | LL | #[cfg(feature = "bar")] | ^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | #[cfg(feature = "bar")] = note: expected values for `feature` are: `foo` warning: unexpected `cfg` condition value: `zebra` - --> $DIR/mix.rs:30:7 + --> $DIR/mix.rs:27:7 | LL | #[cfg(feature = "zebra")] | ^^^^^^^^^^^^^^^^^ @@ -31,21 +31,21 @@ LL | #[cfg(feature = "zebra")] = note: expected values for `feature` are: `foo` warning: unexpected `cfg` condition name: `uu` - --> $DIR/mix.rs:34:12 + --> $DIR/mix.rs:31:12 | LL | #[cfg_attr(uu, test)] | ^^ | - = help: expected names are: `cfg`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `names_values`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition name: `widnows` - --> $DIR/mix.rs:43:10 + --> $DIR/mix.rs:40:10 | LL | cfg!(widnows); | ^^^^^^^ help: there is a config with a similar name: `windows` warning: unexpected `cfg` condition value: `bar` - --> $DIR/mix.rs:46:10 + --> $DIR/mix.rs:43:10 | LL | cfg!(feature = "bar"); | ^^^^^^^^^^^^^^^ @@ -53,7 +53,7 @@ LL | cfg!(feature = "bar"); = note: expected values for `feature` are: `foo` warning: unexpected `cfg` condition value: `zebra` - --> $DIR/mix.rs:48:10 + --> $DIR/mix.rs:45:10 | LL | cfg!(feature = "zebra"); | ^^^^^^^^^^^^^^^^^ @@ -61,25 +61,25 @@ LL | cfg!(feature = "zebra"); = note: expected values for `feature` are: `foo` warning: unexpected `cfg` condition name: `xxx` - --> $DIR/mix.rs:50:10 + --> $DIR/mix.rs:47:10 | LL | cfg!(xxx = "foo"); | ^^^^^^^^^^^ warning: unexpected `cfg` condition name: `xxx` - --> $DIR/mix.rs:52:10 + --> $DIR/mix.rs:49:10 | LL | cfg!(xxx); | ^^^ warning: unexpected `cfg` condition name: `xxx` - --> $DIR/mix.rs:54:14 + --> $DIR/mix.rs:51:14 | LL | cfg!(any(xxx, windows)); | ^^^ warning: unexpected `cfg` condition value: `bad` - --> $DIR/mix.rs:56:14 + --> $DIR/mix.rs:53:14 | LL | cfg!(any(feature = "bad", windows)); | ^^^^^^^^^^^^^^^ @@ -87,43 +87,43 @@ LL | cfg!(any(feature = "bad", windows)); = note: expected values for `feature` are: `foo` warning: unexpected `cfg` condition name: `xxx` - --> $DIR/mix.rs:58:23 + --> $DIR/mix.rs:55:23 | LL | cfg!(any(windows, xxx)); | ^^^ warning: unexpected `cfg` condition name: `xxx` - --> $DIR/mix.rs:60:20 + --> $DIR/mix.rs:57:20 | LL | cfg!(all(unix, xxx)); | ^^^ warning: unexpected `cfg` condition name: `aa` - --> $DIR/mix.rs:62:14 + --> $DIR/mix.rs:59:14 | LL | cfg!(all(aa, bb)); | ^^ warning: unexpected `cfg` condition name: `bb` - --> $DIR/mix.rs:62:18 + --> $DIR/mix.rs:59:18 | LL | cfg!(all(aa, bb)); | ^^ warning: unexpected `cfg` condition name: `aa` - --> $DIR/mix.rs:65:14 + --> $DIR/mix.rs:62:14 | LL | cfg!(any(aa, bb)); | ^^ warning: unexpected `cfg` condition name: `bb` - --> $DIR/mix.rs:65:18 + --> $DIR/mix.rs:62:18 | LL | cfg!(any(aa, bb)); | ^^ warning: unexpected `cfg` condition value: `zebra` - --> $DIR/mix.rs:68:20 + --> $DIR/mix.rs:65:20 | LL | cfg!(any(unix, feature = "zebra")); | ^^^^^^^^^^^^^^^^^ @@ -131,13 +131,13 @@ LL | cfg!(any(unix, feature = "zebra")); = note: expected values for `feature` are: `foo` warning: unexpected `cfg` condition name: `xxx` - --> $DIR/mix.rs:70:14 + --> $DIR/mix.rs:67:14 | LL | cfg!(any(xxx, feature = "zebra")); | ^^^ warning: unexpected `cfg` condition value: `zebra` - --> $DIR/mix.rs:70:19 + --> $DIR/mix.rs:67:19 | LL | cfg!(any(xxx, feature = "zebra")); | ^^^^^^^^^^^^^^^^^ @@ -145,19 +145,19 @@ LL | cfg!(any(xxx, feature = "zebra")); = note: expected values for `feature` are: `foo` warning: unexpected `cfg` condition name: `xxx` - --> $DIR/mix.rs:73:14 + --> $DIR/mix.rs:70:14 | LL | cfg!(any(xxx, unix, xxx)); | ^^^ warning: unexpected `cfg` condition name: `xxx` - --> $DIR/mix.rs:73:25 + --> $DIR/mix.rs:70:25 | LL | cfg!(any(xxx, unix, xxx)); | ^^^ warning: unexpected `cfg` condition value: `zebra` - --> $DIR/mix.rs:76:14 + --> $DIR/mix.rs:73:14 | LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra")); | ^^^^^^^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra")); = note: expected values for `feature` are: `foo` warning: unexpected `cfg` condition value: `zebra` - --> $DIR/mix.rs:76:33 + --> $DIR/mix.rs:73:33 | LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra")); | ^^^^^^^^^^^^^^^^^ @@ -173,7 +173,7 @@ LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra")); = note: expected values for `feature` are: `foo` warning: unexpected `cfg` condition value: `zebra` - --> $DIR/mix.rs:76:52 + --> $DIR/mix.rs:73:52 | LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra")); | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/check-cfg/no-expected-values.empty.stderr b/tests/ui/check-cfg/no-expected-values.empty.stderr index 5d261b2a5e6..0969d61dd40 100644 --- a/tests/ui/check-cfg/no-expected-values.empty.stderr +++ b/tests/ui/check-cfg/no-expected-values.empty.stderr @@ -1,5 +1,5 @@ warning: unexpected `cfg` condition value: `foo` - --> $DIR/no-expected-values.rs:12:7 + --> $DIR/no-expected-values.rs:11:7 | LL | #[cfg(feature = "foo")] | ^^^^^^^-------- @@ -10,7 +10,7 @@ LL | #[cfg(feature = "foo")] = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition value: `foo` - --> $DIR/no-expected-values.rs:16:7 + --> $DIR/no-expected-values.rs:15:7 | LL | #[cfg(test = "foo")] | ^^^^-------- diff --git a/tests/ui/check-cfg/no-expected-values.mixed.stderr b/tests/ui/check-cfg/no-expected-values.mixed.stderr index 5d261b2a5e6..0969d61dd40 100644 --- a/tests/ui/check-cfg/no-expected-values.mixed.stderr +++ b/tests/ui/check-cfg/no-expected-values.mixed.stderr @@ -1,5 +1,5 @@ warning: unexpected `cfg` condition value: `foo` - --> $DIR/no-expected-values.rs:12:7 + --> $DIR/no-expected-values.rs:11:7 | LL | #[cfg(feature = "foo")] | ^^^^^^^-------- @@ -10,7 +10,7 @@ LL | #[cfg(feature = "foo")] = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition value: `foo` - --> $DIR/no-expected-values.rs:16:7 + --> $DIR/no-expected-values.rs:15:7 | LL | #[cfg(test = "foo")] | ^^^^-------- diff --git a/tests/ui/check-cfg/no-expected-values.rs b/tests/ui/check-cfg/no-expected-values.rs index 9e2a9f09aed..9f34c019ea5 100644 --- a/tests/ui/check-cfg/no-expected-values.rs +++ b/tests/ui/check-cfg/no-expected-values.rs @@ -1,10 +1,9 @@ // Check that we detect unexpected value when none are allowed // // check-pass -// revisions: values simple mixed empty +// revisions: simple mixed empty // compile-flags: -Z unstable-options // compile-flags: --check-cfg=cfg(values,simple,mixed,empty) -// [values]compile-flags: --check-cfg=values(test) --check-cfg=values(feature) // [simple]compile-flags: --check-cfg=cfg(test) --check-cfg=cfg(feature) // [mixed]compile-flags: --check-cfg=cfg(test,feature) // [empty]compile-flags: --check-cfg=cfg(test,feature,values()) diff --git a/tests/ui/check-cfg/no-expected-values.simple.stderr b/tests/ui/check-cfg/no-expected-values.simple.stderr index 5d261b2a5e6..0969d61dd40 100644 --- a/tests/ui/check-cfg/no-expected-values.simple.stderr +++ b/tests/ui/check-cfg/no-expected-values.simple.stderr @@ -1,5 +1,5 @@ warning: unexpected `cfg` condition value: `foo` - --> $DIR/no-expected-values.rs:12:7 + --> $DIR/no-expected-values.rs:11:7 | LL | #[cfg(feature = "foo")] | ^^^^^^^-------- @@ -10,7 +10,7 @@ LL | #[cfg(feature = "foo")] = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition value: `foo` - --> $DIR/no-expected-values.rs:16:7 + --> $DIR/no-expected-values.rs:15:7 | LL | #[cfg(test = "foo")] | ^^^^-------- diff --git a/tests/ui/check-cfg/no-expected-values.values.stderr b/tests/ui/check-cfg/no-expected-values.values.stderr deleted file mode 100644 index 5d261b2a5e6..00000000000 --- a/tests/ui/check-cfg/no-expected-values.values.stderr +++ /dev/null @@ -1,23 +0,0 @@ -warning: unexpected `cfg` condition value: `foo` - --> $DIR/no-expected-values.rs:12:7 - | -LL | #[cfg(feature = "foo")] - | ^^^^^^^-------- - | | - | help: remove the value - | - = note: no expected value for `feature` - = note: `#[warn(unexpected_cfgs)]` on by default - -warning: unexpected `cfg` condition value: `foo` - --> $DIR/no-expected-values.rs:16:7 - | -LL | #[cfg(test = "foo")] - | ^^^^-------- - | | - | help: remove the value - | - = note: no expected value for `test` - -warning: 2 warnings emitted - diff --git a/tests/ui/check-cfg/order-independant.names_after.stderr b/tests/ui/check-cfg/order-independant.names_after.stderr deleted file mode 100644 index a308358e485..00000000000 --- a/tests/ui/check-cfg/order-independant.names_after.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: unexpected `cfg` condition value: (none) - --> $DIR/order-independant.rs:8:7 - | -LL | #[cfg(a)] - | ^- help: specify a config value: `= "b"` - | - = note: expected values for `a` are: `b` - = note: `#[warn(unexpected_cfgs)]` on by default - -warning: unexpected `cfg` condition value: `unk` - --> $DIR/order-independant.rs:12:7 - | -LL | #[cfg(a = "unk")] - | ^^^^^^^^^ - | - = note: expected values for `a` are: `b` - -warning: 2 warnings emitted - diff --git a/tests/ui/check-cfg/order-independant.names_before.stderr b/tests/ui/check-cfg/order-independant.names_before.stderr deleted file mode 100644 index a308358e485..00000000000 --- a/tests/ui/check-cfg/order-independant.names_before.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: unexpected `cfg` condition value: (none) - --> $DIR/order-independant.rs:8:7 - | -LL | #[cfg(a)] - | ^- help: specify a config value: `= "b"` - | - = note: expected values for `a` are: `b` - = note: `#[warn(unexpected_cfgs)]` on by default - -warning: unexpected `cfg` condition value: `unk` - --> $DIR/order-independant.rs:12:7 - | -LL | #[cfg(a = "unk")] - | ^^^^^^^^^ - | - = note: expected values for `a` are: `b` - -warning: 2 warnings emitted - diff --git a/tests/ui/check-cfg/order-independant.rs b/tests/ui/check-cfg/order-independant.rs index ce056b8dcd6..86e3cfa1d9b 100644 --- a/tests/ui/check-cfg/order-independant.rs +++ b/tests/ui/check-cfg/order-independant.rs @@ -1,12 +1,13 @@ // check-pass -// revisions: names_before names_after +// +// revisions: values_before values_after // compile-flags: -Z unstable-options -// compile-flags: --check-cfg=names(names_before,names_after) -// [names_before]compile-flags: --check-cfg=names(a) --check-cfg=values(a,"b") -// [names_after]compile-flags: --check-cfg=values(a,"b") --check-cfg=names(a) +// compile-flags: --check-cfg=cfg(values_before,values_after) +// +// [values_before]compile-flags: --check-cfg=cfg(a,values("b")) --check-cfg=cfg(a) +// [values_after]compile-flags: --check-cfg=cfg(a) --check-cfg=cfg(a,values("b")) #[cfg(a)] -//~^ WARNING unexpected `cfg` condition value fn my_cfg() {} #[cfg(a = "unk")] diff --git a/tests/ui/check-cfg/order-independant.values_after.stderr b/tests/ui/check-cfg/order-independant.values_after.stderr new file mode 100644 index 00000000000..ed162fb5489 --- /dev/null +++ b/tests/ui/check-cfg/order-independant.values_after.stderr @@ -0,0 +1,11 @@ +warning: unexpected `cfg` condition value: `unk` + --> $DIR/order-independant.rs:13:7 + | +LL | #[cfg(a = "unk")] + | ^^^^^^^^^ + | + = note: expected values for `a` are: (none), `b` + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/check-cfg/order-independant.values_before.stderr b/tests/ui/check-cfg/order-independant.values_before.stderr new file mode 100644 index 00000000000..ed162fb5489 --- /dev/null +++ b/tests/ui/check-cfg/order-independant.values_before.stderr @@ -0,0 +1,11 @@ +warning: unexpected `cfg` condition value: `unk` + --> $DIR/order-independant.rs:13:7 + | +LL | #[cfg(a = "unk")] + | ^^^^^^^^^ + | + = note: expected values for `a` are: (none), `b` + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/check-cfg/unexpected-cfg-name.exhaustive.stderr b/tests/ui/check-cfg/unexpected-cfg-name.exhaustive.stderr deleted file mode 100644 index 513f7ac7fd1..00000000000 --- a/tests/ui/check-cfg/unexpected-cfg-name.exhaustive.stderr +++ /dev/null @@ -1,10 +0,0 @@ -warning: unexpected `cfg` condition name: `widnows` - --> $DIR/unexpected-cfg-name.rs:9:7 - | -LL | #[cfg(widnows)] - | ^^^^^^^ help: there is a config with a similar name: `windows` - | - = note: `#[warn(unexpected_cfgs)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/check-cfg/unexpected-cfg-name.rs b/tests/ui/check-cfg/unexpected-cfg-name.rs index 15c3aa6e081..9fc0e28a8fe 100644 --- a/tests/ui/check-cfg/unexpected-cfg-name.rs +++ b/tests/ui/check-cfg/unexpected-cfg-name.rs @@ -1,10 +1,7 @@ // Check warning for unexpected configuration name // // check-pass -// revisions: names exhaustive -// compile-flags: --check-cfg=cfg(names,exhaustive) -// [names]compile-flags: --check-cfg=names() -Z unstable-options -// [exhaustive]compile-flags: --check-cfg=cfg() -Z unstable-options +// compile-flags: --check-cfg=cfg() -Z unstable-options #[cfg(widnows)] //~^ WARNING unexpected `cfg` condition name diff --git a/tests/ui/check-cfg/unexpected-cfg-name.names.stderr b/tests/ui/check-cfg/unexpected-cfg-name.stderr index 513f7ac7fd1..0874ccfc461 100644 --- a/tests/ui/check-cfg/unexpected-cfg-name.names.stderr +++ b/tests/ui/check-cfg/unexpected-cfg-name.stderr @@ -1,5 +1,5 @@ warning: unexpected `cfg` condition name: `widnows` - --> $DIR/unexpected-cfg-name.rs:9:7 + --> $DIR/unexpected-cfg-name.rs:6:7 | LL | #[cfg(widnows)] | ^^^^^^^ help: there is a config with a similar name: `windows` diff --git a/tests/ui/check-cfg/unexpected-cfg-value.rs b/tests/ui/check-cfg/unexpected-cfg-value.rs index 1b8ead956be..54dce0f0de4 100644 --- a/tests/ui/check-cfg/unexpected-cfg-value.rs +++ b/tests/ui/check-cfg/unexpected-cfg-value.rs @@ -1,10 +1,8 @@ // Check for unexpected configuration value in the code. // // check-pass -// revisions: values cfg -// compile-flags: -Z unstable-options -// [values]compile-flags: --check-cfg=values(feature,"serde","full") -// [cfg]compile-flags: --check-cfg=cfg(feature,values("serde","full")) +// compile-flags: --cfg=feature="rand" -Z unstable-options +// compile-flags: --check-cfg=cfg(feature,values("serde","full")) #[cfg(feature = "sedre")] //~^ WARNING unexpected `cfg` condition value diff --git a/tests/ui/check-cfg/unexpected-cfg-value.values.stderr b/tests/ui/check-cfg/unexpected-cfg-value.stderr index 2855aa75966..31c473a08cb 100644 --- a/tests/ui/check-cfg/unexpected-cfg-value.values.stderr +++ b/tests/ui/check-cfg/unexpected-cfg-value.stderr @@ -1,5 +1,5 @@ warning: unexpected `cfg` condition value: `sedre` - --> $DIR/unexpected-cfg-value.rs:9:7 + --> $DIR/unexpected-cfg-value.rs:7:7 | LL | #[cfg(feature = "sedre")] | ^^^^^^^^^^------- @@ -10,7 +10,7 @@ LL | #[cfg(feature = "sedre")] = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition value: `rand` - --> $DIR/unexpected-cfg-value.rs:16:7 + --> $DIR/unexpected-cfg-value.rs:14:7 | LL | #[cfg(feature = "rand")] | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/check-cfg/values-target-json.rs b/tests/ui/check-cfg/values-target-json.rs index 2ef5a44592b..e4c1b54cccc 100644 --- a/tests/ui/check-cfg/values-target-json.rs +++ b/tests/ui/check-cfg/values-target-json.rs @@ -2,7 +2,7 @@ // // check-pass // needs-llvm-components: x86 -// compile-flags: --crate-type=lib --check-cfg=values() --target={{src-base}}/check-cfg/my-awesome-platform.json -Z unstable-options +// compile-flags: --crate-type=lib --check-cfg=cfg() --target={{src-base}}/check-cfg/my-awesome-platform.json -Z unstable-options #![feature(lang_items, no_core, auto_traits)] #![no_core] diff --git a/tests/ui/coherence/normalize-for-errors.current.stderr b/tests/ui/coherence/normalize-for-errors.current.stderr new file mode 100644 index 00000000000..0e48aaed879 --- /dev/null +++ b/tests/ui/coherence/normalize-for-errors.current.stderr @@ -0,0 +1,14 @@ +error[E0119]: conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, _)` + --> $DIR/normalize-for-errors.rs:16:1 + | +LL | impl<T: Copy, S: Iterator> MyTrait<S> for (T, S::Item) {} + | ------------------------------------------------------ first implementation here +LL | +LL | impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, _)` + | + = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/normalize-for-errors.next.stderr b/tests/ui/coherence/normalize-for-errors.next.stderr new file mode 100644 index 00000000000..a8a7d437b32 --- /dev/null +++ b/tests/ui/coherence/normalize-for-errors.next.stderr @@ -0,0 +1,14 @@ +error[E0119]: conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, <_ as Iterator>::Item)` + --> $DIR/normalize-for-errors.rs:16:1 + | +LL | impl<T: Copy, S: Iterator> MyTrait<S> for (T, S::Item) {} + | ------------------------------------------------------ first implementation here +LL | +LL | impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, <_ as Iterator>::Item)` + | + = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/normalize-for-errors.rs b/tests/ui/coherence/normalize-for-errors.rs new file mode 100644 index 00000000000..367d34251ae --- /dev/null +++ b/tests/ui/coherence/normalize-for-errors.rs @@ -0,0 +1,21 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + +struct MyType; +trait MyTrait<S> {} + +trait Mirror { + type Assoc; +} +impl<T> Mirror for T { + type Assoc = T; +} + +impl<T: Copy, S: Iterator> MyTrait<S> for (T, S::Item) {} +//~^ NOTE first implementation here +impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {} +//~^ ERROR conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, +//~| NOTE conflicting implementation for `(Box<(MyType,)>, +//~| NOTE upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions + +fn main() {} diff --git a/tests/ui/const-ptr/forbidden_slices.rs b/tests/ui/const-ptr/forbidden_slices.rs index 0374ac7f714..deab67f725a 100644 --- a/tests/ui/const-ptr/forbidden_slices.rs +++ b/tests/ui/const-ptr/forbidden_slices.rs @@ -1,6 +1,6 @@ // Strip out raw byte dumps to make comparison platform-independent: // normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" -// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" +// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP" #![feature( slice_from_ptr_range, diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr index 8b941d538a2..383c167d3c0 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr @@ -6,7 +6,7 @@ LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) | = 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) { - ╾ALLOC0╼ │ ╾──╼ + ╾ALLOC0<imm>╼ │ ╾──╼ } error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr index 5ef03427093..d0679228326 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr @@ -6,7 +6,7 @@ LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) | = 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: 8) { - ╾ALLOC0╼ │ ╾──────╼ + ╾ALLOC0<imm>╼ │ ╾──────╼ } error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr index 43e664ce413..57815e6af65 100644 --- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr @@ -211,7 +211,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:109:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3<imm>, but expected a function pointer | = 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) { @@ -385,7 +385,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:178:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17<imm>, but expected a vtable pointer | = 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) { @@ -396,7 +396,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:182:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC19, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC19<imm>, but expected a vtable pointer | = 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) { @@ -418,7 +418,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:189:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC22, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC22<imm>, but expected a vtable pointer | = 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) { @@ -451,7 +451,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:199:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27<imm>, but expected a vtable pointer | = 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) { diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr index 1427cef7d03..c875d91ccb8 100644 --- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr @@ -211,7 +211,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:109:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3<imm>, but expected a function pointer | = 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: 8) { @@ -385,7 +385,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:178:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17<imm>, but expected a vtable pointer | = 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: 16, align: 8) { @@ -396,7 +396,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:182:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC19, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC19<imm>, but expected a vtable pointer | = 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: 16, align: 8) { @@ -418,7 +418,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:189:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC22, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC22<imm>, but expected a vtable pointer | = 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: 16, align: 8) { @@ -451,7 +451,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:199:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27<imm>, but expected a vtable pointer | = 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: 16, align: 8) { diff --git a/tests/ui/consts/const-eval/raw-bytes.rs b/tests/ui/consts/const-eval/raw-bytes.rs index ff2a32d5757..ae65a5cb8df 100644 --- a/tests/ui/consts/const-eval/raw-bytes.rs +++ b/tests/ui/consts/const-eval/raw-bytes.rs @@ -1,7 +1,7 @@ // stderr-per-bitwidth // ignore-endian-big // ignore-tidy-linelength -// normalize-stderr-test "╾─*ALLOC[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$1╼" +// normalize-stderr-test "╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼" -> "╾ALLOC_ID$1╼" #![feature(never_type, rustc_attrs, ptr_metadata, slice_from_ptr_range, const_slice_from_ptr_range)] #![allow(invalid_value)] diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr index 7b30233c025..5c47cbfdf3b 100644 --- a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr @@ -2,55 +2,55 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:18:1 | LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC1, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC1<imm>, but expected a vtable pointer | = 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) { - ╾ALLOC0╼ ╾ALLOC1╼ │ ╾──╼╾──╼ + ╾ALLOC0<imm>╼ ╾ALLOC1<imm>╼ │ ╾──╼╾──╼ } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:23:1 | LL | const INVALID_VTABLE_SIZE: &dyn Trait = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3<imm>, but expected a vtable pointer | = 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) { - ╾ALLOC2╼ ╾ALLOC3╼ │ ╾──╼╾──╼ + ╾ALLOC2<imm>╼ ╾ALLOC3<imm>╼ │ ╾──╼╾──╼ } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:33:1 | LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5<imm>, but expected a vtable pointer | = 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) { - ╾ALLOC4╼ ╾ALLOC5╼ │ ╾──╼╾──╼ + ╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼ │ ╾──╼╾──╼ } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:38:1 | LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC7, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC7<imm>, but expected a vtable pointer | = 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) { - ╾ALLOC6╼ ╾ALLOC7╼ │ ╾──╼╾──╼ + ╾ALLOC6<imm>╼ ╾ALLOC7<imm>╼ │ ╾──╼╾──╼ } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:44:1 | LL | const INVALID_VTABLE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC9, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC9<imm>, but expected a vtable pointer | = 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) { - ╾ALLOC8╼ ╾ALLOC9╼ │ ╾──╼╾──╼ + ╾ALLOC8<imm>╼ ╾ALLOC9<imm>╼ │ ╾──╼╾──╼ } error[E0080]: it is undefined behavior to use this value @@ -61,7 +61,7 @@ LL | const G: Wide = unsafe { Transmute { t: FOO }.u }; | = 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) { - ╾ALLOC10╼ ╾ALLOC11╼ │ ╾──╼╾──╼ + ╾ALLOC10<imm>╼ ╾ALLOC11╼ │ ╾──╼╾──╼ } error: aborting due to 6 previous errors diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr index 9330ae3c9a6..f400073aca2 100644 --- a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr @@ -2,55 +2,55 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:18:1 | LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC1, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC1<imm>, but expected a vtable pointer | = 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: 16, align: 8) { - ╾ALLOC0╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼ + ╾ALLOC0<imm>╼ ╾ALLOC1<imm>╼ │ ╾──────╼╾──────╼ } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:23:1 | LL | const INVALID_VTABLE_SIZE: &dyn Trait = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3<imm>, but expected a vtable pointer | = 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: 16, align: 8) { - ╾ALLOC2╼ ╾ALLOC3╼ │ ╾──────╼╾──────╼ + ╾ALLOC2<imm>╼ ╾ALLOC3<imm>╼ │ ╾──────╼╾──────╼ } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:33:1 | LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5<imm>, but expected a vtable pointer | = 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: 16, align: 8) { - ╾ALLOC4╼ ╾ALLOC5╼ │ ╾──────╼╾──────╼ + ╾ALLOC4<imm>╼ ╾ALLOC5<imm>╼ │ ╾──────╼╾──────╼ } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:38:1 | LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC7, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC7<imm>, but expected a vtable pointer | = 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: 16, align: 8) { - ╾ALLOC6╼ ╾ALLOC7╼ │ ╾──────╼╾──────╼ + ╾ALLOC6<imm>╼ ╾ALLOC7<imm>╼ │ ╾──────╼╾──────╼ } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:44:1 | LL | const INVALID_VTABLE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC9, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC9<imm>, but expected a vtable pointer | = 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: 16, align: 8) { - ╾ALLOC8╼ ╾ALLOC9╼ │ ╾──────╼╾──────╼ + ╾ALLOC8<imm>╼ ╾ALLOC9<imm>╼ │ ╾──────╼╾──────╼ } error[E0080]: it is undefined behavior to use this value @@ -61,7 +61,7 @@ LL | const G: Wide = unsafe { Transmute { t: FOO }.u }; | = 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: 16, align: 8) { - ╾ALLOC10╼ ╾ALLOC11╼ │ ╾──────╼╾──────╼ + ╾ALLOC10<imm>╼ ╾ALLOC11╼ │ ╾──────╼╾──────╼ } error: aborting due to 6 previous errors diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.rs b/tests/ui/consts/const-eval/ub-ref-ptr.rs index 08d4dce4d17..9e49e3de8bc 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.rs +++ b/tests/ui/consts/const-eval/ub-ref-ptr.rs @@ -1,7 +1,7 @@ // ignore-tidy-linelength // Strip out raw byte dumps to make comparison platform-independent: // normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" -// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" +// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP" #![allow(invalid_value)] use std::mem; diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr index ca7b6645d3f..3bbf2977392 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr @@ -141,7 +141,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:59:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC2, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC2<imm>, but expected a function pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { diff --git a/tests/ui/consts/const-eval/ub-upvars.32bit.stderr b/tests/ui/consts/const-eval/ub-upvars.32bit.stderr index a6938ca0e90..5342fea66bd 100644 --- a/tests/ui/consts/const-eval/ub-upvars.32bit.stderr +++ b/tests/ui/consts/const-eval/ub-upvars.32bit.stderr @@ -6,7 +6,7 @@ LL | const BAD_UPVAR: &dyn FnOnce() = &{ | = 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) { - ╾ALLOC0╼ ╾ALLOC1╼ │ ╾──╼╾──╼ + ╾ALLOC0<imm>╼ ╾ALLOC1╼ │ ╾──╼╾──╼ } error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/ub-upvars.64bit.stderr b/tests/ui/consts/const-eval/ub-upvars.64bit.stderr index ef2545b43b1..a2496dfc287 100644 --- a/tests/ui/consts/const-eval/ub-upvars.64bit.stderr +++ b/tests/ui/consts/const-eval/ub-upvars.64bit.stderr @@ -6,7 +6,7 @@ LL | const BAD_UPVAR: &dyn FnOnce() = &{ | = 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: 16, align: 8) { - ╾ALLOC0╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼ + ╾ALLOC0<imm>╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼ } error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.rs b/tests/ui/consts/const-eval/ub-wide-ptr.rs index dc8d4c640c2..3c1baab3e48 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.rs +++ b/tests/ui/consts/const-eval/ub-wide-ptr.rs @@ -5,7 +5,7 @@ use std::mem; // Strip out raw byte dumps to make comparison platform-independent: // normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" -// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" +// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?(<imm>)?─*╼ )+ *│.*" -> "HEX_DUMP" // normalize-stderr-test "offset \d+" -> "offset N" // normalize-stderr-test "size \d+" -> "size N" diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr index b203794858a..91ce531c9f7 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr @@ -189,7 +189,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:113:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC12, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC12<imm>, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -200,7 +200,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:117:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC14, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC14<imm>, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -222,7 +222,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:124:1 | LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC17, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC17<imm>, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -233,7 +233,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:127:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC19, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC19<imm>, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -244,7 +244,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:130:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC21, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC21<imm>, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -255,7 +255,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:133:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC23, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC23<imm>, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -288,7 +288,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:145:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC28, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC28<imm>, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -310,7 +310,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:154:1 | LL | static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC31, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC31<imm>, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { diff --git a/tests/ui/consts/const-eval/ub-write-through-immutable.rs b/tests/ui/consts/const-eval/ub-write-through-immutable.rs new file mode 100644 index 00000000000..945367f1823 --- /dev/null +++ b/tests/ui/consts/const-eval/ub-write-through-immutable.rs @@ -0,0 +1,30 @@ +//! Ensure we catch UB due to writing through a shared reference. +#![feature(const_mut_refs, const_refs_to_cell)] +#![deny(writes_through_immutable_pointer)] +#![allow(invalid_reference_casting)] + +use std::mem; +use std::cell::UnsafeCell; + +const WRITE_AFTER_CAST: () = unsafe { + let mut x = 0; + let ptr = &x as *const i32 as *mut i32; + *ptr = 0; //~ERROR: writes_through_immutable_pointer + //~^ previously accepted +}; + +const WRITE_AFTER_TRANSMUTE: () = unsafe { + let mut x = 0; + let ptr: *mut i32 = mem::transmute(&x); + *ptr = 0; //~ERROR: writes_through_immutable_pointer + //~^ previously accepted +}; + +// it's okay when there is interior mutability; +const WRITE_INTERIOR_MUT: () = unsafe { + let x = UnsafeCell::new(0); + let ptr = &x as *const _ as *mut i32; + *ptr = 0; +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/ub-write-through-immutable.stderr b/tests/ui/consts/const-eval/ub-write-through-immutable.stderr new file mode 100644 index 00000000000..27eb2d2c0d1 --- /dev/null +++ b/tests/ui/consts/const-eval/ub-write-through-immutable.stderr @@ -0,0 +1,55 @@ +error: writing through a pointer that was derived from a shared (immutable) reference + --> $DIR/ub-write-through-immutable.rs:12:5 + | +LL | *ptr = 0; + | ^^^^^^^^ + | + = 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 #X <https://github.com/rust-lang/rust/issues/X> +note: the lint level is defined here + --> $DIR/ub-write-through-immutable.rs:3:9 + | +LL | #![deny(writes_through_immutable_pointer)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: writing through a pointer that was derived from a shared (immutable) reference + --> $DIR/ub-write-through-immutable.rs:19:5 + | +LL | *ptr = 0; + | ^^^^^^^^ + | + = 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 #X <https://github.com/rust-lang/rust/issues/X> + +error: aborting due to 2 previous errors + +Future incompatibility report: Future breakage diagnostic: +error: writing through a pointer that was derived from a shared (immutable) reference + --> $DIR/ub-write-through-immutable.rs:12:5 + | +LL | *ptr = 0; + | ^^^^^^^^ + | + = 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 #X <https://github.com/rust-lang/rust/issues/X> +note: the lint level is defined here + --> $DIR/ub-write-through-immutable.rs:3:9 + | +LL | #![deny(writes_through_immutable_pointer)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Future breakage diagnostic: +error: writing through a pointer that was derived from a shared (immutable) reference + --> $DIR/ub-write-through-immutable.rs:19:5 + | +LL | *ptr = 0; + | ^^^^^^^^ + | + = 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 #X <https://github.com/rust-lang/rust/issues/X> +note: the lint level is defined here + --> $DIR/ub-write-through-immutable.rs:3:9 + | +LL | #![deny(writes_through_immutable_pointer)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/consts/const-points-to-static.32bit.stderr b/tests/ui/consts/const-points-to-static.32bit.stderr index 452ed6b39d2..73fbf5e1837 100644 --- a/tests/ui/consts/const-points-to-static.32bit.stderr +++ b/tests/ui/consts/const-points-to-static.32bit.stderr @@ -6,7 +6,7 @@ LL | const TEST: &u8 = &MY_STATIC; | = 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) { - ╾ALLOC0╼ │ ╾──╼ + ╾ALLOC0<imm>╼ │ ╾──╼ } warning: skipping const checks diff --git a/tests/ui/consts/const-points-to-static.64bit.stderr b/tests/ui/consts/const-points-to-static.64bit.stderr index 2bebfbfda01..42088bbb2c4 100644 --- a/tests/ui/consts/const-points-to-static.64bit.stderr +++ b/tests/ui/consts/const-points-to-static.64bit.stderr @@ -6,7 +6,7 @@ LL | const TEST: &u8 = &MY_STATIC; | = 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: 8) { - ╾ALLOC0╼ │ ╾──────╼ + ╾ALLOC0<imm>╼ │ ╾──────╼ } warning: skipping const checks diff --git a/tests/ui/consts/invalid-union.32bit.stderr b/tests/ui/consts/invalid-union.32bit.stderr index cd7549597c7..177e4f03e83 100644 --- a/tests/ui/consts/invalid-union.32bit.stderr +++ b/tests/ui/consts/invalid-union.32bit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/invalid-union.rs:41:1 + --> $DIR/invalid-union.rs:35:1 | LL | fn main() { | ^^^^^^^^^ constructing invalid value at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in a `const` @@ -10,13 +10,13 @@ LL | fn main() { } note: erroneous constant encountered - --> $DIR/invalid-union.rs:43:25 + --> $DIR/invalid-union.rs:37:25 | LL | let _: &'static _ = &C; | ^^ note: erroneous constant encountered - --> $DIR/invalid-union.rs:43:25 + --> $DIR/invalid-union.rs:37:25 | LL | let _: &'static _ = &C; | ^^ diff --git a/tests/ui/consts/invalid-union.64bit.stderr b/tests/ui/consts/invalid-union.64bit.stderr index e8a0a9955ad..09c648c3cda 100644 --- a/tests/ui/consts/invalid-union.64bit.stderr +++ b/tests/ui/consts/invalid-union.64bit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/invalid-union.rs:41:1 + --> $DIR/invalid-union.rs:35:1 | LL | fn main() { | ^^^^^^^^^ constructing invalid value at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in a `const` @@ -10,13 +10,13 @@ LL | fn main() { } note: erroneous constant encountered - --> $DIR/invalid-union.rs:43:25 + --> $DIR/invalid-union.rs:37:25 | LL | let _: &'static _ = &C; | ^^ note: erroneous constant encountered - --> $DIR/invalid-union.rs:43:25 + --> $DIR/invalid-union.rs:37:25 | LL | let _: &'static _ = &C; | ^^ diff --git a/tests/ui/consts/invalid-union.rs b/tests/ui/consts/invalid-union.rs index 28706b4a923..4f67ec97902 100644 --- a/tests/ui/consts/invalid-union.rs +++ b/tests/ui/consts/invalid-union.rs @@ -1,11 +1,6 @@ // Check that constants with interior mutability inside unions are rejected // during validation. // -// Note that this test case relies on undefined behaviour to construct a -// constant with interior mutability that is "invisible" to the static checks. -// If for some reason this approach no longer works, it is should be fine to -// remove the test case. -// // build-fail // stderr-per-bitwidth #![feature(const_mut_refs)] @@ -30,10 +25,9 @@ union U { } const C: S = { - let s = S { x: 0, y: E::A }; - // Go through an &u32 reference which is definitely not allowed to mutate anything. - let p = &s.x as *const u32 as *mut u32; - // Change enum tag to E::B. + let mut s = S { x: 0, y: E::A }; + let p = &mut s.x as *mut u32; + // Change enum tag to E::B. Now there's interior mutability here. unsafe { *p.add(1) = 1 }; s }; diff --git a/tests/ui/consts/issue-63952.32bit.stderr b/tests/ui/consts/issue-63952.32bit.stderr index f676d8a7586..f562f9104e3 100644 --- a/tests/ui/consts/issue-63952.32bit.stderr +++ b/tests/ui/consts/issue-63952.32bit.stderr @@ -6,7 +6,7 @@ LL | const SLICE_WAY_TOO_LONG: &[u8] = unsafe { | = 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) { - ╾ALLOC0╼ ff ff ff ff │ ╾──╼.... + ╾ALLOC0<imm>╼ ff ff ff ff │ ╾──╼.... } error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-63952.64bit.stderr b/tests/ui/consts/issue-63952.64bit.stderr index c1d7b75af88..fe66bec13a1 100644 --- a/tests/ui/consts/issue-63952.64bit.stderr +++ b/tests/ui/consts/issue-63952.64bit.stderr @@ -6,7 +6,7 @@ LL | const SLICE_WAY_TOO_LONG: &[u8] = unsafe { | = 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: 16, align: 8) { - ╾ALLOC0╼ ff ff ff ff ff ff ff ff │ ╾──────╼........ + ╾ALLOC0<imm>╼ ff ff ff ff ff ff ff ff │ ╾──────╼........ } error: aborting due to 1 previous error diff --git a/tests/ui/consts/issue-79690.64bit.stderr b/tests/ui/consts/issue-79690.64bit.stderr index e99ce078c11..d603a1dc291 100644 --- a/tests/ui/consts/issue-79690.64bit.stderr +++ b/tests/ui/consts/issue-79690.64bit.stderr @@ -6,7 +6,7 @@ LL | const G: Fat = unsafe { Transmute { t: FOO }.u }; | = 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: 16, align: 8) { - ╾ALLOC0╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼ + ╾ALLOC0<imm>╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼ } error: aborting due to 1 previous error diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr index 4a3344a5b04..ab33b0c00c9 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr @@ -24,7 +24,7 @@ LL | const REF_INTERIOR_MUT: &usize = { | = 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) { - ╾ALLOC0╼ │ ╾──╼ + ╾ALLOC0<imm>╼ │ ╾──╼ } error[E0080]: it is undefined behavior to use this value @@ -35,7 +35,7 @@ LL | const READ_IMMUT: &usize = { | = 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) { - ╾ALLOC1╼ │ ╾──╼ + ╾ALLOC1<imm>╼ │ ╾──╼ } warning: skipping const checks diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr index 7573bfa39ec..f1f58d9ca6d 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr @@ -24,7 +24,7 @@ LL | const REF_INTERIOR_MUT: &usize = { | = 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: 8) { - ╾ALLOC0╼ │ ╾──────╼ + ╾ALLOC0<imm>╼ │ ╾──────╼ } error[E0080]: it is undefined behavior to use this value @@ -35,7 +35,7 @@ LL | const READ_IMMUT: &usize = { | = 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: 8) { - ╾ALLOC1╼ │ ╾──────╼ + ╾ALLOC1<imm>╼ │ ╾──────╼ } warning: skipping const checks diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr index 492d8718a13..7960648ce3a 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr @@ -6,7 +6,7 @@ LL | const SLICE_MUT: &[u8; 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) { - ╾ALLOC0╼ │ ╾──╼ + ╾ALLOC0<imm>╼ │ ╾──╼ } error: could not evaluate constant pattern @@ -23,7 +23,7 @@ LL | const U8_MUT: &u8 = { | = 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) { - ╾ALLOC0╼ │ ╾──╼ + ╾ALLOC0<imm>╼ │ ╾──╼ } error: could not evaluate constant pattern diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr index f6d82d6c0ba..6ae0b2d1bfe 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr @@ -6,7 +6,7 @@ LL | const SLICE_MUT: &[u8; 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: 8) { - ╾ALLOC0╼ │ ╾──────╼ + ╾ALLOC0<imm>╼ │ ╾──────╼ } error: could not evaluate constant pattern @@ -23,7 +23,7 @@ LL | const U8_MUT: &u8 = { | = 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: 8) { - ╾ALLOC0╼ │ ╾──────╼ + ╾ALLOC0<imm>╼ │ ╾──────╼ } error: could not evaluate constant pattern diff --git a/tests/ui/coroutine/async_gen_fn.rs b/tests/ui/coroutine/async_gen_fn.rs new file mode 100644 index 00000000000..f8860e07f6c --- /dev/null +++ b/tests/ui/coroutine/async_gen_fn.rs @@ -0,0 +1,11 @@ +// edition: 2024 +// compile-flags: -Zunstable-options +#![feature(gen_blocks)] + +// async generators are not yet supported, so this test makes sure they make some kind of reasonable +// error. + +async gen fn foo() {} +//~^ `async gen` functions are not supported + +fn main() {} diff --git a/tests/ui/coroutine/async_gen_fn.stderr b/tests/ui/coroutine/async_gen_fn.stderr new file mode 100644 index 00000000000..6857ebe6c79 --- /dev/null +++ b/tests/ui/coroutine/async_gen_fn.stderr @@ -0,0 +1,8 @@ +error: `async gen` functions are not supported + --> $DIR/async_gen_fn.rs:8:1 + | +LL | async gen fn foo() {} + | ^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/coroutine/gen_fn.e2024.stderr b/tests/ui/coroutine/gen_fn.e2024.stderr index 928c16f57a2..9ad890af3e1 100644 --- a/tests/ui/coroutine/gen_fn.e2024.stderr +++ b/tests/ui/coroutine/gen_fn.e2024.stderr @@ -1,10 +1,12 @@ -error: `gen` functions are not yet implemented +error[E0658]: gen blocks are experimental --> $DIR/gen_fn.rs:4:1 | LL | gen fn foo() {} | ^^^ | - = help: for now you can use `gen {}` blocks and return `impl Iterator` instead + = note: see issue #117078 <https://github.com/rust-lang/rust/issues/117078> for more information + = help: add `#![feature(gen_blocks)]` to the crate attributes to enable error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/coroutine/gen_fn.rs b/tests/ui/coroutine/gen_fn.rs index da515f263b0..e06629c5dfe 100644 --- a/tests/ui/coroutine/gen_fn.rs +++ b/tests/ui/coroutine/gen_fn.rs @@ -3,6 +3,6 @@ gen fn foo() {} //[none]~^ ERROR: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `unsafe`, or `use`, found `gen` -//[e2024]~^^ ERROR: `gen` functions are not yet implemented +//[e2024]~^^ ERROR: gen blocks are experimental fn main() {} diff --git a/tests/ui/coroutine/gen_fn_iter.rs b/tests/ui/coroutine/gen_fn_iter.rs new file mode 100644 index 00000000000..da01bc96ef4 --- /dev/null +++ b/tests/ui/coroutine/gen_fn_iter.rs @@ -0,0 +1,20 @@ +// edition: 2024 +// compile-flags: -Zunstable-options +// run-pass +#![feature(gen_blocks)] + +// make sure that a ridiculously simple gen fn works as an iterator. + +gen fn foo() -> i32 { + yield 1; + yield 2; + yield 3; +} + +fn main() { + let mut iter = foo(); + assert_eq!(iter.next(), Some(1)); + assert_eq!(iter.next(), Some(2)); + assert_eq!(iter.next(), Some(3)); + assert_eq!(iter.next(), None); +} diff --git a/tests/ui/coroutine/gen_fn_lifetime_capture.rs b/tests/ui/coroutine/gen_fn_lifetime_capture.rs new file mode 100644 index 00000000000..b6a4d71e6cc --- /dev/null +++ b/tests/ui/coroutine/gen_fn_lifetime_capture.rs @@ -0,0 +1,19 @@ +// edition: 2024 +// compile-flags: -Zunstable-options +// check-pass +#![feature(gen_blocks)] + +// make sure gen fn captures lifetimes in its signature + +gen fn foo<'a, 'b>(x: &'a i32, y: &'b i32, z: &'b i32) -> &'b i32 { + yield y; + yield z; +} + +fn main() { + let z = 3; + let mut iter = foo(&1, &2, &z); + assert_eq!(iter.next(), Some(&2)); + assert_eq!(iter.next(), Some(&3)); + assert_eq!(iter.next(), None); +} diff --git a/tests/ui/error-codes/E0401.stderr b/tests/ui/error-codes/E0401.stderr index 0a069e8d350..d27fade487f 100644 --- a/tests/ui/error-codes/E0401.stderr +++ b/tests/ui/error-codes/E0401.stderr @@ -55,7 +55,7 @@ error[E0283]: type annotations needed LL | bfnr(x); | ^^^^ cannot infer type of the type parameter `W` declared on the function `bfnr` | - = note: multiple `impl`s satisfying `_: Fn<()>` found in the following crates: `alloc`, `core`: + = note: multiple `impl`s satisfying `_: Fn()` found in the following crates: `alloc`, `core`: - impl<A, F> Fn<A> for &F where A: Tuple, F: Fn<A>, F: ?Sized; - impl<Args, F, A> Fn<Args> for Box<F, A> diff --git a/tests/ui/error-emitter/highlighting.not-windows.stderr b/tests/ui/error-emitter/highlighting.not-windows.stderr new file mode 100644 index 00000000000..922bb19a248 --- /dev/null +++ b/tests/ui/error-emitter/highlighting.not-windows.stderr @@ -0,0 +1,22 @@ +[0m[1m[38;5;9merror[E0308][0m[0m[1m: mismatched types[0m +[0m [0m[0m[1m[38;5;12m--> [0m[0m$DIR/highlighting.rs:26:11[0m +[0m [0m[0m[1m[38;5;12m|[0m +[0m[1m[38;5;12mLL[0m[0m [0m[0m[1m[38;5;12m|[0m[0m [0m[0m query(wrapped_fn);[0m +[0m [0m[0m[1m[38;5;12m| [0m[0m [0m[0m[1m[38;5;12m-----[0m[0m [0m[0m[1m[38;5;9m^^^^^^^^^^[0m[0m [0m[0m[1m[38;5;9mone type is more general than the other[0m +[0m [0m[0m[1m[38;5;12m| [0m[0m [0m[0m[1m[38;5;12m|[0m +[0m [0m[0m[1m[38;5;12m| [0m[0m [0m[0m[1m[38;5;12marguments to this function are incorrect[0m +[0m [0m[0m[1m[38;5;12m|[0m +[0m [0m[0m[1m[38;5;12m= [0m[0m[1mnote[0m[0m: expected fn pointer `[0m[0m[1m[35mfor<'a> [0m[0mfn(Box<[0m[0m[1m[35m(dyn Any + Send + 'a)[0m[0m>) -> Pin<_>`[0m +[0m found fn item `fn(Box<[0m[0m[1m[35m(dyn Any + Send + 'static)[0m[0m>) -> Pin<_> {wrapped_fn}`[0m +[0m[1m[38;5;10mnote[0m[0m: function defined here[0m +[0m [0m[0m[1m[38;5;12m--> [0m[0m$DIR/highlighting.rs:15:4[0m +[0m [0m[0m[1m[38;5;12m|[0m +[0m[1m[38;5;12mLL[0m[0m [0m[0m[1m[38;5;12m|[0m[0m [0m[0mfn query(_: fn(Box<(dyn Any + Send + '_)>) -> Pin<Box<([0m +[0m [0m[0m[1m[38;5;12m| [0m[0m [0m[0m[1m[38;5;12m____[0m[0m[1m[38;5;10m^^^^^[0m[0m[1m[38;5;12m_-[0m +[0m[1m[38;5;12mLL[0m[0m [0m[0m[1m[38;5;12m|[0m[0m [0m[0m[1m[38;5;12m|[0m[0m [0m[0m dyn Future<Output = Result<Box<(dyn Any + 'static)>, String>> + Send + 'static[0m +[0m[1m[38;5;12mLL[0m[0m [0m[0m[1m[38;5;12m|[0m[0m [0m[0m[1m[38;5;12m|[0m[0m [0m[0m)>>) {}[0m +[0m [0m[0m[1m[38;5;12m| [0m[0m[1m[38;5;12m|___-[0m + +[0m[1m[38;5;9merror[0m[0m[1m: aborting due to 1 previous error[0m + +[0m[1mFor more information about this error, try `rustc --explain E0308`.[0m diff --git a/tests/ui/error-emitter/highlighting.rs b/tests/ui/error-emitter/highlighting.rs new file mode 100644 index 00000000000..fd61b2b05ff --- /dev/null +++ b/tests/ui/error-emitter/highlighting.rs @@ -0,0 +1,27 @@ +// Make sure "highlighted" code is colored purple + +// compile-flags: --error-format=human --color=always +// error-pattern:[35mfor<'a> [0m +// edition:2018 + +// revisions: windows not-windows +// [windows]only-windows +// [not-windows]ignore-windows + +use core::pin::Pin; +use core::future::Future; +use core::any::Any; + +fn query(_: fn(Box<(dyn Any + Send + '_)>) -> Pin<Box<( + dyn Future<Output = Result<Box<(dyn Any + 'static)>, String>> + Send + 'static +)>>) {} + +fn wrapped_fn<'a>(_: Box<(dyn Any + Send)>) -> Pin<Box<( + dyn Future<Output = Result<Box<(dyn Any + 'static)>, String>> + Send + 'static +)>> { + Box::pin(async { Err("nope".into()) }) +} + +fn main() { + query(wrapped_fn); +} diff --git a/tests/ui/error-emitter/highlighting.windows.stderr b/tests/ui/error-emitter/highlighting.windows.stderr new file mode 100644 index 00000000000..11d4125db4b --- /dev/null +++ b/tests/ui/error-emitter/highlighting.windows.stderr @@ -0,0 +1,22 @@ +[0m[1m[38;5;9merror[E0308][0m[0m[1m[38;5;15m: mismatched types[0m +[0m [0m[0m[1m[38;5;14m--> [0m[0m$DIR/highlighting.rs:26:11[0m +[0m [0m[0m[1m[38;5;14m|[0m +[0m[1m[38;5;14mLL[0m[0m [0m[0m[1m[38;5;14m|[0m[0m [0m[0m query(wrapped_fn);[0m +[0m [0m[0m[1m[38;5;14m| [0m[0m [0m[0m[1m[38;5;14m-----[0m[0m [0m[0m[1m[38;5;9m^^^^^^^^^^[0m[0m [0m[0m[1m[38;5;9mone type is more general than the other[0m +[0m [0m[0m[1m[38;5;14m| [0m[0m [0m[0m[1m[38;5;14m|[0m +[0m [0m[0m[1m[38;5;14m| [0m[0m [0m[0m[1m[38;5;14marguments to this function are incorrect[0m +[0m [0m[0m[1m[38;5;14m|[0m +[0m [0m[0m[1m[38;5;14m= [0m[0m[1m[38;5;15mnote[0m[0m: expected fn pointer `[0m[0m[1m[35mfor<'a> [0m[0mfn(Box<[0m[0m[1m[35m(dyn Any + Send + 'a)[0m[0m>) -> Pin<_>`[0m +[0m found fn item `fn(Box<[0m[0m[1m[35m(dyn Any + Send + 'static)[0m[0m>) -> Pin<_> {wrapped_fn}`[0m +[0m[1m[38;5;10mnote[0m[0m: function defined here[0m +[0m [0m[0m[1m[38;5;14m--> [0m[0m$DIR/highlighting.rs:15:4[0m +[0m [0m[0m[1m[38;5;14m|[0m +[0m[1m[38;5;14mLL[0m[0m [0m[0m[1m[38;5;14m|[0m[0m [0m[0mfn query(_: fn(Box<(dyn Any + Send + '_)>) -> Pin<Box<([0m +[0m [0m[0m[1m[38;5;14m| [0m[0m [0m[0m[1m[38;5;14m____[0m[0m[1m[38;5;10m^^^^^[0m[0m[1m[38;5;14m_-[0m +[0m[1m[38;5;14mLL[0m[0m [0m[0m[1m[38;5;14m|[0m[0m [0m[0m[1m[38;5;14m|[0m[0m [0m[0m dyn Future<Output = Result<Box<(dyn Any + 'static)>, String>> + Send + 'static[0m +[0m[1m[38;5;14mLL[0m[0m [0m[0m[1m[38;5;14m|[0m[0m [0m[0m[1m[38;5;14m|[0m[0m [0m[0m)>>) {}[0m +[0m [0m[0m[1m[38;5;14m| [0m[0m[1m[38;5;14m|___-[0m + +[0m[1m[38;5;9merror[0m[0m[1m[38;5;15m: aborting due to 1 previous error[0m + +[0m[1m[38;5;15mFor more information about this error, try `rustc --explain E0308`.[0m diff --git a/tests/ui/suggestions/multiline-multipart-suggestion.stderr b/tests/ui/error-emitter/multiline-multipart-suggestion.not-windows.stderr index 045a86b4f54..49c0354a2a7 100644 --- a/tests/ui/suggestions/multiline-multipart-suggestion.stderr +++ b/tests/ui/error-emitter/multiline-multipart-suggestion.not-windows.stderr @@ -1,17 +1,17 @@ [0m[1m[38;5;9merror[E0106][0m[0m[1m: missing lifetime specifier[0m -[0m [0m[0m[1m[38;5;12m--> [0m[0m$DIR/multiline-multipart-suggestion.rs:4:34[0m +[0m [0m[0m[1m[38;5;12m--> [0m[0m$DIR/multiline-multipart-suggestion.rs:8:34[0m [0m [0m[0m[1m[38;5;12m|[0m -[0m[1m[38;5;12mLL[0m[0m [0m[0m[1m[38;5;12m|[0m[0m [0m[0mfn short(foo_bar: &Vec<&i32>) -> &i32 { +[0m[1m[38;5;12mLL[0m[0m [0m[0m[1m[38;5;12m|[0m[0m [0m[0mfn short(foo_bar: &Vec<&i32>) -> &i32 {[0m [0m [0m[0m[1m[38;5;12m| [0m[0m [0m[0m[1m[38;5;12m----------[0m[0m [0m[0m[1m[38;5;9m^[0m[0m [0m[0m[1m[38;5;9mexpected named lifetime parameter[0m [0m [0m[0m[1m[38;5;12m|[0m [0m [0m[0m[1m[38;5;12m= [0m[0m[1mhelp[0m[0m: this function's return type contains a borrowed value, but the signature does not say which one of `foo_bar`'s 2 lifetimes it is borrowed from[0m [0m[1m[38;5;14mhelp[0m[0m: consider introducing a named lifetime parameter[0m [0m [0m[0m[1m[38;5;12m|[0m -[0m[1m[38;5;12mLL[0m[0m [0m[0m[1m[38;5;12m| [0m[0mfn short[0m[0m[38;5;10m<'a>[0m[0m(foo_bar: &[0m[0m[38;5;10m'a [0m[0mVec<&[0m[0m[38;5;10m'a [0m[0mi32>) -> &[0m[0m[38;5;10m'a [0m[0mi32 { +[0m[1m[38;5;12mLL[0m[0m [0m[0m[1m[38;5;12m| [0m[0mfn short[0m[0m[38;5;10m<'a>[0m[0m(foo_bar: &[0m[0m[38;5;10m'a [0m[0mVec<&[0m[0m[38;5;10m'a [0m[0mi32>) -> &[0m[0m[38;5;10m'a [0m[0mi32 {[0m [0m [0m[0m[1m[38;5;12m|[0m[0m [0m[0m[38;5;10m++++[0m[0m [0m[0m[38;5;10m++[0m[0m [0m[0m[38;5;10m++[0m[0m [0m[0m[38;5;10m++[0m [0m[1m[38;5;9merror[E0106][0m[0m[1m: missing lifetime specifier[0m -[0m [0m[0m[1m[38;5;12m--> [0m[0m$DIR/multiline-multipart-suggestion.rs:11:6[0m +[0m [0m[0m[1m[38;5;12m--> [0m[0m$DIR/multiline-multipart-suggestion.rs:15:6[0m [0m [0m[0m[1m[38;5;12m|[0m [0m[1m[38;5;12mLL[0m[0m [0m[0m[1m[38;5;12m|[0m[0m [0m[0m foo_bar: &Vec<&i32>,[0m [0m [0m[0m[1m[38;5;12m| [0m[0m [0m[0m[1m[38;5;12m----------[0m @@ -22,14 +22,14 @@ [0m [0m[0m[1m[38;5;12m= [0m[0m[1mhelp[0m[0m: this function's return type contains a borrowed value, but the signature does not say which one of `foo_bar`'s 2 lifetimes it is borrowed from[0m [0m[1m[38;5;14mhelp[0m[0m: consider introducing a named lifetime parameter[0m [0m [0m[0m[1m[38;5;12m|[0m -[0m[1m[38;5;12mLL[0m[0m [0m[0m[38;5;10m~ [0m[0mfn long[0m[0m[38;5;10m<'a>[0m[0m( +[0m[1m[38;5;12mLL[0m[0m [0m[0m[38;5;10m~ [0m[0mfn long[0m[0m[38;5;10m<'a>[0m[0m([0m [0m[1m[38;5;12mLL[0m[0m [0m[0m[38;5;10m~ [0m[0m foo_bar: &[0m[0m[38;5;10m'a [0m[0mVec<&[0m[0m[38;5;10m'a [0m[0mi32>,[0m [0m[1m[38;5;12mLL[0m[0m [0m[0m[1m[38;5;12m| [0m[0m something_very_long_so_that_the_line_will_wrap_around__________: i32,[0m [0m[1m[38;5;12mLL[0m[0m [0m[0m[38;5;10m~ [0m[0m) -> &[0m[0m[38;5;10m'a [0m[0mi32 {[0m [0m [0m[0m[1m[38;5;12m|[0m [0m[1m[38;5;9merror[E0106][0m[0m[1m: missing lifetime specifier[0m -[0m [0m[0m[1m[38;5;12m--> [0m[0m$DIR/multiline-multipart-suggestion.rs:16:29[0m +[0m [0m[0m[1m[38;5;12m--> [0m[0m$DIR/multiline-multipart-suggestion.rs:20:29[0m [0m [0m[0m[1m[38;5;12m|[0m [0m[1m[38;5;12mLL[0m[0m [0m[0m[1m[38;5;12m|[0m[0m [0m[0m foo_bar: &Vec<&i32>) -> &i32 {[0m [0m [0m[0m[1m[38;5;12m| [0m[0m [0m[0m[1m[38;5;12m----------[0m[0m [0m[0m[1m[38;5;9m^[0m[0m [0m[0m[1m[38;5;9mexpected named lifetime parameter[0m @@ -37,7 +37,7 @@ [0m [0m[0m[1m[38;5;12m= [0m[0m[1mhelp[0m[0m: this function's return type contains a borrowed value, but the signature does not say which one of `foo_bar`'s 2 lifetimes it is borrowed from[0m [0m[1m[38;5;14mhelp[0m[0m: consider introducing a named lifetime parameter[0m [0m [0m[0m[1m[38;5;12m|[0m -[0m[1m[38;5;12mLL[0m[0m [0m[0m[38;5;10m~ [0m[0mfn long2[0m[0m[38;5;10m<'a>[0m[0m( +[0m[1m[38;5;12mLL[0m[0m [0m[0m[38;5;10m~ [0m[0mfn long2[0m[0m[38;5;10m<'a>[0m[0m([0m [0m[1m[38;5;12mLL[0m[0m [0m[0m[38;5;10m~ [0m[0m foo_bar: &[0m[0m[38;5;10m'a [0m[0mVec<&[0m[0m[38;5;10m'a [0m[0mi32>) -> &[0m[0m[38;5;10m'a [0m[0mi32 {[0m [0m [0m[0m[1m[38;5;12m|[0m diff --git a/tests/ui/suggestions/multiline-multipart-suggestion.rs b/tests/ui/error-emitter/multiline-multipart-suggestion.rs index 77d0322d05f..a06399c3458 100644 --- a/tests/ui/suggestions/multiline-multipart-suggestion.rs +++ b/tests/ui/error-emitter/multiline-multipart-suggestion.rs @@ -1,18 +1,22 @@ // compile-flags: --error-format=human --color=always -// ignore-windows +// error-pattern: missing lifetime specifier -fn short(foo_bar: &Vec<&i32>) -> &i32 { //~ ERROR missing lifetime specifier +// revisions: windows not-windows +// [windows]only-windows +// [not-windows]ignore-windows + +fn short(foo_bar: &Vec<&i32>) -> &i32 { &12 } -fn long( //~ ERROR missing lifetime specifier +fn long( foo_bar: &Vec<&i32>, something_very_long_so_that_the_line_will_wrap_around__________: i32, ) -> &i32 { &12 } -fn long2( //~ ERROR missing lifetime specifier +fn long2( foo_bar: &Vec<&i32>) -> &i32 { &12 } diff --git a/tests/ui/error-emitter/multiline-multipart-suggestion.windows.stderr b/tests/ui/error-emitter/multiline-multipart-suggestion.windows.stderr new file mode 100644 index 00000000000..bf32c228de3 --- /dev/null +++ b/tests/ui/error-emitter/multiline-multipart-suggestion.windows.stderr @@ -0,0 +1,46 @@ +[0m[1m[38;5;9merror[E0106][0m[0m[1m[38;5;15m: missing lifetime specifier[0m +[0m [0m[0m[1m[38;5;14m--> [0m[0m$DIR/multiline-multipart-suggestion.rs:8:34[0m +[0m [0m[0m[1m[38;5;14m|[0m +[0m[1m[38;5;14mLL[0m[0m [0m[0m[1m[38;5;14m|[0m[0m [0m[0mfn short(foo_bar: &Vec<&i32>) -> &i32 {[0m +[0m [0m[0m[1m[38;5;14m| [0m[0m [0m[0m[1m[38;5;14m----------[0m[0m [0m[0m[1m[38;5;9m^[0m[0m [0m[0m[1m[38;5;9mexpected named lifetime parameter[0m +[0m [0m[0m[1m[38;5;14m|[0m +[0m [0m[0m[1m[38;5;14m= [0m[0m[1m[38;5;15mhelp[0m[0m: this function's return type contains a borrowed value, but the signature does not say which one of `foo_bar`'s 2 lifetimes it is borrowed from[0m +[0m[1m[38;5;14mhelp[0m[0m: consider introducing a named lifetime parameter[0m +[0m [0m[0m[1m[38;5;14m|[0m +[0m[1m[38;5;14mLL[0m[0m [0m[0m[1m[38;5;14m| [0m[0mfn short[0m[0m[38;5;10m<'a>[0m[0m(foo_bar: &[0m[0m[38;5;10m'a [0m[0mVec<&[0m[0m[38;5;10m'a [0m[0mi32>) -> &[0m[0m[38;5;10m'a [0m[0mi32 {[0m +[0m [0m[0m[1m[38;5;14m|[0m[0m [0m[0m[38;5;10m++++[0m[0m [0m[0m[38;5;10m++[0m[0m [0m[0m[38;5;10m++[0m[0m [0m[0m[38;5;10m++[0m + +[0m[1m[38;5;9merror[E0106][0m[0m[1m[38;5;15m: missing lifetime specifier[0m +[0m [0m[0m[1m[38;5;14m--> [0m[0m$DIR/multiline-multipart-suggestion.rs:15:6[0m +[0m [0m[0m[1m[38;5;14m|[0m +[0m[1m[38;5;14mLL[0m[0m [0m[0m[1m[38;5;14m|[0m[0m [0m[0m foo_bar: &Vec<&i32>,[0m +[0m [0m[0m[1m[38;5;14m| [0m[0m [0m[0m[1m[38;5;14m----------[0m +[0m[1m[38;5;14mLL[0m[0m [0m[0m[1m[38;5;14m|[0m[0m [0m[0m something_very_long_so_that_the_line_will_wrap_around__________: i32,[0m +[0m[1m[38;5;14mLL[0m[0m [0m[0m[1m[38;5;14m|[0m[0m [0m[0m) -> &i32 {[0m +[0m [0m[0m[1m[38;5;14m| [0m[0m [0m[0m[1m[38;5;9m^[0m[0m [0m[0m[1m[38;5;9mexpected named lifetime parameter[0m +[0m [0m[0m[1m[38;5;14m|[0m +[0m [0m[0m[1m[38;5;14m= [0m[0m[1m[38;5;15mhelp[0m[0m: this function's return type contains a borrowed value, but the signature does not say which one of `foo_bar`'s 2 lifetimes it is borrowed from[0m +[0m[1m[38;5;14mhelp[0m[0m: consider introducing a named lifetime parameter[0m +[0m [0m[0m[1m[38;5;14m|[0m +[0m[1m[38;5;14mLL[0m[0m [0m[0m[38;5;10m~ [0m[0mfn long[0m[0m[38;5;10m<'a>[0m[0m([0m +[0m[1m[38;5;14mLL[0m[0m [0m[0m[38;5;10m~ [0m[0m foo_bar: &[0m[0m[38;5;10m'a [0m[0mVec<&[0m[0m[38;5;10m'a [0m[0mi32>,[0m +[0m[1m[38;5;14mLL[0m[0m [0m[0m[1m[38;5;14m| [0m[0m something_very_long_so_that_the_line_will_wrap_around__________: i32,[0m +[0m[1m[38;5;14mLL[0m[0m [0m[0m[38;5;10m~ [0m[0m) -> &[0m[0m[38;5;10m'a [0m[0mi32 {[0m +[0m [0m[0m[1m[38;5;14m|[0m + +[0m[1m[38;5;9merror[E0106][0m[0m[1m[38;5;15m: missing lifetime specifier[0m +[0m [0m[0m[1m[38;5;14m--> [0m[0m$DIR/multiline-multipart-suggestion.rs:20:29[0m +[0m [0m[0m[1m[38;5;14m|[0m +[0m[1m[38;5;14mLL[0m[0m [0m[0m[1m[38;5;14m|[0m[0m [0m[0m foo_bar: &Vec<&i32>) -> &i32 {[0m +[0m [0m[0m[1m[38;5;14m| [0m[0m [0m[0m[1m[38;5;14m----------[0m[0m [0m[0m[1m[38;5;9m^[0m[0m [0m[0m[1m[38;5;9mexpected named lifetime parameter[0m +[0m [0m[0m[1m[38;5;14m|[0m +[0m [0m[0m[1m[38;5;14m= [0m[0m[1m[38;5;15mhelp[0m[0m: this function's return type contains a borrowed value, but the signature does not say which one of `foo_bar`'s 2 lifetimes it is borrowed from[0m +[0m[1m[38;5;14mhelp[0m[0m: consider introducing a named lifetime parameter[0m +[0m [0m[0m[1m[38;5;14m|[0m +[0m[1m[38;5;14mLL[0m[0m [0m[0m[38;5;10m~ [0m[0mfn long2[0m[0m[38;5;10m<'a>[0m[0m([0m +[0m[1m[38;5;14mLL[0m[0m [0m[0m[38;5;10m~ [0m[0m foo_bar: &[0m[0m[38;5;10m'a [0m[0mVec<&[0m[0m[38;5;10m'a [0m[0mi32>) -> &[0m[0m[38;5;10m'a [0m[0mi32 {[0m +[0m [0m[0m[1m[38;5;14m|[0m + +[0m[1m[38;5;9merror[0m[0m[1m[38;5;15m: aborting due to 3 previous errors[0m + +[0m[1m[38;5;15mFor more information about this error, try `rustc --explain E0106`.[0m diff --git a/tests/ui/extern/issue-116203.rs b/tests/ui/extern/issue-116203.rs new file mode 100644 index 00000000000..f8212841644 --- /dev/null +++ b/tests/ui/extern/issue-116203.rs @@ -0,0 +1,21 @@ +extern "C" { + thread_local! { + static FOO: u32 = 0; + //~^ error: extern items cannot be `const` + //~| error: incorrect `static` inside `extern` block + } +} + +macro_rules! hello { + ($name:ident) => { + const $name: () = (); + }; +} + +extern "C" { + hello! { yes } + //~^ error: extern items cannot be `const` + //~| error: incorrect `static` inside `extern` block +} + +fn main() {} diff --git a/tests/ui/extern/issue-116203.stderr b/tests/ui/extern/issue-116203.stderr new file mode 100644 index 00000000000..86e4cc763bd --- /dev/null +++ b/tests/ui/extern/issue-116203.stderr @@ -0,0 +1,46 @@ +error: extern items cannot be `const` + --> $DIR/issue-116203.rs:3:14 + | +LL | static FOO: u32 = 0; + | ^^^ + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: extern items cannot be `const` + --> $DIR/issue-116203.rs:16:14 + | +LL | hello! { yes } + | ^^^ + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: incorrect `static` inside `extern` block + --> $DIR/issue-116203.rs:3:14 + | +LL | extern "C" { + | ---------- `extern` blocks define existing foreign statics and statics inside of them cannot have a body +LL | / thread_local! { +LL | | static FOO: u32 = 0; + | | ^^^ cannot have a body +LL | | +LL | | +LL | | } + | |_____- the invalid body + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: incorrect `static` inside `extern` block + --> $DIR/issue-116203.rs:16:14 + | +LL | const $name: () = (); + | -- the invalid body +... +LL | extern "C" { + | ---------- `extern` blocks define existing foreign statics and statics inside of them cannot have a body +LL | hello! { yes } + | ^^^ cannot have a body + | + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: aborting due to 4 previous errors + diff --git a/tests/ui/feature-gates/feature-gate-check-cfg.rs b/tests/ui/feature-gates/feature-gate-check-cfg.rs index 4012a3b04b5..953b8e3ffce 100644 --- a/tests/ui/feature-gates/feature-gate-check-cfg.rs +++ b/tests/ui/feature-gates/feature-gate-check-cfg.rs @@ -1,3 +1,3 @@ -// compile-flags: --check-cfg "names()" +// compile-flags: --check-cfg "cfg()" fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr b/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr index 8694924e52f..c89dcaf727a 100644 --- a/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr +++ b/tests/ui/feature-gates/feature-gate-precise_pointer_size_matching.stderr @@ -6,7 +6,6 @@ LL | match 0usize { | = note: the matched value is of type `usize` = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ 0..=usize::MAX => {}, @@ -21,7 +20,6 @@ LL | match 0isize { | = note: the matched value is of type `isize` = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ isize::MIN..=isize::MAX => {}, diff --git a/tests/ui/generic-associated-types/parse/trait-path-expected-token.stderr b/tests/ui/generic-associated-types/parse/trait-path-expected-token.stderr index 59c21e24a42..838d37cc64f 100644 --- a/tests/ui/generic-associated-types/parse/trait-path-expected-token.stderr +++ b/tests/ui/generic-associated-types/parse/trait-path-expected-token.stderr @@ -2,9 +2,7 @@ error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=` --> $DIR/trait-path-expected-token.rs:5:33 | LL | fn f1<'a>(arg : Box<dyn X<Y = B = &'a ()>>) {} - | - ^ expected one of 7 possible tokens - | | - | maybe try to close unmatched angle bracket + | ^ expected one of 7 possible tokens error: aborting due to 1 previous error diff --git a/tests/ui/generic-associated-types/parse/trait-path-expressions.stderr b/tests/ui/generic-associated-types/parse/trait-path-expressions.stderr index cf2b1763fc9..06dbf00af63 100644 --- a/tests/ui/generic-associated-types/parse/trait-path-expressions.stderr +++ b/tests/ui/generic-associated-types/parse/trait-path-expressions.stderr @@ -10,9 +10,7 @@ error: expected one of `,`, `:`, or `>`, found `=` --> $DIR/trait-path-expressions.rs:16:36 | LL | fn f2<'a>(arg : Box<dyn X< { 1 } = 32 >>) {} - | - ^ expected one of `,`, `:`, or `>` - | | - | maybe try to close unmatched angle bracket + | ^ expected one of `,`, `:`, or `>` | help: you might have meant to end the type parameters here | diff --git a/tests/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr b/tests/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr index bfddb6dc693..4bc57f55096 100644 --- a/tests/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr +++ b/tests/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr @@ -8,9 +8,7 @@ error: expected one of `>`, a const expression, lifetime, or type, found `=` --> $DIR/trait-path-missing-gen_arg.rs:11:30 | LL | fn f1<'a>(arg : Box<dyn X< = 32 >>) {} - | - ^ expected one of `>`, a const expression, lifetime, or type - | | - | maybe try to close unmatched angle bracket + | ^ expected one of `>`, a const expression, lifetime, or type error: aborting due to 2 previous errors diff --git a/tests/ui/generic-associated-types/parse/trait-path-segments.stderr b/tests/ui/generic-associated-types/parse/trait-path-segments.stderr index 8bc737d6752..0ab155590e2 100644 --- a/tests/ui/generic-associated-types/parse/trait-path-segments.stderr +++ b/tests/ui/generic-associated-types/parse/trait-path-segments.stderr @@ -2,9 +2,7 @@ error: expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, or `>`, found `=` --> $DIR/trait-path-segments.rs:6:36 | LL | fn f1<'a>(arg : Box<dyn X<X::Y = u32>>) {} - | - ^ expected one of 8 possible tokens - | | - | maybe try to close unmatched angle bracket + | ^ expected one of 8 possible tokens | help: you might have meant to end the type parameters here | @@ -15,9 +13,7 @@ error: expected one of `,`, `::`, `:`, or `>`, found `=` --> $DIR/trait-path-segments.rs:17:35 | LL | impl<T : X<<Self as X>::Y<'a> = &'a u32>> Z for T {} - | - ^ expected one of `,`, `::`, `:`, or `>` - | | - | maybe try to close unmatched angle bracket + | ^ expected one of `,`, `::`, `:`, or `>` | help: you might have meant to end the type parameters here | @@ -28,9 +24,7 @@ error: expected one of `!`, `+`, `,`, `::`, `:`, or `>`, found `=` --> $DIR/trait-path-segments.rs:28:25 | LL | impl<T : X<X::Y<'a> = &'a u32>> Z for T {} - | - ^ expected one of `!`, `+`, `,`, `::`, `:`, or `>` - | | - | maybe try to close unmatched angle bracket + | ^ expected one of `!`, `+`, `,`, `::`, `:`, or `>` | help: you might have meant to end the type parameters here | diff --git a/tests/ui/generic-associated-types/parse/trait-path-types.stderr b/tests/ui/generic-associated-types/parse/trait-path-types.stderr index 8f7a73c95b6..ec1aa71846d 100644 --- a/tests/ui/generic-associated-types/parse/trait-path-types.stderr +++ b/tests/ui/generic-associated-types/parse/trait-path-types.stderr @@ -2,9 +2,7 @@ error: expected one of `,`, `:`, or `>`, found `=` --> $DIR/trait-path-types.rs:6:37 | LL | fn f<'a>(arg : Box<dyn X< [u8; 1] = u32>>) {} - | - ^ expected one of `,`, `:`, or `>` - | | - | maybe try to close unmatched angle bracket + | ^ expected one of `,`, `:`, or `>` | help: you might have meant to end the type parameters here | @@ -15,9 +13,7 @@ error: expected one of `,`, `:`, or `>`, found `=` --> $DIR/trait-path-types.rs:11:37 | LL | fn f1<'a>(arg : Box<dyn X<(Y<'a>) = &'a ()>>) {} - | - ^ expected one of `,`, `:`, or `>` - | | - | maybe try to close unmatched angle bracket + | ^ expected one of `,`, `:`, or `>` | help: you might have meant to end the type parameters here | @@ -28,9 +24,7 @@ error: expected one of `,`, `:`, or `>`, found `=` --> $DIR/trait-path-types.rs:16:33 | LL | fn f1<'a>(arg : Box<dyn X< 'a = u32 >>) {} - | -- ^ expected one of `,`, `:`, or `>` - | | - | maybe try to close unmatched angle bracket + | ^ expected one of `,`, `:`, or `>` | help: you might have meant to end the type parameters here | diff --git a/tests/ui/generics/unclosed-generics-in-impl-def.rs b/tests/ui/generics/unclosed-generics-in-impl-def.rs new file mode 100644 index 00000000000..2ec99b16e55 --- /dev/null +++ b/tests/ui/generics/unclosed-generics-in-impl-def.rs @@ -0,0 +1,2 @@ +impl<S: Into<std::borrow::Cow<'static, str>> From<S> for Canonical {} //~ ERROR expected +fn main() {} diff --git a/tests/ui/generics/unclosed-generics-in-impl-def.stderr b/tests/ui/generics/unclosed-generics-in-impl-def.stderr new file mode 100644 index 00000000000..aa1977ad82a --- /dev/null +++ b/tests/ui/generics/unclosed-generics-in-impl-def.stderr @@ -0,0 +1,13 @@ +error: expected one of `+`, `,`, `::`, `=`, or `>`, found `From` + --> $DIR/unclosed-generics-in-impl-def.rs:1:46 + | +LL | impl<S: Into<std::borrow::Cow<'static, str>> From<S> for Canonical {} + | ^^^^ expected one of `+`, `,`, `::`, `=`, or `>` + | +help: you might have meant to end the type parameters here + | +LL | impl<S: Into<std::borrow::Cow<'static, str>>> From<S> for Canonical {} + | + + +error: aborting due to 1 previous error + diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr index 4ef96cd9541..1cf364aa9f6 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | foo(bar, "string", |s| s.len() == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a &'b str,)>` - found trait `for<'a> FnOnce<(&'a &str,)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a &'b str)` + found trait `for<'a> FnOnce(&'a &str)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:45:24 | @@ -23,8 +23,8 @@ error[E0308]: mismatched types LL | foo(bar, "string", |s| s.len() == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a &'b str,)>` - found trait `for<'a> FnOnce<(&'a &str,)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a &'b str)` + found trait `for<'a> FnOnce(&'a &str)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:45:24 | @@ -42,8 +42,8 @@ error[E0308]: mismatched types LL | foo(baz, "string", |s| s.0.len() == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a Wrapper<'b>,)>` - found trait `for<'a> FnOnce<(&'a Wrapper<'_>,)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a Wrapper<'b>)` + found trait `for<'a> FnOnce(&'a Wrapper<'_>)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:48:24 | @@ -61,8 +61,8 @@ error[E0308]: mismatched types LL | foo(baz, "string", |s| s.0.len() == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a Wrapper<'b>,)>` - found trait `for<'a> FnOnce<(&'a Wrapper<'_>,)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a Wrapper<'b>)` + found trait `for<'a> FnOnce(&'a Wrapper<'_>)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-71955.rs:48:24 | diff --git a/tests/ui/imports/issue-55884-2.stderr b/tests/ui/imports/issue-55884-2.stderr index a409265525b..8a9d5f2a6d8 100644 --- a/tests/ui/imports/issue-55884-2.stderr +++ b/tests/ui/imports/issue-55884-2.stderr @@ -13,17 +13,21 @@ note: ...and refers to the struct import `ParseOptions` which is defined here... --> $DIR/issue-55884-2.rs:13:9 | LL | pub use parser::ParseOptions; - | ^^^^^^^^^^^^^^^^^^^^ consider importing it directly + | ^^^^^^^^^^^^^^^^^^^^ you could import this re-export note: ...and refers to the struct import `ParseOptions` which is defined here... --> $DIR/issue-55884-2.rs:6:13 | LL | pub use options::*; - | ^^^^^^^^^^ consider importing it directly + | ^^^^^^^^^^ you could import this re-export note: ...and refers to the struct `ParseOptions` which is defined here --> $DIR/issue-55884-2.rs:2:5 | LL | pub struct ParseOptions {} - | ^^^^^^^^^^^^^^^^^^^^^^^ consider importing it directly + | ^^^^^^^^^^^^^^^^^^^^^^^ you could import this directly +help: import `ParseOptions` through the re-export + | +LL | pub use parser::ParseOptions; + | ~~~~~~~~~~~~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/imports/private-std-reexport-suggest-public.fixed b/tests/ui/imports/private-std-reexport-suggest-public.fixed new file mode 100644 index 00000000000..b6fd22f5d3f --- /dev/null +++ b/tests/ui/imports/private-std-reexport-suggest-public.fixed @@ -0,0 +1,9 @@ +// run-rustfix +#![allow(unused_imports)] +fn main() { + use std::mem; //~ ERROR module import `mem` is private +} + +pub mod foo { + use std::mem; +} diff --git a/tests/ui/imports/private-std-reexport-suggest-public.rs b/tests/ui/imports/private-std-reexport-suggest-public.rs new file mode 100644 index 00000000000..1247055af60 --- /dev/null +++ b/tests/ui/imports/private-std-reexport-suggest-public.rs @@ -0,0 +1,9 @@ +// run-rustfix +#![allow(unused_imports)] +fn main() { + use foo::mem; //~ ERROR module import `mem` is private +} + +pub mod foo { + use std::mem; +} diff --git a/tests/ui/imports/private-std-reexport-suggest-public.stderr b/tests/ui/imports/private-std-reexport-suggest-public.stderr new file mode 100644 index 00000000000..222553235aa --- /dev/null +++ b/tests/ui/imports/private-std-reexport-suggest-public.stderr @@ -0,0 +1,23 @@ +error[E0603]: module import `mem` is private + --> $DIR/private-std-reexport-suggest-public.rs:4:14 + | +LL | use foo::mem; + | ^^^ private module import + | +note: the module import `mem` is defined here... + --> $DIR/private-std-reexport-suggest-public.rs:8:9 + | +LL | use std::mem; + | ^^^^^^^^ +note: ...and refers to the module `mem` which is defined here + --> $SRC_DIR/std/src/lib.rs:LL:COL + | + = note: you could import this directly +help: import `mem` through the re-export + | +LL | use std::mem; + | ~~~~~~~~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/invalid-compile-flags/fuel.rs b/tests/ui/invalid-compile-flags/fuel.rs new file mode 100644 index 00000000000..456bc47d359 --- /dev/null +++ b/tests/ui/invalid-compile-flags/fuel.rs @@ -0,0 +1,11 @@ +// revisions: incremental threads +// dont-check-compiler-stderr +// +// [threads] compile-flags: -Zfuel=a=1 -Zthreads=2 +// [threads] error-pattern:optimization fuel is incompatible with multiple threads +// +// [incremental] incremental +// [incremental] compile-flags: -Zprint-fuel=a +// [incremental] error-pattern:optimization fuel is incompatible with incremental compilation + +fn main() {} diff --git a/tests/ui/issues/issue-34334.stderr b/tests/ui/issues/issue-34334.stderr index 753942dd1d1..ac2e63eca3e 100644 --- a/tests/ui/issues/issue-34334.stderr +++ b/tests/ui/issues/issue-34334.stderr @@ -2,9 +2,8 @@ error: expected one of `,`, `:`, or `>`, found `=` --> $DIR/issue-34334.rs:2:29 | LL | let sr: Vec<(u32, _, _) = vec![]; - | -- - ^ expected one of `,`, `:`, or `>` - | | | - | | maybe try to close unmatched angle bracket + | -- ^ expected one of `,`, `:`, or `>` + | | | while parsing the type for `sr` | help: you might have meant to end the type parameters here diff --git a/tests/ui/lifetimes/issue-105675.stderr b/tests/ui/lifetimes/issue-105675.stderr index 54ecd35ed6a..f1fa5a59860 100644 --- a/tests/ui/lifetimes/issue-105675.stderr +++ b/tests/ui/lifetimes/issue-105675.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | thing(f); | ^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>` - found trait `for<'a> FnOnce<(&u32, &'a u32, u32)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)` + found trait `for<'a> FnOnce(&u32, &'a u32, u32)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-105675.rs:4:13 | @@ -27,8 +27,8 @@ error[E0308]: mismatched types LL | thing(f); | ^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>` - found trait `for<'a> FnOnce<(&u32, &'a u32, u32)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)` + found trait `for<'a> FnOnce(&u32, &'a u32, u32)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-105675.rs:4:13 | @@ -46,8 +46,8 @@ error[E0308]: mismatched types LL | thing(f); | ^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>` - found trait `FnOnce<(&u32, &u32, u32)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)` + found trait `FnOnce(&u32, &u32, u32)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-105675.rs:8:13 | @@ -69,8 +69,8 @@ error[E0308]: mismatched types LL | thing(f); | ^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> FnOnce<(&'a u32, &'b u32, u32)>` - found trait `FnOnce<(&u32, &u32, u32)>` + = note: expected trait `for<'a, 'b> FnOnce(&'a u32, &'b u32, u32)` + found trait `FnOnce(&u32, &u32, u32)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-105675.rs:8:13 | diff --git a/tests/ui/lifetimes/issue-79187-2.stderr b/tests/ui/lifetimes/issue-79187-2.stderr index 75fd87b3fe9..86a4ac4132e 100644 --- a/tests/ui/lifetimes/issue-79187-2.stderr +++ b/tests/ui/lifetimes/issue-79187-2.stderr @@ -31,8 +31,8 @@ error[E0308]: mismatched types LL | take_foo(|a| a); | ^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> Fn<(&'a i32,)>` - found trait `Fn<(&i32,)>` + = note: expected trait `for<'a> Fn(&'a i32)` + found trait `Fn(&i32)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-79187-2.rs:8:14 | diff --git a/tests/ui/lifetimes/issue-79187.stderr b/tests/ui/lifetimes/issue-79187.stderr index 209f2b7b739..14bdfe75c08 100644 --- a/tests/ui/lifetimes/issue-79187.stderr +++ b/tests/ui/lifetimes/issue-79187.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | thing(f); | ^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> FnOnce<(&'a u32,)>` - found trait `FnOnce<(&u32,)>` + = note: expected trait `for<'a> FnOnce(&'a u32)` + found trait `FnOnce(&u32)` note: this closure does not fulfill the lifetime requirements --> $DIR/issue-79187.rs:4:13 | diff --git a/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr b/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr index dbc587dd004..677f918fe93 100644 --- a/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr +++ b/tests/ui/lifetimes/lifetime-errors/issue_74400.stderr @@ -18,8 +18,8 @@ error[E0308]: mismatched types LL | f(data, identity) | ^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> Fn<(&'a T,)>` - found trait `Fn<(&T,)>` + = note: expected trait `for<'a> Fn(&'a T)` + found trait `Fn(&T)` note: the lifetime requirement is introduced here --> $DIR/issue_74400.rs:8:34 | diff --git a/tests/ui/lint/internal_features.rs b/tests/ui/lint/internal_features.rs new file mode 100644 index 00000000000..32ce9540cb3 --- /dev/null +++ b/tests/ui/lint/internal_features.rs @@ -0,0 +1,11 @@ +#![forbid(internal_features)] +// A lang feature and a lib feature. +#![feature(intrinsics, panic_internals)] +//~^ ERROR: internal +//~| ERROR: internal + +extern "rust-intrinsic" { + fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize); +} + +fn main() {} diff --git a/tests/ui/lint/internal_features.stderr b/tests/ui/lint/internal_features.stderr new file mode 100644 index 00000000000..8b52bef8f03 --- /dev/null +++ b/tests/ui/lint/internal_features.stderr @@ -0,0 +1,23 @@ +error: the feature `intrinsics` is internal to the compiler or standard library + --> $DIR/internal_features.rs:3:12 + | +LL | #![feature(intrinsics, panic_internals)] + | ^^^^^^^^^^ + | + = note: using it is strongly discouraged +note: the lint level is defined here + --> $DIR/internal_features.rs:1:11 + | +LL | #![forbid(internal_features)] + | ^^^^^^^^^^^^^^^^^ + +error: the feature `panic_internals` is internal to the compiler or standard library + --> $DIR/internal_features.rs:3:24 + | +LL | #![feature(intrinsics, panic_internals)] + | ^^^^^^^^^^^^^^^ + | + = note: using it is strongly discouraged + +error: aborting due to 2 previous errors + diff --git a/tests/ui/lint/unused/assoc-types.assoc_ty.stderr b/tests/ui/lint/unused/assoc-types.assoc_ty.stderr new file mode 100644 index 00000000000..190c4ef0cea --- /dev/null +++ b/tests/ui/lint/unused/assoc-types.assoc_ty.stderr @@ -0,0 +1,15 @@ +error: unused implementer of `Future` that must be used + --> $DIR/assoc-types.rs:19:5 + | +LL | T::foo(); + | ^^^^^^^^ + | + = note: futures do nothing unless you `.await` or poll them +note: the lint level is defined here + --> $DIR/assoc-types.rs:4:9 + | +LL | #![deny(unused_must_use)] + | ^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/unused/assoc-types.rpitit.stderr b/tests/ui/lint/unused/assoc-types.rpitit.stderr new file mode 100644 index 00000000000..190c4ef0cea --- /dev/null +++ b/tests/ui/lint/unused/assoc-types.rpitit.stderr @@ -0,0 +1,15 @@ +error: unused implementer of `Future` that must be used + --> $DIR/assoc-types.rs:19:5 + | +LL | T::foo(); + | ^^^^^^^^ + | + = note: futures do nothing unless you `.await` or poll them +note: the lint level is defined here + --> $DIR/assoc-types.rs:4:9 + | +LL | #![deny(unused_must_use)] + | ^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/unused/assoc-types.rs b/tests/ui/lint/unused/assoc-types.rs new file mode 100644 index 00000000000..cebb9b4090c --- /dev/null +++ b/tests/ui/lint/unused/assoc-types.rs @@ -0,0 +1,23 @@ +// edition: 2021 +// revisions: rpitit assoc_ty + +#![deny(unused_must_use)] + +use std::future::Future; + +pub trait Tr { + type Fut: Future<Output = ()>; + + #[cfg(rpitit)] + fn foo() -> impl Future<Output = ()>; + + #[cfg(assoc_ty)] + fn foo() -> Self::Fut; +} + +pub async fn bar<T: Tr>() { + T::foo(); + //~^ ERROR unused implementer of `Future` that must be used +} + +fn main() {} diff --git a/tests/ui/mismatched_types/closure-mismatch.stderr b/tests/ui/mismatched_types/closure-mismatch.stderr index c5b8270ba84..74033c18573 100644 --- a/tests/ui/mismatched_types/closure-mismatch.stderr +++ b/tests/ui/mismatched_types/closure-mismatch.stderr @@ -13,8 +13,8 @@ error[E0308]: mismatched types LL | baz(|_| ()); | ^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> Fn<(&'a (),)>` - found trait `Fn<(&(),)>` + = note: expected trait `for<'a> Fn(&'a ())` + found trait `Fn(&())` note: this closure does not fulfill the lifetime requirements --> $DIR/closure-mismatch.rs:8:9 | @@ -45,8 +45,8 @@ error[E0308]: mismatched types LL | baz(|x| ()); | ^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> Fn<(&'a (),)>` - found trait `Fn<(&(),)>` + = note: expected trait `for<'a> Fn(&'a ())` + found trait `Fn(&())` note: this closure does not fulfill the lifetime requirements --> $DIR/closure-mismatch.rs:11:9 | diff --git a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.fixed b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.fixed new file mode 100644 index 00000000000..e88ca6079ec --- /dev/null +++ b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.fixed @@ -0,0 +1,30 @@ +// run-rustfix +#![allow(unused_variables, dead_code)] +use std::collections::BTreeMap; +use std::collections::HashSet; + +#[derive(Debug,Eq,PartialEq,Hash)] +#[derive(Clone)] +enum Day { + Mon, +} + +struct Class { + days: BTreeMap<u32, HashSet<Day>> +} + +impl Class { + fn do_stuff(&self) { + for (_, v) in &self.days { + let mut x: HashSet<Day> = v.clone(); //~ ERROR + let y: Vec<Day> = x.drain().collect(); + println!("{:?}", x); + } + } +} + +fn fail() { + let c = Class { days: BTreeMap::new() }; + c.do_stuff(); +} +fn main() {} diff --git a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.rs b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.rs new file mode 100644 index 00000000000..ba277c4a9c4 --- /dev/null +++ b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.rs @@ -0,0 +1,29 @@ +// run-rustfix +#![allow(unused_variables, dead_code)] +use std::collections::BTreeMap; +use std::collections::HashSet; + +#[derive(Debug,Eq,PartialEq,Hash)] +enum Day { + Mon, +} + +struct Class { + days: BTreeMap<u32, HashSet<Day>> +} + +impl Class { + fn do_stuff(&self) { + for (_, v) in &self.days { + let mut x: HashSet<Day> = v.clone(); //~ ERROR + let y: Vec<Day> = x.drain().collect(); + println!("{:?}", x); + } + } +} + +fn fail() { + let c = Class { days: BTreeMap::new() }; + c.do_stuff(); +} +fn main() {} diff --git a/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.stderr b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.stderr new file mode 100644 index 00000000000..821661f1a56 --- /dev/null +++ b/tests/ui/moves/assignment-of-clone-call-on-ref-due-to-missing-bound.stderr @@ -0,0 +1,25 @@ +error[E0308]: mismatched types + --> $DIR/assignment-of-clone-call-on-ref-due-to-missing-bound.rs:18:39 + | +LL | let mut x: HashSet<Day> = v.clone(); + | ------------ ^^^^^^^^^ expected `HashSet<Day>`, found `&HashSet<Day>` + | | + | expected due to this + | + = note: expected struct `HashSet<Day>` + found reference `&HashSet<Day>` +note: `HashSet<Day>` does not implement `Clone`, so `&HashSet<Day>` was cloned instead + --> $DIR/assignment-of-clone-call-on-ref-due-to-missing-bound.rs:18:39 + | +LL | let mut x: HashSet<Day> = v.clone(); + | ^ + = help: `Clone` is not implemented because the trait bound `Day: Clone` is not satisfied +help: consider annotating `Day` with `#[derive(Clone)]` + | +LL + #[derive(Clone)] +LL | enum Day { + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/moves/move-fn-self-receiver.stderr b/tests/ui/moves/move-fn-self-receiver.stderr index c91a8b5efac..462deacbe8d 100644 --- a/tests/ui/moves/move-fn-self-receiver.stderr +++ b/tests/ui/moves/move-fn-self-receiver.stderr @@ -55,6 +55,10 @@ note: `Foo::use_box_self` takes ownership of the receiver `self`, which moves `b | LL | fn use_box_self(self: Box<Self>) {} | ^^^^ +help: you could `clone` the value and consume it, if the `Box<Foo>: Clone` trait bound could be satisfied + | +LL | boxed_foo.clone().use_box_self(); + | ++++++++ error[E0382]: use of moved value: `pin_box_foo` --> $DIR/move-fn-self-receiver.rs:46:5 @@ -71,6 +75,10 @@ note: `Foo::use_pin_box_self` takes ownership of the receiver `self`, which move | LL | fn use_pin_box_self(self: Pin<Box<Self>>) {} | ^^^^ +help: you could `clone` the value and consume it, if the `Box<Foo>: Clone` trait bound could be satisfied + | +LL | pin_box_foo.clone().use_pin_box_self(); + | ++++++++ error[E0505]: cannot move out of `mut_foo` because it is borrowed --> $DIR/move-fn-self-receiver.rs:50:5 diff --git a/tests/ui/moves/needs-clone-through-deref.fixed b/tests/ui/moves/needs-clone-through-deref.fixed new file mode 100644 index 00000000000..419718175e9 --- /dev/null +++ b/tests/ui/moves/needs-clone-through-deref.fixed @@ -0,0 +1,18 @@ +// run-rustfix +#![allow(dead_code, noop_method_call)] +use std::ops::Deref; +struct S(Vec<usize>); +impl Deref for S { + type Target = Vec<usize>; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl S { + fn foo(&self) { + // `self.clone()` returns `&S`, not `Vec` + for _ in <Vec<usize> as Clone>::clone(&self.clone()).into_iter() {} //~ ERROR cannot move out of dereference of `S` + } +} +fn main() {} diff --git a/tests/ui/moves/needs-clone-through-deref.rs b/tests/ui/moves/needs-clone-through-deref.rs new file mode 100644 index 00000000000..8116008ffe3 --- /dev/null +++ b/tests/ui/moves/needs-clone-through-deref.rs @@ -0,0 +1,18 @@ +// run-rustfix +#![allow(dead_code, noop_method_call)] +use std::ops::Deref; +struct S(Vec<usize>); +impl Deref for S { + type Target = Vec<usize>; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl S { + fn foo(&self) { + // `self.clone()` returns `&S`, not `Vec` + for _ in self.clone().into_iter() {} //~ ERROR cannot move out of dereference of `S` + } +} +fn main() {} diff --git a/tests/ui/moves/needs-clone-through-deref.stderr b/tests/ui/moves/needs-clone-through-deref.stderr new file mode 100644 index 00000000000..ff92f32e8d2 --- /dev/null +++ b/tests/ui/moves/needs-clone-through-deref.stderr @@ -0,0 +1,18 @@ +error[E0507]: cannot move out of dereference of `S` + --> $DIR/needs-clone-through-deref.rs:15:18 + | +LL | for _ in self.clone().into_iter() {} + | ^^^^^^^^^^^^ ----------- value moved due to this method call + | | + | move occurs because value has type `Vec<usize>`, which does not implement the `Copy` trait + | +note: `into_iter` takes ownership of the receiver `self`, which moves value + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL +help: you can `clone` the value and consume it, but this might not be your desired behavior + | +LL | for _ in <Vec<usize> as Clone>::clone(&self.clone()).into_iter() {} + | ++++++++++++++++++++++++++++++ + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.fixed b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.fixed new file mode 100644 index 00000000000..a4e219e1c9b --- /dev/null +++ b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.fixed @@ -0,0 +1,28 @@ +// run-rustfix +// Issue #109429 +use std::collections::hash_map::DefaultHasher; +use std::collections::HashMap; +use std::hash::BuildHasher; +use std::hash::Hash; + +#[derive(Clone)] +pub struct Hash128_1; + +impl BuildHasher for Hash128_1 { + type Hasher = DefaultHasher; + fn build_hasher(&self) -> DefaultHasher { DefaultHasher::default() } +} + +#[allow(unused)] +pub fn hashmap_copy<T, U>( + map: &HashMap<T, U, Hash128_1>, +) where T: Hash + Clone, U: Clone +{ + let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map.clone()).into_values().collect(); //~ ERROR +} + +pub fn make_map() -> HashMap<String, i64, Hash128_1> +{ + HashMap::with_hasher(Hash128_1) +} +fn main() {} diff --git a/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.rs b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.rs new file mode 100644 index 00000000000..efe035ebae0 --- /dev/null +++ b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.rs @@ -0,0 +1,27 @@ +// run-rustfix +// Issue #109429 +use std::collections::hash_map::DefaultHasher; +use std::collections::HashMap; +use std::hash::BuildHasher; +use std::hash::Hash; + +pub struct Hash128_1; + +impl BuildHasher for Hash128_1 { + type Hasher = DefaultHasher; + fn build_hasher(&self) -> DefaultHasher { DefaultHasher::default() } +} + +#[allow(unused)] +pub fn hashmap_copy<T, U>( + map: &HashMap<T, U, Hash128_1>, +) where T: Hash + Clone, U: Clone +{ + let mut copy: Vec<U> = map.clone().into_values().collect(); //~ ERROR +} + +pub fn make_map() -> HashMap<String, i64, Hash128_1> +{ + HashMap::with_hasher(Hash128_1) +} +fn main() {} diff --git a/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr new file mode 100644 index 00000000000..403daf8ff7c --- /dev/null +++ b/tests/ui/moves/suggest-clone-when-some-obligation-is-unmet.stderr @@ -0,0 +1,23 @@ +error[E0507]: cannot move out of a shared reference + --> $DIR/suggest-clone-when-some-obligation-is-unmet.rs:20:28 + | +LL | let mut copy: Vec<U> = map.clone().into_values().collect(); + | ^^^^^^^^^^^ ------------- value moved due to this method call + | | + | move occurs because value has type `HashMap<T, U, Hash128_1>`, which does not implement the `Copy` trait + | +note: `HashMap::<K, V, S>::into_values` takes ownership of the receiver `self`, which moves value + --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL +help: you could `clone` the value and consume it, if the `Hash128_1: Clone` trait bound could be satisfied + | +LL | let mut copy: Vec<U> = <HashMap<T, U, Hash128_1> as Clone>::clone(&map.clone()).into_values().collect(); + | ++++++++++++++++++++++++++++++++++++++++++++ + +help: consider annotating `Hash128_1` with `#[derive(Clone)]` + | +LL + #[derive(Clone)] +LL | pub struct Hash128_1; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/moves/suggest-clone.fixed b/tests/ui/moves/suggest-clone.fixed index 204bfdb10b0..0c4a94d77e4 100644 --- a/tests/ui/moves/suggest-clone.fixed +++ b/tests/ui/moves/suggest-clone.fixed @@ -7,5 +7,5 @@ impl Foo { } fn main() { let foo = &Foo; - foo.clone().foo(); //~ ERROR cannot move out + <Foo as Clone>::clone(&foo).foo(); //~ ERROR cannot move out } diff --git a/tests/ui/moves/suggest-clone.stderr b/tests/ui/moves/suggest-clone.stderr index e0b68f249ee..25e89a58955 100644 --- a/tests/ui/moves/suggest-clone.stderr +++ b/tests/ui/moves/suggest-clone.stderr @@ -13,8 +13,8 @@ LL | fn foo(self) {} | ^^^^ help: you can `clone` the value and consume it, but this might not be your desired behavior | -LL | foo.clone().foo(); - | ++++++++ +LL | <Foo as Clone>::clone(&foo).foo(); + | +++++++++++++++++++++++ + error: aborting due to 1 previous error diff --git a/tests/ui/nll/missing-universe-cause-issue-114907.stderr b/tests/ui/nll/missing-universe-cause-issue-114907.stderr index 988eee61027..a616d29c4fe 100644 --- a/tests/ui/nll/missing-universe-cause-issue-114907.stderr +++ b/tests/ui/nll/missing-universe-cause-issue-114907.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | accept(callback); | ^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> FnOnce<(&'a (),)>` - found trait `FnOnce<(&(),)>` + = note: expected trait `for<'a> FnOnce(&'a ())` + found trait `FnOnce(&())` note: this closure does not fulfill the lifetime requirements --> $DIR/missing-universe-cause-issue-114907.rs:32:20 | @@ -46,8 +46,8 @@ error[E0308]: mismatched types LL | accept(callback); | ^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected trait `for<'a> FnOnce<(&'a (),)>` - found trait `FnOnce<(&(),)>` + = note: expected trait `for<'a> FnOnce(&'a ())` + found trait `FnOnce(&())` note: this closure does not fulfill the lifetime requirements --> $DIR/missing-universe-cause-issue-114907.rs:32:20 | diff --git a/tests/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr b/tests/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr index b2448774ae9..e40d9858262 100644 --- a/tests/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr +++ b/tests/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr @@ -2,9 +2,8 @@ error: expected one of `,`, `:`, or `>`, found `=` --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:7:23 | LL | let v : Vec<(u32,_) = vec![]; - | - - ^ expected one of `,`, `:`, or `>` - | | | - | | maybe try to close unmatched angle bracket + | - ^ expected one of `,`, `:`, or `>` + | | | while parsing the type for `v` | help: you might have meant to end the type parameters here @@ -29,9 +28,8 @@ error: expected one of `,`, `:`, or `>`, found `=` --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:18:18 | LL | let v : Vec<'a = vec![]; - | - -- ^ expected one of `,`, `:`, or `>` - | | | - | | maybe try to close unmatched angle bracket + | - ^ expected one of `,`, `:`, or `>` + | | | while parsing the type for `v` | help: you might have meant to end the type parameters here diff --git a/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.rs b/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.rs index fe363a6887f..b9e3c5783eb 100644 --- a/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.rs +++ b/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.rs @@ -6,4 +6,8 @@ fn test(_: &for<'a> dyn Trait) {} fn test2(_: for<'a> impl Trait) {} //~^ ERROR `for<...>` expected after `impl`, not before +// Issue #118564 +type A2 = dyn<for<> dyn>; +//~^ ERROR expected identifier, found `>` + fn main() {} diff --git a/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.stderr b/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.stderr index 6fc1259b910..a012220e8c7 100644 --- a/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.stderr +++ b/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.stderr @@ -22,5 +22,11 @@ LL - fn test2(_: for<'a> impl Trait) {} LL + fn test2(_: impl for<'a> Trait) {} | -error: aborting due to 2 previous errors +error: expected identifier, found `>` + --> $DIR/recover-hrtb-before-dyn-impl-kw.rs:10:24 + | +LL | type A2 = dyn<for<> dyn>; + | ^ expected identifier + +error: aborting due to 3 previous errors diff --git a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr deleted file mode 100644 index ebbbccc5d58..00000000000 --- a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0004]: non-exhaustive patterns: type `usize` is non-empty - --> $DIR/pointer-sized-int.rs:59:11 - | -LL | match 7usize {} - | ^^^^^^ - | - = note: the matched value is of type `usize` -help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown - | -LL ~ match 7usize { -LL + _ => todo!(), -LL + } - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr index 2949081039a..416523213c0 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr +++ b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr @@ -1,12 +1,11 @@ error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered - --> $DIR/pointer-sized-int.rs:14:11 + --> $DIR/pointer-sized-int.rs:13:11 | LL | match 0usize { | ^^^^^^ pattern `usize::MAX..` not covered | = note: the matched value is of type `usize` = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ 0..=usize::MAX => {}, @@ -14,14 +13,13 @@ LL + usize::MAX.. => todo!() | error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered - --> $DIR/pointer-sized-int.rs:19:11 + --> $DIR/pointer-sized-int.rs:18:11 | LL | match 0isize { | ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered | = note: the matched value is of type `isize` = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ isize::MIN..=isize::MAX => {}, @@ -29,133 +27,124 @@ LL + ..isize::MIN | isize::MAX.. => todo!() | error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered - --> $DIR/pointer-sized-int.rs:24:8 + --> $DIR/pointer-sized-int.rs:23:8 | LL | m!(0usize, 0..=usize::MAX); | ^^^^^^ pattern `usize::MAX..` not covered | = note: the matched value is of type `usize` = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL | match $s { $($t)+ => {}, usize::MAX.. => todo!() } | +++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered - --> $DIR/pointer-sized-int.rs:26:8 + --> $DIR/pointer-sized-int.rs:25:8 | LL | m!(0usize, 0..5 | 5..=usize::MAX); | ^^^^^^ pattern `usize::MAX..` not covered | = note: the matched value is of type `usize` = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL | match $s { $($t)+ => {}, usize::MAX.. => todo!() } | +++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered - --> $DIR/pointer-sized-int.rs:28:8 + --> $DIR/pointer-sized-int.rs:27:8 | LL | m!(0usize, 0..usize::MAX | usize::MAX); | ^^^^^^ pattern `usize::MAX..` not covered | = note: the matched value is of type `usize` = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL | match $s { $($t)+ => {}, usize::MAX.. => todo!() } | +++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `(usize::MAX.., _)` not covered - --> $DIR/pointer-sized-int.rs:30:8 + --> $DIR/pointer-sized-int.rs:29:8 | LL | m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false)); | ^^^^^^^^^^^^^^ pattern `(usize::MAX.., _)` not covered | = note: the matched value is of type `(usize, bool)` = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL | match $s { $($t)+ => {}, (usize::MAX.., _) => todo!() } | ++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered - --> $DIR/pointer-sized-int.rs:39:8 + --> $DIR/pointer-sized-int.rs:38:8 | LL | m!(0isize, isize::MIN..=isize::MAX); | ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered | = note: the matched value is of type `isize` = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL | match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() } | ++++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered - --> $DIR/pointer-sized-int.rs:41:8 + --> $DIR/pointer-sized-int.rs:40:8 | LL | m!(0isize, isize::MIN..5 | 5..=isize::MAX); | ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered | = note: the matched value is of type `isize` = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL | match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() } | ++++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered - --> $DIR/pointer-sized-int.rs:43:8 + --> $DIR/pointer-sized-int.rs:42:8 | LL | m!(0isize, isize::MIN..=-1 | 0 | 1..=isize::MAX); | ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered | = note: the matched value is of type `isize` = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL | match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() } | ++++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered - --> $DIR/pointer-sized-int.rs:45:8 + --> $DIR/pointer-sized-int.rs:44:8 | LL | m!(0isize, isize::MIN..isize::MAX | isize::MAX); | ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered | = note: the matched value is of type `isize` = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL | match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() } | ++++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered - --> $DIR/pointer-sized-int.rs:48:9 + --> $DIR/pointer-sized-int.rs:47:9 | LL | (0isize, true), | ^^^^^^^^^^^^^^ patterns `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered | = note: the matched value is of type `(isize, bool)` = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL | match $s { $($t)+ => {}, (..isize::MIN, _) | (isize::MAX.., _) => todo!() } | ++++++++++++++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: type `usize` is non-empty - --> $DIR/pointer-sized-int.rs:59:11 + --> $DIR/pointer-sized-int.rs:58:11 | LL | match 7usize {} | ^^^^^^ diff --git a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs index cf137dca5aa..3778dede721 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs +++ b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs @@ -1,6 +1,5 @@ -// revisions: allow deny +// revisions: deny #![feature(exclusive_range_pattern)] -#![cfg_attr(allow, feature(precise_pointer_size_matching))] #![allow(overlapping_range_endpoints)] macro_rules! m { @@ -12,23 +11,23 @@ macro_rules! m { #[rustfmt::skip] fn main() { match 0usize { - //[deny]~^ ERROR non-exhaustive patterns + //~^ ERROR non-exhaustive patterns 0..=usize::MAX => {} } match 0isize { - //[deny]~^ ERROR non-exhaustive patterns + //~^ ERROR non-exhaustive patterns isize::MIN..=isize::MAX => {} } m!(0usize, 0..=usize::MAX); - //[deny]~^ ERROR non-exhaustive patterns + //~^ ERROR non-exhaustive patterns m!(0usize, 0..5 | 5..=usize::MAX); - //[deny]~^ ERROR non-exhaustive patterns + //~^ ERROR non-exhaustive patterns m!(0usize, 0..usize::MAX | usize::MAX); - //[deny]~^ ERROR non-exhaustive patterns + //~^ ERROR non-exhaustive patterns m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false)); - //[deny]~^ ERROR non-exhaustive patterns + //~^ ERROR non-exhaustive patterns m!(0usize, 0..); m!(0usize, 0..5 | 5..); @@ -37,18 +36,18 @@ fn main() { m!(0usize, 0..=usize::MAX | usize::MAX..); m!(0isize, isize::MIN..=isize::MAX); - //[deny]~^ ERROR non-exhaustive patterns + //~^ ERROR non-exhaustive patterns m!(0isize, isize::MIN..5 | 5..=isize::MAX); - //[deny]~^ ERROR non-exhaustive patterns + //~^ ERROR non-exhaustive patterns m!(0isize, isize::MIN..=-1 | 0 | 1..=isize::MAX); - //[deny]~^ ERROR non-exhaustive patterns + //~^ ERROR non-exhaustive patterns m!(0isize, isize::MIN..isize::MAX | isize::MAX); - //[deny]~^ ERROR non-exhaustive patterns + //~^ ERROR non-exhaustive patterns m!( (0isize, true), (isize::MIN..5, true) | (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false) ); - //[deny]~^^^ ERROR non-exhaustive patterns + //~^^^ ERROR non-exhaustive patterns m!(0isize, ..0 | 0..); m!(0isize, ..5 | 5..); diff --git a/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr b/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr index a7f93648ed3..36743aa8102 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr +++ b/tests/ui/pattern/usefulness/integer-ranges/precise_pointer_matching-message.stderr @@ -6,7 +6,6 @@ LL | match 0usize { | = note: the matched value is of type `usize` = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ 0..=usize::MAX => {}, @@ -21,7 +20,6 @@ LL | match 0isize { | = note: the matched value is of type `isize` = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ isize::MIN..=isize::MAX => {}, diff --git a/tests/ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.stderr b/tests/ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.stderr index 556efcda516..c31411018bc 100644 --- a/tests/ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.stderr +++ b/tests/ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.stderr @@ -6,7 +6,6 @@ LL | match 0 { | = note: the matched value is of type `usize` = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ 1..=usize::MAX => (), @@ -21,7 +20,6 @@ LL | match (0usize, 0usize) { | = note: the matched value is of type `(usize, usize)` = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ (1..=usize::MAX, 1..=usize::MAX) => (), @@ -36,7 +34,6 @@ LL | match (0isize, 0usize) { | = note: the matched value is of type `(isize, usize)` = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ (isize::MIN..=isize::MAX, 1..=usize::MAX) => (), @@ -74,7 +71,6 @@ note: `Option<usize>` defined here = note: not covered = note: the matched value is of type `Option<usize>` = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ None => (), @@ -98,7 +94,6 @@ note: `Option<Option<Option<usize>>>` defined here = note: not covered = note: the matched value is of type `Option<Option<Option<usize>>>` = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ None => (), @@ -118,7 +113,6 @@ LL | struct A<T> { | ^ = note: the matched value is of type `A<usize>` = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ A { a: 1..=usize::MAX } => (), @@ -138,7 +132,6 @@ LL | struct B<T, U>(T, U); | ^ = note: the matched value is of type `B<isize, usize>` = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ B(isize::MIN..=isize::MAX, 1..=usize::MAX) => (), @@ -158,7 +151,6 @@ LL | struct B<T, U>(T, U); | ^ = note: the matched value is of type `B<isize, usize>` = note: `usize` does not have a fixed maximum value, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ B(_, 1..=usize::MAX) => (), diff --git a/tests/ui/privacy/privacy2.stderr b/tests/ui/privacy/privacy2.stderr index e7135d3fd8a..46bb9823dbf 100644 --- a/tests/ui/privacy/privacy2.stderr +++ b/tests/ui/privacy/privacy2.stderr @@ -19,7 +19,7 @@ note: ...and refers to the function `foo` which is defined here --> $DIR/privacy2.rs:16:1 | LL | pub fn foo() {} - | ^^^^^^^^^^^^ consider importing it directly + | ^^^^^^^^^^^^ you could import this directly error: requires `sized` lang_item diff --git a/tests/ui/proc-macro/disappearing-resolution.stderr b/tests/ui/proc-macro/disappearing-resolution.stderr index 5b969549a11..e6d0868687e 100644 --- a/tests/ui/proc-macro/disappearing-resolution.stderr +++ b/tests/ui/proc-macro/disappearing-resolution.stderr @@ -19,7 +19,11 @@ note: ...and refers to the derive macro `Empty` which is defined here --> $DIR/auxiliary/test-macros.rs:25:1 | LL | pub fn empty_derive(_: TokenStream) -> TokenStream { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ consider importing it directly + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ you could import this directly +help: import `Empty` directly + | +LL | use test_macros::Empty; + | ~~~~~~~~~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/resolve/issue-117920.rs b/tests/ui/resolve/issue-117920.rs new file mode 100644 index 00000000000..928f194c59c --- /dev/null +++ b/tests/ui/resolve/issue-117920.rs @@ -0,0 +1,11 @@ +#![crate_type = "lib"] + +use super::A; //~ ERROR failed to resolve + +mod b { + pub trait A {} + pub trait B {} +} + +/// [`A`] +pub use b::*; diff --git a/tests/ui/resolve/issue-117920.stderr b/tests/ui/resolve/issue-117920.stderr new file mode 100644 index 00000000000..c4528d467e9 --- /dev/null +++ b/tests/ui/resolve/issue-117920.stderr @@ -0,0 +1,9 @@ +error[E0433]: failed to resolve: there are too many leading `super` keywords + --> $DIR/issue-117920.rs:3:5 + | +LL | use super::A; + | ^^^^^ there are too many leading `super` keywords + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/resolve/issue-118295.rs b/tests/ui/resolve/issue-118295.rs new file mode 100644 index 00000000000..b97681d9563 --- /dev/null +++ b/tests/ui/resolve/issue-118295.rs @@ -0,0 +1,5 @@ +macro_rules! {} +//~^ ERROR cannot find macro `macro_rules` in this scope +//~| NOTE maybe you have forgotten to define a name for this `macro_rules!` + +fn main() {} diff --git a/tests/ui/resolve/issue-118295.stderr b/tests/ui/resolve/issue-118295.stderr new file mode 100644 index 00000000000..d60d7d9185d --- /dev/null +++ b/tests/ui/resolve/issue-118295.stderr @@ -0,0 +1,14 @@ +error: cannot find macro `macro_rules` in this scope + --> $DIR/issue-118295.rs:1:1 + | +LL | macro_rules! {} + | ^^^^^^^^^^^ + | +note: maybe you have forgotten to define a name for this `macro_rules!` + --> $DIR/issue-118295.rs:1:1 + | +LL | macro_rules! {} + | ^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/rfcs/rfc-1623-static/rfc1623-2.stderr b/tests/ui/rfcs/rfc-1623-static/rfc1623-2.stderr index 5f8c5dbe619..52c700c326e 100644 --- a/tests/ui/rfcs/rfc-1623-static/rfc1623-2.stderr +++ b/tests/ui/rfcs/rfc-1623-static/rfc1623-2.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | f: &id, | ^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> Fn<(&'a Foo<'b>,)>` - found trait `Fn<(&Foo<'_>,)>` + = note: expected trait `for<'a, 'b> Fn(&'a Foo<'b>)` + found trait `Fn(&Foo<'_>)` error[E0308]: mismatched types --> $DIR/rfc1623-2.rs:28:8 @@ -13,8 +13,8 @@ error[E0308]: mismatched types LL | f: &id, | ^^^ one type is more general than the other | - = note: expected trait `for<'a, 'b> Fn<(&'a Foo<'b>,)>` - found trait `Fn<(&Foo<'_>,)>` + = note: expected trait `for<'a, 'b> Fn(&'a Foo<'b>)` + found trait `Fn(&Foo<'_>)` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: implementation of `FnOnce` is not general enough diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/effect-param-infer.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/effect-param-infer.rs new file mode 100644 index 00000000000..e216f687913 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/effect-param-infer.rs @@ -0,0 +1,15 @@ +// Ensure that we don't get a mismatch error when inserting the host param +// at the end of generic args when the generics have defaulted params. +// +// check-pass + +#![feature(const_trait_impl, effects)] + +#[const_trait] +pub trait Foo<Rhs: ?Sized = Self> { + /* stuff */ +} + +impl const Foo for () {} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs index e7ba0505d9b..17f203e1565 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs @@ -3,15 +3,16 @@ // gate-test-effects // ^ effects doesn't have a gate so we will trick tidy into thinking this is a gate test -#![feature(const_trait_impl, effects, rustc_attrs)] +#![feature(const_trait_impl, effects, core_intrinsics, const_eval_select)] // ensure we are passing in the correct host effect in always const contexts. -pub const fn hmm<T, #[rustc_host] const host: bool = true>() -> usize { - if host { - 1 - } else { - 0 +pub const fn hmm<T>() -> usize { + // FIXME(const_trait_impl): maybe we should have a way to refer to the (hidden) effect param + fn one() -> usize { 1 } + const fn zero() -> usize { 0 } + unsafe { + std::intrinsics::const_eval_select((), zero, one) } } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs index ecf45c97dcd..2c6fd83484f 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs @@ -21,8 +21,7 @@ trait Add<Rhs = Self> { fn add(self, rhs: Rhs) -> Self::Output; } -// FIXME(effects) we shouldn't need to have to specify `Rhs`. -impl const Add<i32> for i32 { +impl const Add for i32 { type Output = i32; fn add(self, rhs: i32) -> i32 { loop {} @@ -353,8 +352,7 @@ where } } -// FIXME(effects): again, this should not error without Rhs specified -impl PartialEq<str> for str { +impl PartialEq for str { fn eq(&self, other: &str) -> bool { loop {} } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr index 461133e6c3e..3c1e6dda85c 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr @@ -1,5 +1,5 @@ error[E0493]: destructor of `Self` cannot be evaluated at compile-time - --> $DIR/minicore.rs:503:9 + --> $DIR/minicore.rs:501:9 | LL | *self = source.clone() | ^^^^^ @@ -8,7 +8,7 @@ LL | *self = source.clone() | value is dropped here error[E0493]: destructor of `T` cannot be evaluated at compile-time - --> $DIR/minicore.rs:513:35 + --> $DIR/minicore.rs:511:35 | LL | const fn drop<T: ~const Destruct>(_: T) {} | ^ - value is dropped here diff --git a/tests/ui/suggestions/as-ref-2.stderr b/tests/ui/suggestions/as-ref-2.stderr index 5432fcb1a58..30928577537 100644 --- a/tests/ui/suggestions/as-ref-2.stderr +++ b/tests/ui/suggestions/as-ref-2.stderr @@ -12,6 +12,15 @@ LL | let _y = foo; | note: `Option::<T>::map` takes ownership of the receiver `self`, which moves `foo` --> $SRC_DIR/core/src/option.rs:LL:COL +help: you could `clone` the value and consume it, if the `Struct: Clone` trait bound could be satisfied + | +LL | let _x: Option<Struct> = foo.clone().map(|s| bar(&s)); + | ++++++++ +help: consider annotating `Struct` with `#[derive(Clone)]` + | +LL + #[derive(Clone)] +LL | struct Struct; + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/option-content-move.fixed b/tests/ui/suggestions/option-content-move.fixed new file mode 100644 index 00000000000..5e79cf71d82 --- /dev/null +++ b/tests/ui/suggestions/option-content-move.fixed @@ -0,0 +1,38 @@ +// run-rustfix +pub struct LipogramCorpora { + selections: Vec<(char, Option<String>)>, +} + +impl LipogramCorpora { + pub fn validate_all(&mut self) -> Result<(), char> { + for selection in &self.selections { + if selection.1.is_some() { + if <Option<String> as Clone>::clone(&selection.1).unwrap().contains(selection.0) { + //~^ ERROR cannot move out of `selection.1` + return Err(selection.0); + } + } + } + Ok(()) + } +} + +pub struct LipogramCorpora2 { + selections: Vec<(char, Result<String, String>)>, +} + +impl LipogramCorpora2 { + pub fn validate_all(&mut self) -> Result<(), char> { + for selection in &self.selections { + if selection.1.is_ok() { + if <Result<String, String> as Clone>::clone(&selection.1).unwrap().contains(selection.0) { + //~^ ERROR cannot move out of `selection.1` + return Err(selection.0); + } + } + } + Ok(()) + } +} + +fn main() {} diff --git a/tests/ui/suggestions/option-content-move.rs b/tests/ui/suggestions/option-content-move.rs index 46c895b95f5..58efbe71f27 100644 --- a/tests/ui/suggestions/option-content-move.rs +++ b/tests/ui/suggestions/option-content-move.rs @@ -1,3 +1,4 @@ +// run-rustfix pub struct LipogramCorpora { selections: Vec<(char, Option<String>)>, } diff --git a/tests/ui/suggestions/option-content-move.stderr b/tests/ui/suggestions/option-content-move.stderr index 5060606d842..e5de150275d 100644 --- a/tests/ui/suggestions/option-content-move.stderr +++ b/tests/ui/suggestions/option-content-move.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of `selection.1` which is behind a shared reference - --> $DIR/option-content-move.rs:9:20 + --> $DIR/option-content-move.rs:10:20 | LL | if selection.1.unwrap().contains(selection.0) { | ^^^^^^^^^^^ -------- `selection.1` moved due to this method call @@ -11,11 +11,11 @@ note: `Option::<T>::unwrap` takes ownership of the receiver `self`, which moves --> $SRC_DIR/core/src/option.rs:LL:COL help: you can `clone` the value and consume it, but this might not be your desired behavior | -LL | if selection.1.clone().unwrap().contains(selection.0) { - | ++++++++ +LL | if <Option<String> as Clone>::clone(&selection.1).unwrap().contains(selection.0) { + | ++++++++++++++++++++++++++++++++++ + error[E0507]: cannot move out of `selection.1` which is behind a shared reference - --> $DIR/option-content-move.rs:27:20 + --> $DIR/option-content-move.rs:28:20 | LL | if selection.1.unwrap().contains(selection.0) { | ^^^^^^^^^^^ -------- `selection.1` moved due to this method call @@ -27,8 +27,8 @@ note: `Result::<T, E>::unwrap` takes ownership of the receiver `self`, which mov --> $SRC_DIR/core/src/result.rs:LL:COL help: you can `clone` the value and consume it, but this might not be your desired behavior | -LL | if selection.1.clone().unwrap().contains(selection.0) { - | ++++++++ +LL | if <Result<String, String> as Clone>::clone(&selection.1).unwrap().contains(selection.0) { + | ++++++++++++++++++++++++++++++++++++++++++ + error: aborting due to 2 previous errors diff --git a/tests/ui/traits/issue-85735.stderr b/tests/ui/traits/issue-85735.stderr index 1aba4183348..0980c5c33bd 100644 --- a/tests/ui/traits/issue-85735.stderr +++ b/tests/ui/traits/issue-85735.stderr @@ -1,10 +1,10 @@ -error[E0283]: type annotations needed: cannot satisfy `T: FnMut<(&'a (),)>` +error[E0283]: type annotations needed: cannot satisfy `T: FnMut(&'a ())` --> $DIR/issue-85735.rs:7:8 | LL | T: FnMut(&'a ()), | ^^^^^^^^^^^^^ | -note: multiple `impl`s or `where` clauses satisfying `T: FnMut<(&'a (),)>` found +note: multiple `impl`s or `where` clauses satisfying `T: FnMut(&'a ())` found --> $DIR/issue-85735.rs:7:8 | LL | T: FnMut(&'a ()), diff --git a/tests/ui/traits/question-mark-result-err-mismatch.rs b/tests/ui/traits/question-mark-result-err-mismatch.rs new file mode 100644 index 00000000000..0ca18b5b0dd --- /dev/null +++ b/tests/ui/traits/question-mark-result-err-mismatch.rs @@ -0,0 +1,59 @@ +fn foo() -> Result<String, String> { //~ NOTE expected `String` because of this + let test = String::from("one,two"); + let x = test + .split_whitespace() + .next() + .ok_or_else(|| { + "Couldn't split the test string" + }); + let one = x + .map(|s| ()) + .map_err(|e| { //~ NOTE this can't be annotated with `?` because it has type `Result<_, ()>` + e; //~ HELP remove this semicolon + }) + .map(|()| "")?; //~ ERROR `?` couldn't convert the error to `String` + //~^ NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE the trait `From<()>` is not implemented for `String` + //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + //~| NOTE required for `Result<String, String>` to implement `FromResidual<Result<Infallible, ()>>` + Ok(one.to_string()) +} + +fn bar() -> Result<(), String> { //~ NOTE expected `String` because of this + let x = foo(); //~ NOTE this has type `Result<_, String>` + let one = x + .map(|s| ()) + .map_err(|_| ())?; //~ ERROR `?` couldn't convert the error to `String` + //~^ NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE this can't be annotated with `?` because it has type `Result<_, ()>` + //~| NOTE the trait `From<()>` is not implemented for `String` + //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + //~| NOTE required for `Result<(), String>` to implement `FromResidual<Result<Infallible, ()>>` + //~| HELP the following other types implement trait `From<T>`: + Ok(one) +} + +fn baz() -> Result<String, String> { //~ NOTE expected `String` because of this + let test = String::from("one,two"); + let one = test + .split_whitespace() + .next() + .ok_or_else(|| { //~ NOTE this can't be annotated with `?` because it has type `Result<_, ()>` + "Couldn't split the test string"; //~ HELP remove this semicolon + })?; + //~^ ERROR `?` couldn't convert the error to `String` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE in this expansion of desugaring of operator `?` + //~| NOTE the trait `From<()>` is not implemented for `String` + //~| NOTE the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + //~| NOTE required for `Result<String, String>` to implement `FromResidual<Result<Infallible, ()>>` + Ok(one.to_string()) +} + +fn main() {} diff --git a/tests/ui/traits/question-mark-result-err-mismatch.stderr b/tests/ui/traits/question-mark-result-err-mismatch.stderr new file mode 100644 index 00000000000..3059e0beca3 --- /dev/null +++ b/tests/ui/traits/question-mark-result-err-mismatch.stderr @@ -0,0 +1,62 @@ +error[E0277]: `?` couldn't convert the error to `String` + --> $DIR/question-mark-result-err-mismatch.rs:14:22 + | +LL | fn foo() -> Result<String, String> { + | ---------------------- expected `String` because of this +... +LL | .map_err(|e| { + | __________- +LL | | e; + | | - help: remove this semicolon +LL | | }) + | |__________- this can't be annotated with `?` because it has type `Result<_, ()>` +LL | .map(|()| "")?; + | ^ the trait `From<()>` is not implemented for `String` + | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + = note: required for `Result<String, String>` to implement `FromResidual<Result<Infallible, ()>>` + +error[E0277]: `?` couldn't convert the error to `String` + --> $DIR/question-mark-result-err-mismatch.rs:28:25 + | +LL | fn bar() -> Result<(), String> { + | ------------------ expected `String` because of this +LL | let x = foo(); + | ----- this has type `Result<_, String>` +... +LL | .map_err(|_| ())?; + | ---------------^ the trait `From<()>` is not implemented for `String` + | | + | this can't be annotated with `?` because it has type `Result<_, ()>` + | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + = help: the following other types implement trait `From<T>`: + <String as From<char>> + <String as From<Box<str>>> + <String as From<Cow<'a, str>>> + <String as From<&str>> + <String as From<&mut str>> + <String as From<&String>> + = note: required for `Result<(), String>` to implement `FromResidual<Result<Infallible, ()>>` + +error[E0277]: `?` couldn't convert the error to `String` + --> $DIR/question-mark-result-err-mismatch.rs:48:11 + | +LL | fn baz() -> Result<String, String> { + | ---------------------- expected `String` because of this +... +LL | .ok_or_else(|| { + | __________- +LL | | "Couldn't split the test string"; + | | - help: remove this semicolon +LL | | })?; + | | -^ the trait `From<()>` is not implemented for `String` + | |__________| + | this can't be annotated with `?` because it has type `Result<_, ()>` + | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + = note: required for `Result<String, String>` to implement `FromResidual<Result<Infallible, ()>>` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/try-block/try-block-bad-type.stderr b/tests/ui/try-block/try-block-bad-type.stderr index b41bf86d3d9..d58a011ff55 100644 --- a/tests/ui/try-block/try-block-bad-type.stderr +++ b/tests/ui/try-block/try-block-bad-type.stderr @@ -2,7 +2,9 @@ error[E0277]: `?` couldn't convert the error to `TryFromSliceError` --> $DIR/try-block-bad-type.rs:7:16 | LL | Err("")?; - | ^ the trait `From<&str>` is not implemented for `TryFromSliceError` + | -------^ the trait `From<&str>` is not implemented for `TryFromSliceError` + | | + | this can't be annotated with `?` because it has type `Result<_, &str>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the trait `From<Infallible>` is implemented for `TryFromSliceError` diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index d8b9431becc..97fbbdbf8f8 100644 --- a/tests/ui/try-trait/bad-interconversion.stderr +++ b/tests/ui/try-trait/bad-interconversion.stderr @@ -4,7 +4,9 @@ error[E0277]: `?` couldn't convert the error to `u8` LL | fn result_to_result() -> Result<u64, u8> { | --------------- expected `u8` because of this LL | Ok(Err(123_i32)?) - | ^ the trait `From<i32>` is not implemented for `u8` + | ------------^ the trait `From<i32>` is not implemented for `u8` + | | + | this can't be annotated with `?` because it has type `Result<_, i32>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From<T>`: diff --git a/tests/ui/try-trait/issue-32709.stderr b/tests/ui/try-trait/issue-32709.stderr index 46798f5dcfd..b155b3ff663 100644 --- a/tests/ui/try-trait/issue-32709.stderr +++ b/tests/ui/try-trait/issue-32709.stderr @@ -4,7 +4,9 @@ error[E0277]: `?` couldn't convert the error to `()` LL | fn a() -> Result<i32, ()> { | --------------- expected `()` because of this LL | Err(5)?; - | ^ the trait `From<{integer}>` is not implemented for `()` + | ------^ the trait `From<{integer}>` is not implemented for `()` + | | + | this can't be annotated with `?` because it has type `Result<_, {integer}>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following other types implement trait `From<T>`: diff --git a/triagebot.toml b/triagebot.toml index 24926690cfe..775d9714c60 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -431,7 +431,7 @@ changelog-branch = "master" cc = ["@bjorn3"] [mentions."compiler/rustc_codegen_gcc"] -cc = ["@antoyo"] +cc = ["@antoyo", "@GuillaumeGomez"] [mentions."compiler/rustc_const_eval/src/interpret"] message = "Some changes occurred to the CTFE / Miri engine" |
