diff options
| author | bors <bors@rust-lang.org> | 2023-11-30 15:21:09 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-11-30 15:21:09 +0000 |
| commit | d368c4043c26800bf1d45103e482d3e9d3bf6010 (patch) | |
| tree | 9500da2a806a8fa2c229e97350fe90c02bcd5f1d | |
| parent | 33e8232b82efb5f57760fcf08045cb36b93ed8e4 (diff) | |
| parent | cd124409335f8830becb7f7ec7de1c6aa8a504e3 (diff) | |
| download | rust-d368c4043c26800bf1d45103e482d3e9d3bf6010.tar.gz rust-d368c4043c26800bf1d45103e482d3e9d3bf6010.zip | |
Auto merge of #3197 - RalfJung:rustup, r=RalfJung
Rustup also move some fail tests into suitable subdirectories
434 files changed, 5730 insertions, 2627 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f659a1c306..a0d9eb8c452 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,7 +56,7 @@ jobs: - name: mingw-check-tidy os: ubuntu-20.04-4core-16gb env: {} - - name: x86_64-gnu-llvm-15 + - name: x86_64-gnu-llvm-16 env: ENABLE_GCC_CODEGEN: "1" os: ubuntu-20.04-16core-64gb @@ -302,10 +302,6 @@ jobs: env: RUST_BACKTRACE: 1 os: ubuntu-20.04-8core-32gb - - name: x86_64-gnu-llvm-15 - env: - RUST_BACKTRACE: 1 - os: ubuntu-20.04-8core-32gb - name: x86_64-gnu-nopt os: ubuntu-20.04-4core-16gb env: {} diff --git a/.mailmap b/.mailmap index b6f4112392d..d70a9f2aed6 100644 --- a/.mailmap +++ b/.mailmap @@ -575,7 +575,8 @@ Val Markovic <val@markovic.io> Valerii Lashmanov <vflashm@gmail.com> Vitali Haravy <HumaneProgrammer@gmail.com> Vitali Haravy <humaneprogrammer@gmail.com> Vitaly Shukela <vi0oss@gmail.com> -Waffle Maybe <waffle.lapkin@gmail.com> +Waffle Lapkin <waffle.lapkin@gmail.com> +Waffle Lapkin <waffle.lapkin@tasking.com> Wesley Wiser <wwiser@gmail.com> <wesleywiser@microsoft.com> whitequark <whitequark@whitequark.org> William Ting <io@williamting.com> <william.h.ting@gmail.com> diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 10776f31c07..cba9121aa5a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -645,6 +645,7 @@ impl Pat { // These patterns do not contain subpatterns, skip. PatKind::Wild | PatKind::Rest + | PatKind::Never | PatKind::Lit(_) | PatKind::Range(..) | PatKind::Ident(..) @@ -795,6 +796,9 @@ pub enum PatKind { /// only one rest pattern may occur in the pattern sequences. Rest, + // A never pattern `!` + Never, + /// Parentheses in patterns used for grouping (i.e., `(PAT)`). Paren(P<Pat>), @@ -817,7 +821,7 @@ pub enum BorrowKind { Raw, } -#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)] +#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)] pub enum BinOpKind { /// The `+` operator (addition) Add, @@ -858,9 +862,9 @@ pub enum BinOpKind { } impl BinOpKind { - pub fn to_string(&self) -> &'static str { + pub fn as_str(&self) -> &'static str { use BinOpKind::*; - match *self { + match self { Add => "+", Sub => "-", Mul => "*", @@ -881,19 +885,25 @@ impl BinOpKind { Gt => ">", } } - pub fn lazy(&self) -> bool { + + pub fn is_lazy(&self) -> bool { matches!(self, BinOpKind::And | BinOpKind::Or) } pub fn is_comparison(&self) -> bool { use BinOpKind::*; - // Note for developers: please keep this as is; + // Note for developers: please keep this match exhaustive; // we want compilation to fail if another variant is added. match *self { Eq | Lt | Le | Ne | Gt | Ge => true, And | Or | Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Shl | Shr => false, } } + + /// Returns `true` if the binary operator takes its arguments by value. + pub fn is_by_value(self) -> bool { + !self.is_comparison() + } } pub type BinOp = Spanned<BinOpKind>; @@ -901,7 +911,7 @@ pub type BinOp = Spanned<BinOpKind>; /// Unary operator. /// /// Note that `&data` is not an operator, it's an `AddrOf` expression. -#[derive(Clone, Encodable, Decodable, Debug, Copy)] +#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)] pub enum UnOp { /// The `*` operator for dereferencing Deref, @@ -912,13 +922,18 @@ pub enum UnOp { } impl UnOp { - pub fn to_string(op: UnOp) -> &'static str { - match op { + pub fn as_str(&self) -> &'static str { + match self { UnOp::Deref => "*", UnOp::Not => "!", UnOp::Neg => "-", } } + + /// Returns `true` if the unary operator takes its argument by value. + pub fn is_by_value(self) -> bool { + matches!(self, Self::Neg | Self::Not) + } } /// A statement diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 541b9872922..8ce86bf9ecf 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1249,7 +1249,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) { let Pat { id, kind, span, tokens } = pat.deref_mut(); vis.visit_id(id); match kind { - PatKind::Wild | PatKind::Rest => {} + PatKind::Wild | PatKind::Rest | PatKind::Never => {} PatKind::Ident(_binding_mode, ident, sub) => { vis.visit_ident(ident); visit_opt(sub, |sub| vis.visit_pat(sub)); diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 3189fcf7ff9..a7c6f8c5d8c 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -756,6 +756,11 @@ impl Token { ) } + /// Returns `true` if the token is the integer literal. + pub fn is_integer_lit(&self) -> bool { + matches!(self.kind, Literal(Lit { kind: LitKind::Integer, .. })) + } + /// Returns `true` if the token is a non-raw identifier for which `pred` holds. pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool { match self.ident() { diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 1caa39e2dd9..9dbadcb49d3 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -559,7 +559,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) { walk_list!(visitor, visit_expr, lower_bound); walk_list!(visitor, visit_expr, upper_bound); } - PatKind::Wild | PatKind::Rest => {} + PatKind::Wild | PatKind::Rest | PatKind::Never => {} PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => { walk_list!(visitor, visit_pat, elems); } diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index a1e62699680..951bf41d9d7 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -228,6 +228,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { parent_def_id.def_id, node_id, DefPathData::AnonConst, + DefKind::AnonConst, *op_sp, ); let anon_const = AnonConst { id: node_id, value: P(expr) }; diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 6f2f9787e77..be5671f1bf7 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -12,7 +12,7 @@ use rustc_ast::ptr::P as AstP; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; -use rustc_hir::def::Res; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::definitions::DefPathData; use rustc_session::errors::report_lit_error; use rustc_span::source_map::{respan, Spanned}; @@ -72,7 +72,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), ExprKind::ConstBlock(c) => { - let c = self.with_new_scopes(|this| hir::ConstBlock { + let c = self.with_new_scopes(c.value.span, |this| hir::ConstBlock { def_id: this.local_def_id(c.id), hir_id: this.lower_node_id(c.id), body: this.lower_const_body(c.value.span, Some(&c.value)), @@ -189,7 +189,7 @@ impl<'hir> LoweringContext<'_, 'hir> { None, e.span, hir::CoroutineSource::Block, - |this| this.with_new_scopes(|this| this.lower_block_expr(block)), + |this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)), ), ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr), ExprKind::Closure(box Closure { @@ -323,7 +323,7 @@ impl<'hir> LoweringContext<'_, 'hir> { None, e.span, hir::CoroutineSource::Block, - |this| this.with_new_scopes(|this| this.lower_block_expr(block)), + |this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)), ), ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()), ExprKind::Err => hir::ExprKind::Err( @@ -350,30 +350,8 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn lower_binop(&mut self, b: BinOp) -> hir::BinOp { - Spanned { - node: match b.node { - BinOpKind::Add => hir::BinOpKind::Add, - BinOpKind::Sub => hir::BinOpKind::Sub, - BinOpKind::Mul => hir::BinOpKind::Mul, - BinOpKind::Div => hir::BinOpKind::Div, - BinOpKind::Rem => hir::BinOpKind::Rem, - BinOpKind::And => hir::BinOpKind::And, - BinOpKind::Or => hir::BinOpKind::Or, - BinOpKind::BitXor => hir::BinOpKind::BitXor, - BinOpKind::BitAnd => hir::BinOpKind::BitAnd, - BinOpKind::BitOr => hir::BinOpKind::BitOr, - BinOpKind::Shl => hir::BinOpKind::Shl, - BinOpKind::Shr => hir::BinOpKind::Shr, - BinOpKind::Eq => hir::BinOpKind::Eq, - BinOpKind::Lt => hir::BinOpKind::Lt, - BinOpKind::Le => hir::BinOpKind::Le, - BinOpKind::Ne => hir::BinOpKind::Ne, - BinOpKind::Ge => hir::BinOpKind::Ge, - BinOpKind::Gt => hir::BinOpKind::Gt, - }, - span: self.lower_span(b.span), - } + fn lower_binop(&mut self, b: BinOp) -> BinOp { + Spanned { node: b.node, span: self.lower_span(b.span) } } fn lower_legacy_const_generics( @@ -395,7 +373,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let node_id = self.next_node_id(); // Add a definition for the in-band const def. - self.create_def(parent_def_id.def_id, node_id, DefPathData::AnonConst, f.span); + self.create_def( + parent_def_id.def_id, + node_id, + DefPathData::AnonConst, + DefKind::AnonConst, + f.span, + ); let anon_const = AnonConst { id: node_id, value: arg }; generic_args.push(AngleBracketedArg::Arg(GenericArg::Const(anon_const))); @@ -524,7 +508,7 @@ impl<'hir> LoweringContext<'_, 'hir> { this.mark_span_with_reason( DesugaringKind::TryBlock, expr.span, - this.allow_try_trait.clone(), + Some(this.allow_try_trait.clone()), ), expr, ) @@ -532,7 +516,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let try_span = this.mark_span_with_reason( DesugaringKind::TryBlock, this.tcx.sess.source_map().end_point(body.span), - this.allow_try_trait.clone(), + Some(this.allow_try_trait.clone()), ); (try_span, this.expr_unit(try_span)) @@ -612,8 +596,11 @@ impl<'hir> LoweringContext<'_, 'hir> { let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span))); // Resume argument type: `ResumeTy` - let unstable_span = - self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone()); + let unstable_span = self.mark_span_with_reason( + DesugaringKind::Async, + span, + Some(self.allow_gen_future.clone()), + ); let resume_ty = hir::QPath::LangItem(hir::LangItem::ResumeTy, unstable_span); let input_ty = hir::Ty { hir_id: self.next_id(), @@ -735,7 +722,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let unstable_span = self.mark_span_with_reason( DesugaringKind::Async, span, - self.allow_gen_future.clone(), + Some(self.allow_gen_future.clone()), ); self.lower_attrs( inner_hir_id, @@ -772,17 +759,17 @@ impl<'hir> LoweringContext<'_, 'hir> { match self.coroutine_kind { Some(hir::CoroutineKind::Async(_)) => {} Some(hir::CoroutineKind::Coroutine) | Some(hir::CoroutineKind::Gen(_)) | None => { - self.tcx.sess.emit_err(AwaitOnlyInAsyncFnAndBlocks { + return hir::ExprKind::Err(self.tcx.sess.emit_err(AwaitOnlyInAsyncFnAndBlocks { await_kw_span, item_span: self.current_item, - }); + })); } } let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, None); let gen_future_span = self.mark_span_with_reason( DesugaringKind::Await, full_span, - self.allow_gen_future.clone(), + Some(self.allow_gen_future.clone()), ); let expr = self.lower_expr_mut(expr); let expr_hir_id = expr.hir_id; @@ -935,9 +922,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::ExprKind<'hir> { let (binder_clause, generic_params) = self.lower_closure_binder(binder); - let (body_id, coroutine_option) = self.with_new_scopes(move |this| { - let prev = this.current_item; - this.current_item = Some(fn_decl_span); + let (body_id, coroutine_option) = self.with_new_scopes(fn_decl_span, move |this| { let mut coroutine_kind = None; let body_id = this.lower_fn_body(decl, |this| { let e = this.lower_expr_mut(body); @@ -946,7 +931,6 @@ impl<'hir> LoweringContext<'_, 'hir> { }); let coroutine_option = this.coroutine_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability); - this.current_item = prev; (body_id, coroutine_option) }); @@ -1032,7 +1016,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let outer_decl = FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) }; - let body = self.with_new_scopes(|this| { + let body = self.with_new_scopes(fn_decl_span, |this| { // FIXME(cramertj): allow `async` non-`move` closures with arguments. if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() { this.tcx.sess.emit_err(AsyncNonMoveClosureNotSupported { fn_decl_span }); @@ -1054,7 +1038,7 @@ impl<'hir> LoweringContext<'_, 'hir> { async_ret_ty, body.span, hir::CoroutineSource::Closure, - |this| this.with_new_scopes(|this| this.lower_expr_mut(body)), + |this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)), ); let hir_id = this.lower_node_id(inner_closure_id); this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id); @@ -1494,7 +1478,9 @@ impl<'hir> LoweringContext<'_, 'hir> { match self.coroutine_kind { Some(hir::CoroutineKind::Gen(_)) => {} Some(hir::CoroutineKind::Async(_)) => { - self.tcx.sess.emit_err(AsyncCoroutinesNotSupported { span }); + return hir::ExprKind::Err( + self.tcx.sess.emit_err(AsyncCoroutinesNotSupported { span }), + ); } Some(hir::CoroutineKind::Coroutine) | None => { if !self.tcx.features().coroutines { @@ -1640,13 +1626,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let unstable_span = self.mark_span_with_reason( DesugaringKind::QuestionMark, span, - self.allow_try_trait.clone(), + Some(self.allow_try_trait.clone()), ); let try_span = self.tcx.sess.source_map().end_point(span); let try_span = self.mark_span_with_reason( DesugaringKind::QuestionMark, try_span, - self.allow_try_trait.clone(), + Some(self.allow_try_trait.clone()), ); // `Try::branch(<expr>)` @@ -1739,7 +1725,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let unstable_span = self.mark_span_with_reason( DesugaringKind::YeetExpr, span, - self.allow_try_trait.clone(), + Some(self.allow_try_trait.clone()), ); let from_yeet_expr = self.wrap_in_try_constructor( diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index e91b78720a8..1741611fb11 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::TyCtxt; use rustc_span::{Span, DUMMY_SP}; /// A visitor that walks over the HIR and collects `Node`s into a HIR map. -pub(super) struct NodeCollector<'a, 'hir> { +struct NodeCollector<'a, 'hir> { tcx: TyCtxt<'hir>, bodies: &'a SortedMap<ItemLocalId, &'hir Body<'hir>>, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index c4c08096b8b..c47c5fc8fcc 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -7,7 +7,6 @@ use hir::definitions::DefPathData; use rustc_ast::ptr::P; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; -use rustc_data_structures::sorted_map::SortedMap; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -55,42 +54,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { owner: NodeId, f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>, ) { - let allow_gen_future = Some(if self.tcx.features().async_fn_track_caller { - [sym::gen_future, sym::closure_track_caller][..].into() - } else { - [sym::gen_future][..].into() - }); - let mut lctx = LoweringContext { - // Pseudo-globals. - tcx: self.tcx, - resolver: self.resolver, - arena: self.tcx.hir_arena, - - // HirId handling. - bodies: Vec::new(), - attrs: SortedMap::default(), - children: Vec::default(), - current_hir_id_owner: hir::CRATE_OWNER_ID, - item_local_id_counter: hir::ItemLocalId::new(0), - node_id_to_local_id: Default::default(), - trait_map: Default::default(), - - // Lowering state. - catch_scope: None, - loop_scope: None, - is_in_loop_condition: false, - is_in_trait_impl: false, - is_in_dyn_type: false, - coroutine_kind: None, - task_context: None, - current_item: None, - impl_trait_defs: Vec::new(), - impl_trait_bounds: Vec::new(), - allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()), - allow_gen_future, - generics_def_id_map: Default::default(), - host_param_id: None, - }; + let mut lctx = LoweringContext::new(self.tcx, self.resolver); lctx.with_hir_id_owner(owner, |lctx| f(lctx)); for (def_id, info) in lctx.children { @@ -136,39 +100,9 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { fn lower_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) { let def_id = self.resolver.node_id_to_def_id[&item.id]; - let parent_id = self.tcx.local_parent(def_id); let parent_hir = self.lower_node(parent_id).unwrap(); - self.with_lctx(item.id, |lctx| { - // Evaluate with the lifetimes in `params` in-scope. - // This is used to track which lifetimes have already been defined, - // and which need to be replicated when lowering an async fn. - - match parent_hir.node().expect_item().kind { - hir::ItemKind::Impl(impl_) => { - lctx.is_in_trait_impl = impl_.of_trait.is_some(); - } - hir::ItemKind::Trait(_, _, generics, _, _) if lctx.tcx.features().effects => { - lctx.host_param_id = generics - .params - .iter() - .find(|param| { - parent_hir - .attrs - .get(param.hir_id.local_id) - .iter() - .any(|attr| attr.has_name(sym::rustc_host)) - }) - .map(|param| param.def_id); - } - _ => {} - } - - match ctxt { - AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)), - AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)), - } - }) + self.with_lctx(item.id, |lctx| lctx.lower_assoc_item(item, ctxt, parent_hir)) } fn lower_foreign_item(&mut self, item: &ForeignItem) { @@ -268,9 +202,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body, .. }) => { - self.with_new_scopes(|this| { - this.current_item = Some(ident.span); - + self.with_new_scopes(ident.span, |this| { // Note: we don't need to change the return type from `T` to // `impl Future<Output = T>` here because lower_body // only cares about the input argument patterns in the function @@ -480,7 +412,9 @@ impl<'hir> LoweringContext<'_, 'hir> { } ItemKind::MacroDef(MacroDef { body, macro_rules }) => { let body = P(self.lower_delim_args(body)); - let macro_kind = self.resolver.decl_macro_kind(self.local_def_id(id)); + let DefKind::Macro(macro_kind) = self.tcx.def_kind(self.local_def_id(id)) else { + unreachable!() + }; let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules }); hir::ItemKind::Macro(macro_def, macro_kind) } @@ -609,6 +543,42 @@ impl<'hir> LoweringContext<'_, 'hir> { } } + fn lower_assoc_item( + &mut self, + item: &AssocItem, + ctxt: AssocCtxt, + parent_hir: &'hir hir::OwnerInfo<'hir>, + ) -> hir::OwnerNode<'hir> { + // Evaluate with the lifetimes in `params` in-scope. + // This is used to track which lifetimes have already been defined, + // and which need to be replicated when lowering an async fn. + + match parent_hir.node().expect_item().kind { + hir::ItemKind::Impl(impl_) => { + self.is_in_trait_impl = impl_.of_trait.is_some(); + } + hir::ItemKind::Trait(_, _, generics, _, _) if self.tcx.features().effects => { + self.host_param_id = generics + .params + .iter() + .find(|param| { + parent_hir + .attrs + .get(param.hir_id.local_id) + .iter() + .any(|attr| attr.has_name(sym::rustc_host)) + }) + .map(|param| param.def_id); + } + _ => {} + } + + match ctxt { + AssocCtxt::Trait => hir::OwnerNode::TraitItem(self.lower_trait_item(item)), + AssocCtxt::Impl => hir::OwnerNode::ImplItem(self.lower_impl_item(item)), + } + } + fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> { let hir_id = self.lower_node_id(i.id); let owner_id = hir_id.expect_owner(); @@ -865,7 +835,6 @@ impl<'hir> LoweringContext<'_, 'hir> { }, ), AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => { - self.current_item = Some(i.span); let asyncness = sig.header.asyncness; let body_id = self.lower_maybe_async_body( i.span, @@ -1399,6 +1368,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.local_def_id(parent_node_id), param_node_id, DefPathData::TypeNs(sym::host), + DefKind::ConstParam, span, ); self.host_param_id = Some(def_id); @@ -1457,8 +1427,13 @@ impl<'hir> LoweringContext<'_, 'hir> { if let Some((span, hir_id, def_id)) = host_param_parts { let const_node_id = self.next_node_id(); - let anon_const: LocalDefId = - self.create_def(def_id, const_node_id, DefPathData::AnonConst, span); + let anon_const = self.create_def( + def_id, + const_node_id, + DefPathData::AnonConst, + DefKind::AnonConst, + span, + ); let const_id = self.next_id(); let const_expr_id = self.next_id(); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index e9e84255922..4abd0f135c6 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -35,7 +35,6 @@ #![doc(rust_logo)] #![feature(box_patterns)] #![feature(let_chains)] -#![feature(never_type)] #![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] @@ -67,7 +66,6 @@ use rustc_middle::{ ty::{ResolverAstLowering, TyCtxt}, }; use rustc_session::parse::{add_feature_diagnostics, feature_err}; -use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{DesugaringKind, Span, DUMMY_SP}; use smallvec::SmallVec; @@ -133,8 +131,8 @@ struct LoweringContext<'a, 'hir> { /// NodeIds that are lowered inside the current HIR owner. node_id_to_local_id: FxHashMap<NodeId, hir::ItemLocalId>, - allow_try_trait: Option<Lrc<[Symbol]>>, - allow_gen_future: Option<Lrc<[Symbol]>>, + allow_try_trait: Lrc<[Symbol]>, + allow_gen_future: Lrc<[Symbol]>, /// Mapping from generics `def_id`s to TAIT generics `def_id`s. /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic @@ -145,6 +143,46 @@ struct LoweringContext<'a, 'hir> { host_param_id: Option<LocalDefId>, } +impl<'a, 'hir> LoweringContext<'a, 'hir> { + fn new(tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering) -> Self { + Self { + // Pseudo-globals. + tcx, + resolver: resolver, + arena: tcx.hir_arena, + + // HirId handling. + bodies: Vec::new(), + attrs: SortedMap::default(), + children: Vec::default(), + current_hir_id_owner: hir::CRATE_OWNER_ID, + item_local_id_counter: hir::ItemLocalId::new(0), + node_id_to_local_id: Default::default(), + trait_map: Default::default(), + + // Lowering state. + catch_scope: None, + loop_scope: None, + is_in_loop_condition: false, + is_in_trait_impl: false, + is_in_dyn_type: false, + coroutine_kind: None, + task_context: None, + current_item: None, + impl_trait_defs: Vec::new(), + impl_trait_bounds: Vec::new(), + allow_try_trait: [sym::try_trait_v2, sym::yeet_desugar_details].into(), + allow_gen_future: if tcx.features().async_fn_track_caller { + [sym::gen_future, sym::closure_track_caller].into() + } else { + [sym::gen_future].into() + }, + generics_def_id_map: Default::default(), + host_param_id: None, + } + } +} + trait ResolverAstLoweringExt { fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>; fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>; @@ -153,7 +191,6 @@ trait ResolverAstLoweringExt { fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>; fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>; fn remap_extra_lifetime_params(&mut self, from: NodeId, to: NodeId); - fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind; } impl ResolverAstLoweringExt for ResolverAstLowering { @@ -217,10 +254,6 @@ impl ResolverAstLoweringExt for ResolverAstLowering { let lifetimes = self.extra_lifetime_params_map.remove(&from).unwrap_or_default(); self.extra_lifetime_params_map.insert(to, lifetimes); } - - fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind { - self.builtin_macro_kinds.get(&def_id).copied().unwrap_or(MacroKind::Bang) - } } /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree, @@ -467,6 +500,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { parent: LocalDefId, node_id: ast::NodeId, data: DefPathData, + def_kind: DefKind, span: Span, ) -> LocalDefId { debug_assert_ne!(node_id, ast::DUMMY_NODE_ID); @@ -478,7 +512,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.tcx.hir().def_key(self.local_def_id(node_id)), ); - let def_id = self.tcx.at(span).create_def(parent, data).def_id(); + let def_id = self.tcx.at(span).create_def(parent, data, def_kind).def_id(); debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id); self.resolver.node_id_to_def_id.insert(node_id, def_id); @@ -780,6 +814,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.current_hir_id_owner.def_id, param, DefPathData::LifetimeNs(kw::UnderscoreLifetime), + DefKind::LifetimeParam, ident.span, ); debug!(?_def_id); @@ -843,7 +878,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { result } - fn with_new_scopes<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T { + fn with_new_scopes<T>(&mut self, scope_span: Span, f: impl FnOnce(&mut Self) -> T) -> T { + let current_item = self.current_item; + self.current_item = Some(scope_span); + let was_in_loop_condition = self.is_in_loop_condition; self.is_in_loop_condition = false; @@ -855,6 +893,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.is_in_loop_condition = was_in_loop_condition; + self.current_item = current_item; + ret } @@ -1192,6 +1232,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { parent_def_id.def_id, node_id, DefPathData::AnonConst, + DefKind::AnonConst, span, ); @@ -1203,7 +1244,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { tokens: None, }; - let ct = self.with_new_scopes(|this| hir::AnonConst { + let ct = self.with_new_scopes(span, |this| hir::AnonConst { def_id, hir_id: this.lower_node_id(node_id), body: this.lower_const_body(path_expr.span, Some(&path_expr)), @@ -1429,6 +1470,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.current_hir_id_owner.def_id, *def_node_id, DefPathData::TypeNs(ident.name), + DefKind::TyParam, span, ); let (param, bounds, path) = self.lower_universal_param_and_bounds( @@ -1582,6 +1624,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.current_hir_id_owner.def_id, opaque_ty_node_id, DefPathData::ImplTrait, + DefKind::OpaqueTy, opaque_ty_span, ); debug!(?opaque_ty_def_id); @@ -1636,6 +1679,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { opaque_ty_def_id, duplicated_lifetime_node_id, DefPathData::LifetimeNs(lifetime.ident.name), + DefKind::LifetimeParam, lifetime.ident.span, ); captured_to_synthesized_mapping.insert(old_def_id, duplicated_lifetime_def_id); @@ -2207,7 +2251,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst { - self.with_new_scopes(|this| hir::AnonConst { + self.with_new_scopes(c.value.span, |this| hir::AnonConst { def_id: this.local_def_id(c.id), hir_id: this.lower_node_id(c.id), body: this.lower_const_body(c.value.span, Some(&c.value)), @@ -2505,8 +2549,13 @@ impl<'hir> GenericArgsCtor<'hir> { }); 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, DefPathData::AnonConst, span); + let def_id = lcx.create_def( + lcx.current_hir_id_owner.def_id, + id, + DefPathData::AnonConst, + 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/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs index d66bba517e0..4b1c057cdbf 100644 --- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs +++ b/compiler/rustc_ast_lowering/src/lifetime_collector.rs @@ -108,7 +108,7 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> { } } -pub fn lifetimes_in_bounds( +pub(crate) fn lifetimes_in_bounds( resolver: &ResolverAstLowering, bounds: &GenericBounds, ) -> Vec<Lifetime> { diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index a30f264bc7d..017314ee4d1 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -18,12 +18,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc(self.lower_pat_mut(pattern)) } - pub(crate) fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> { + fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> { ensure_sufficient_stack(|| { // loop here to avoid recursion let node = loop { match &pattern.kind { PatKind::Wild => break hir::PatKind::Wild, + PatKind::Never => break hir::PatKind::Never, PatKind::Ident(binding_mode, ident, sub) => { let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(s)); break self.lower_pat_ident(pattern, *binding_mode, *ident, lower_sub); diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 8fb7c7de50c..8851fbd28f0 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -555,6 +555,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(explicit_tail_calls, "`become` expression is experimental"); gate_all!(generic_const_items, "generic const items are experimental"); gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented"); + gate_all!(never_patterns, "`!` patterns are experimental"); if !visitor.features.negative_bounds { for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index a3bf47328ea..cbdcc683b56 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -151,7 +151,7 @@ pub fn print_crate<'a>( /// Note: some old proc macros parse pretty-printed output, so changes here can /// break old code. For example: /// - #63896: `#[allow(unused,` must be printed rather than `#[allow(unused ,` -/// - #73345: `#[allow(unused)] must be printed rather than `# [allow(unused)] +/// - #73345: `#[allow(unused)]` must be printed rather than `# [allow(unused)]` /// fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool { use token::*; @@ -1343,6 +1343,7 @@ impl<'a> State<'a> { is that it doesn't matter */ match &pat.kind { PatKind::Wild => self.word("_"), + PatKind::Never => self.word("!"), PatKind::Ident(BindingAnnotation(by_ref, mutbl), ident, sub) => { if *by_ref == ByRef::Yes { self.word_nbsp("ref"); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index ed9b68a1d5a..45a55e20ca7 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -255,12 +255,12 @@ impl<'a> State<'a> { self.print_expr_maybe_paren(lhs, left_prec); self.space(); - self.word_space(op.node.to_string()); + self.word_space(op.node.as_str()); self.print_expr_maybe_paren(rhs, right_prec) } fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) { - self.word(ast::UnOp::to_string(op)); + self.word(op.as_str()); self.print_expr_maybe_paren(expr, parser::PREC_PREFIX) } @@ -470,7 +470,7 @@ impl<'a> State<'a> { let prec = AssocOp::Assign.precedence() as i8; self.print_expr_maybe_paren(lhs, prec + 1); self.space(); - self.word(op.node.to_string()); + self.word(op.node.as_str()); self.word_space("="); self.print_expr_maybe_paren(rhs, prec); } diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 7e87d1c3130..609d75733b2 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -985,7 +985,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> { Ok(literal) => acc.push(ReprPacked(literal)), Err(message) => literal_error = Some(message), }; - } else if matches!(name, sym::C | sym::simd | sym::transparent) + } else if matches!(name, sym::Rust | sym::C | sym::simd | sym::transparent) || int_type_of_word(name).is_some() { recognised = true; @@ -1018,7 +1018,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> { }); } else if matches!( meta_item.name_or_empty(), - sym::C | sym::simd | sym::transparent + sym::Rust | sym::C | sym::simd | sym::transparent ) || int_type_of_word(meta_item.name_or_empty()).is_some() { recognised = true; @@ -1043,7 +1043,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> { ); } else if matches!( meta_item.name_or_empty(), - sym::C | sym::simd | sym::transparent + sym::Rust | sym::C | sym::simd | sym::transparent ) || int_type_of_word(meta_item.name_or_empty()).is_some() { recognised = true; diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 9225f19876d..ef4bf543454 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2352,7 +2352,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Applicability::MaybeIncorrect, ); } else { - err.note("the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used"); + err.note("the result of `format_args!` can only be assigned directly if no placeholders in its arguments are used"); err.note("to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html>"); } suggested = true; diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 7d6e15839c5..6e44f44dc18 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -42,6 +42,7 @@ use rustc_target::abi::FieldIdx; use smallvec::SmallVec; use std::cell::RefCell; use std::collections::BTreeMap; +use std::marker::PhantomData; use std::ops::Deref; use std::rc::Rc; @@ -100,7 +101,7 @@ use renumber::RegionCtxt; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } /// Associate some local constants with the `'tcx` lifetime -struct TyCtxtConsts<'tcx>(TyCtxt<'tcx>); +struct TyCtxtConsts<'tcx>(PhantomData<&'tcx ()>); impl<'tcx> TyCtxtConsts<'tcx> { const DEREF_PROJECTION: &'tcx [PlaceElem<'tcx>; 1] = &[ProjectionElem::Deref]; } diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 12d12d5bff0..c5fd535b036 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -672,30 +672,22 @@ fn report_missing_placeholders( if explained.contains(&sub) { continue; } - explained.insert(sub.clone()); + explained.insert(sub); if !found_foreign { found_foreign = true; show_doc_note = true; } - if let Some(inner_sp) = pos { - let sp = fmt_span.from_inner(inner_sp); + let sp = fmt_span.from_inner(pos); - if success { - suggestions.push((sp, trn)); - } else { - diag.span_note( - sp, - format!("format specifiers use curly braces, and {}", trn), - ); - } + if success { + suggestions.push((sp, trn)); } else { - if success { - diag.help(format!("`{}` should be written as `{}`", sub, trn)); - } else { - diag.note(format!("`{}` should use curly braces, and {}", sub, trn)); - } + diag.span_note( + sp, + format!("format specifiers use curly braces, and {}", trn), + ); } } diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index 2fc8a076366..307e582d65e 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -19,10 +19,10 @@ pub(crate) mod printf { } } - pub fn position(&self) -> Option<InnerSpan> { + pub fn position(&self) -> InnerSpan { match self { - Substitution::Format(fmt) => Some(fmt.position), - &Substitution::Escape((start, end)) => Some(InnerSpan::new(start, end)), + Substitution::Format(fmt) => fmt.position, + &Substitution::Escape((start, end)) => InnerSpan::new(start, end), } } @@ -302,10 +302,9 @@ pub(crate) mod printf { fn next(&mut self) -> Option<Self::Item> { let (mut sub, tail) = parse_next_substitution(self.s)?; self.s = tail; - if let Some(InnerSpan { start, end }) = sub.position() { - sub.set_position(start + self.pos, end + self.pos); - self.pos += end; - } + let InnerSpan { start, end } = sub.position(); + sub.set_position(start + self.pos, end + self.pos); + self.pos += end; Some(sub) } @@ -629,9 +628,9 @@ pub mod shell { } } - pub fn position(&self) -> Option<InnerSpan> { + pub fn position(&self) -> InnerSpan { let (Self::Ordinal(_, pos) | Self::Name(_, pos) | Self::Escape(pos)) = self; - Some(InnerSpan::new(pos.0, pos.1)) + InnerSpan::new(pos.0, pos.1) } pub fn set_position(&mut self, start: usize, end: usize) { @@ -664,10 +663,9 @@ pub mod shell { fn next(&mut self) -> Option<Self::Item> { let (mut sub, tail) = parse_next_substitution(self.s)?; self.s = tail; - if let Some(InnerSpan { start, end }) = sub.position() { - sub.set_position(start + self.pos, end + self.pos); - self.pos += end; - } + let InnerSpan { start, end } = sub.position(); + sub.set_position(start + self.pos, end + self.pos); + self.pos += end; Some(sub) } diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 92ae59ad352..481741bb127 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -4,7 +4,7 @@ use rustc_codegen_ssa::traits::*; use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::config::OptLevel; +use rustc_session::config::{FunctionReturn, OptLevel}; use rustc_span::symbol::sym; use rustc_target::spec::abi::Abi; use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector}; @@ -118,6 +118,15 @@ pub fn frame_pointer_type_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attr Some(llvm::CreateAttrStringValue(cx.llcx, "frame-pointer", attr_value)) } +fn function_return_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { + let function_return_attr = match cx.sess().opts.unstable_opts.function_return { + FunctionReturn::Keep => return None, + FunctionReturn::ThunkExtern => AttributeKind::FnRetThunkExtern, + }; + + Some(function_return_attr.create_attr(cx.llcx)) +} + /// Tell LLVM what instrument function to insert. #[inline] fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attribute; 4]> { @@ -331,8 +340,9 @@ pub fn from_fn_attrs<'ll, 'tcx>( to_add.push(llvm::CreateAttrString(cx.llcx, "use-sample-profile")); } - // FIXME: none of these three functions interact with source level attributes. + // FIXME: none of these functions interact with source level attributes. to_add.extend(frame_pointer_type_attr(cx)); + to_add.extend(function_return_attr(cx)); to_add.extend(instrument_function_attr(cx)); to_add.extend(nojumptables_attr(cx)); to_add.extend(probestack_attr(cx)); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index e6c5085cc0e..92a8c00510b 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -134,18 +134,6 @@ pub unsafe fn create_module<'ll>( let mut target_data_layout = sess.target.data_layout.to_string(); let llvm_version = llvm_util::get_version(); - if llvm_version < (16, 0, 0) { - if sess.target.arch == "s390x" { - // LLVM 16 data layout changed to always set 64-bit vector alignment, - // which is conditional in earlier LLVM versions. - // https://reviews.llvm.org/D131158 for the discussion. - target_data_layout = target_data_layout.replace("-v128:64", ""); - } else if sess.target.arch == "riscv64" { - // LLVM 16 introduced this change so as to produce more efficient code. - // See https://reviews.llvm.org/D116735 for the discussion. - target_data_layout = target_data_layout.replace("-n32:64-", "-n64-"); - } - } if llvm_version < (17, 0, 0) { if sess.target.arch.starts_with("powerpc") { // LLVM 17 specifies function pointer alignment for ppc: diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index df4cd8ea0bd..d701b20e953 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -200,6 +200,7 @@ pub enum AttributeKind { AllocatedPointer = 38, AllocAlign = 39, SanitizeSafeStack = 40, + FnRetThunkExtern = 41, } /// LLVMIntPredicate diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index ac13d61229e..be895417bbe 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -44,7 +44,7 @@ use tempfile::Builder as TempFileBuilder; use itertools::Itertools; use std::cell::OnceCell; use std::collections::BTreeSet; -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use std::fs::{read, File, OpenOptions}; use std::io::{BufWriter, Write}; use std::ops::Deref; @@ -2527,7 +2527,7 @@ fn add_native_libs_from_crate( NativeLibKind::WasmImportModule => {} NativeLibKind::LinkArg => { if link_static { - cmd.arg(name); + cmd.linker_arg(OsStr::new(name), verbatim); } } } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 4dd688c2234..bb5f6e27e4d 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -196,6 +196,14 @@ pub trait Linker { fn add_no_exec(&mut self) {} fn add_as_needed(&mut self) {} fn reset_per_library_state(&mut self) {} + fn linker_arg(&mut self, arg: &OsStr, verbatim: bool) { + self.linker_args(&[arg], verbatim); + } + fn linker_args(&mut self, args: &[&OsStr], _verbatim: bool) { + args.into_iter().for_each(|a| { + self.cmd().arg(a); + }); + } } impl dyn Linker + '_ { @@ -223,38 +231,12 @@ pub struct GccLinker<'a> { } impl<'a> GccLinker<'a> { - /// Passes an argument directly to the linker. - /// - /// When the linker is not ld-like such as when using a compiler as a linker, the argument is - /// prepended by `-Wl,`. - fn linker_arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Self { - self.linker_args(&[arg]); - self + fn linker_arg(&mut self, arg: impl AsRef<OsStr>) { + Linker::linker_arg(self, arg.as_ref(), false); } - - /// Passes a series of arguments directly to the linker. - /// - /// When the linker is ld-like, the arguments are simply appended to the command. When the - /// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by - /// commas to form an argument that is then prepended with `-Wl`. In this situation, only a - /// single argument is appended to the command to ensure that the order of the arguments is - /// preserved by the compiler. - fn linker_args(&mut self, args: &[impl AsRef<OsStr>]) -> &mut Self { - if self.is_ld { - args.into_iter().for_each(|a| { - self.cmd.arg(a); - }); - } else { - if !args.is_empty() { - let mut s = OsString::from("-Wl"); - for a in args { - s.push(","); - s.push(a); - } - self.cmd.arg(s); - } - } - self + fn linker_args(&mut self, args: &[impl AsRef<OsStr>]) { + let args_vec: Vec<&OsStr> = args.iter().map(|x| x.as_ref()).collect(); + Linker::linker_args(self, &args_vec, false); } fn takes_hints(&self) -> bool { @@ -361,6 +343,30 @@ impl<'a> GccLinker<'a> { } impl<'a> Linker for GccLinker<'a> { + /// Passes a series of arguments directly to the linker. + /// + /// When the linker is ld-like, the arguments are simply appended to the command. When the + /// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by + /// commas to form an argument that is then prepended with `-Wl`. In this situation, only a + /// single argument is appended to the command to ensure that the order of the arguments is + /// preserved by the compiler. + fn linker_args(&mut self, args: &[&OsStr], verbatim: bool) { + if self.is_ld || verbatim { + args.into_iter().for_each(|a| { + self.cmd.arg(a); + }); + } else { + if !args.is_empty() { + let mut s = OsString::from("-Wl"); + for a in args { + s.push(","); + s.push(a); + } + self.cmd.arg(s); + } + } + } + fn cmd(&mut self) -> &mut Command { &mut self.cmd } @@ -531,7 +537,7 @@ impl<'a> Linker for GccLinker<'a> { self.linker_arg("-force_load"); self.linker_arg(&lib); } else { - self.linker_arg("--whole-archive").cmd.arg(lib); + self.linker_args(&[OsString::from("--whole-archive"), lib.into()]); self.linker_arg("--no-whole-archive"); } } @@ -1302,6 +1308,8 @@ impl<'a> Linker for WasmLd<'a> { } fn optimize(&mut self) { + // The -O flag is, as of late 2023, only used for merging of strings and debuginfo, and + // only differentiates -O0 and -O1. It does not apply to LTO. self.cmd.arg(match self.sess.opts.optimize { OptLevel::No => "-O0", OptLevel::Less => "-O1", @@ -1354,7 +1362,31 @@ impl<'a> Linker for WasmLd<'a> { fn subsystem(&mut self, _subsystem: &str) {} fn linker_plugin_lto(&mut self) { - // Do nothing for now + match self.sess.opts.cg.linker_plugin_lto { + LinkerPluginLto::Disabled => { + // Nothing to do + } + LinkerPluginLto::LinkerPluginAuto => { + self.push_linker_plugin_lto_args(); + } + LinkerPluginLto::LinkerPlugin(_) => { + self.push_linker_plugin_lto_args(); + } + } + } +} + +impl<'a> WasmLd<'a> { + fn push_linker_plugin_lto_args(&mut self) { + let opt_level = match self.sess.opts.optimize { + config::OptLevel::No => "O0", + config::OptLevel::Less => "O1", + config::OptLevel::Default => "O2", + config::OptLevel::Aggressive => "O3", + // wasm-ld only handles integer LTO opt levels. Use O2 + config::OptLevel::Size | config::OptLevel::SizeMin => "O2", + }; + self.cmd.arg(&format!("--lto-{opt_level}")); } } diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index a0d6e1885c2..bfd0a458884 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -216,6 +216,7 @@ impl CodegenResults { sess: &Session, rlink_file: &Path, codegen_results: &CodegenResults, + outputs: &OutputFilenames, ) -> Result<usize, io::Error> { let mut encoder = FileEncoder::new(rlink_file)?; encoder.emit_raw_bytes(RLINK_MAGIC); @@ -224,10 +225,14 @@ impl CodegenResults { encoder.emit_raw_bytes(&RLINK_VERSION.to_be_bytes()); encoder.emit_str(sess.cfg_version); Encodable::encode(codegen_results, &mut encoder); + Encodable::encode(outputs, &mut encoder); encoder.finish().map_err(|(_path, err)| err) } - pub fn deserialize_rlink(sess: &Session, data: Vec<u8>) -> Result<Self, CodegenErrors> { + pub fn deserialize_rlink( + sess: &Session, + data: Vec<u8>, + ) -> Result<(Self, OutputFilenames), CodegenErrors> { // The Decodable machinery is not used here because it panics if the input data is invalid // and because its internal representation may change. if !data.starts_with(RLINK_MAGIC) { @@ -256,6 +261,7 @@ impl CodegenResults { } let codegen_results = CodegenResults::decode(&mut decoder); - Ok(codegen_results) + let outputs = OutputFilenames::decode(&mut decoder); + Ok((codegen_results, outputs)) } } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 2ad0c9a8731..04f0cdb326e 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -7,12 +7,11 @@ use std::assert_matches::assert_matches; use either::{Either, Left, Right}; use rustc_ast::Mutability; -use rustc_index::IndexSlice; use rustc_middle::mir; use rustc_middle::ty; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::Ty; -use rustc_target::abi::{Abi, Align, FieldIdx, HasDataLayout, Size, FIRST_VARIANT}; +use rustc_target::abi::{Abi, Align, HasDataLayout, Size}; use super::{ alloc_range, mir_assign_valid_types, AllocId, AllocRef, AllocRefMut, CheckAlignMsg, ImmTy, @@ -977,34 +976,6 @@ where Ok(self.ptr_with_meta_to_mplace(ptr.into(), MemPlaceMeta::Meta(meta), layout)) } - /// Writes the aggregate to the destination. - #[instrument(skip(self), level = "trace")] - pub fn write_aggregate( - &mut self, - kind: &mir::AggregateKind<'tcx>, - operands: &IndexSlice<FieldIdx, mir::Operand<'tcx>>, - dest: &PlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx> { - self.write_uninit(dest)?; - let (variant_index, variant_dest, active_field_index) = match *kind { - mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => { - let variant_dest = self.project_downcast(dest, variant_index)?; - (variant_index, variant_dest, active_field_index) - } - _ => (FIRST_VARIANT, dest.clone(), None), - }; - if active_field_index.is_some() { - assert_eq!(operands.len(), 1); - } - for (field_index, operand) in operands.iter_enumerated() { - let field_index = active_field_index.unwrap_or(field_index); - let field_dest = self.project_field(&variant_dest, field_index.as_usize())?; - let op = self.eval_operand(operand, Some(field_dest.layout))?; - self.copy_op(&op, &field_dest, /*allow_transmute*/ false)?; - } - self.write_discriminant(variant_index, dest) - } - pub fn raw_const_to_mplace( &self, raw: mir::ConstAlloc<'tcx>, diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index b6993d939c5..d48329b6c69 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -4,11 +4,12 @@ use either::Either; +use rustc_index::IndexSlice; use rustc_middle::mir; -use rustc_middle::mir::interpret::{InterpResult, Scalar}; use rustc_middle::ty::layout::LayoutOf; +use rustc_target::abi::{FieldIdx, FIRST_VARIANT}; -use super::{ImmTy, InterpCx, Machine, Projectable}; +use super::{ImmTy, InterpCx, InterpResult, Machine, PlaceTy, Projectable, Scalar}; use crate::util; impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { @@ -187,34 +188,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } Repeat(ref operand, _) => { - let src = self.eval_operand(operand, None)?; - assert!(src.layout.is_sized()); - let dest = self.force_allocation(&dest)?; - let length = dest.len(self)?; - - if length == 0 { - // Nothing to copy... but let's still make sure that `dest` as a place is valid. - self.get_place_alloc_mut(&dest)?; - } else { - // Write the src to the first element. - let first = self.project_index(&dest, 0)?; - self.copy_op(&src, &first, /*allow_transmute*/ false)?; - - // This is performance-sensitive code for big static/const arrays! So we - // avoid writing each operand individually and instead just make many copies - // of the first element. - let elem_size = first.layout.size; - let first_ptr = first.ptr(); - let rest_ptr = first_ptr.offset(elem_size, self)?; - // No alignment requirement since `copy_op` above already checked it. - self.mem_copy_repeatedly( - first_ptr, - rest_ptr, - elem_size, - length - 1, - /*nonoverlapping:*/ true, - )?; - } + self.write_repeat(operand, &dest)?; } Len(place) => { @@ -307,6 +281,73 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(()) } + /// Writes the aggregate to the destination. + #[instrument(skip(self), level = "trace")] + fn write_aggregate( + &mut self, + kind: &mir::AggregateKind<'tcx>, + operands: &IndexSlice<FieldIdx, mir::Operand<'tcx>>, + dest: &PlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx> { + self.write_uninit(dest)?; // make sure all the padding ends up as uninit + let (variant_index, variant_dest, active_field_index) = match *kind { + mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => { + let variant_dest = self.project_downcast(dest, variant_index)?; + (variant_index, variant_dest, active_field_index) + } + _ => (FIRST_VARIANT, dest.clone(), None), + }; + if active_field_index.is_some() { + assert_eq!(operands.len(), 1); + } + for (field_index, operand) in operands.iter_enumerated() { + let field_index = active_field_index.unwrap_or(field_index); + let field_dest = self.project_field(&variant_dest, field_index.as_usize())?; + let op = self.eval_operand(operand, Some(field_dest.layout))?; + self.copy_op(&op, &field_dest, /*allow_transmute*/ false)?; + } + self.write_discriminant(variant_index, dest) + } + + /// Repeats `operand` into the destination. `dest` must have array type, and that type + /// determines how often `operand` is repeated. + fn write_repeat( + &mut self, + operand: &mir::Operand<'tcx>, + dest: &PlaceTy<'tcx, M::Provenance>, + ) -> InterpResult<'tcx> { + let src = self.eval_operand(operand, None)?; + assert!(src.layout.is_sized()); + let dest = self.force_allocation(&dest)?; + let length = dest.len(self)?; + + if length == 0 { + // Nothing to copy... but let's still make sure that `dest` as a place is valid. + self.get_place_alloc_mut(&dest)?; + } else { + // Write the src to the first element. + let first = self.project_index(&dest, 0)?; + self.copy_op(&src, &first, /*allow_transmute*/ false)?; + + // This is performance-sensitive code for big static/const arrays! So we + // avoid writing each operand individually and instead just make many copies + // of the first element. + let elem_size = first.layout.size; + let first_ptr = first.ptr(); + let rest_ptr = first_ptr.offset(elem_size, self)?; + // No alignment requirement since `copy_op` above already checked it. + self.mem_copy_repeatedly( + first_ptr, + rest_ptr, + elem_size, + length - 1, + /*nonoverlapping:*/ true, + )?; + } + + Ok(()) + } + /// Evaluate the given terminator. Will also adjust the stack frame and statement position accordingly. fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> { info!("{:?}", terminator.kind); diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index cf9312ea8fb..b54d75f7ed7 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -492,7 +492,7 @@ where let returned_walk = return_value.take().into_iter().map(|walk| (*successor_node, Some(walk))); - let successor_walk = successors.by_ref().map(|successor_node| { + let successor_walk = successors.map(|successor_node| { debug!(?node, ?successor_node); (successor_node, self.inspect_node(successor_node)) }); diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index e7cc3ae4d55..6af11ce8479 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -401,9 +401,7 @@ fn run_compiler( Ok(()) })?; - // Make sure the `output_filenames` query is run for its side - // effects of writing the dep-info and reporting errors. - queries.global_ctxt()?.enter(|tcx| tcx.output_filenames(())); + queries.write_dep_info()?; } else { let krate = queries.parse()?; pretty::print( @@ -431,9 +429,7 @@ fn run_compiler( return early_exit(); } - // Make sure the `output_filenames` query is run for its side - // effects of writing the dep-info and reporting errors. - queries.global_ctxt()?.enter(|tcx| tcx.output_filenames(())); + queries.write_dep_info()?; if sess.opts.output_types.contains_key(&OutputType::DepInfo) && sess.opts.output_types.len() == 1 @@ -648,12 +644,11 @@ fn show_md_content_with_pager(content: &str, color: ColorConfig) { fn process_rlink(sess: &Session, compiler: &interface::Compiler) { assert!(sess.opts.unstable_opts.link_only); if let Input::File(file) = &sess.io.input { - let outputs = compiler.build_output_filenames(sess, &[]); let rlink_data = fs::read(file).unwrap_or_else(|err| { sess.emit_fatal(RlinkUnableToRead { err }); }); - let codegen_results = match CodegenResults::deserialize_rlink(sess, rlink_data) { - Ok(codegen) => codegen, + let (codegen_results, outputs) = match CodegenResults::deserialize_rlink(sess, rlink_data) { + Ok((codegen, outputs)) => (codegen, outputs), Err(err) => { match err { CodegenErrors::WrongFileType => sess.emit_fatal(RLinkWrongFileType), diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 6680e8875c3..1028d43f9c5 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -653,3 +653,4 @@ E0795: include_str!("./error_codes/E0795.md"), // E0721, // `await` keyword // E0723, // unstable feature in `const` context // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. +// E0744, // merged into E0728 diff --git a/compiler/rustc_error_codes/src/error_codes/E0744.md b/compiler/rustc_error_codes/src/error_codes/E0744.md index 9a8ef3b840d..e56c45db176 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0744.md +++ b/compiler/rustc_error_codes/src/error_codes/E0744.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + An unsupported expression was used inside a const context. Erroneous code example: -```compile_fail,edition2018,E0744 +```ignore (removed error code) const _: i32 = { async { 0 }.await }; diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index e34661d5fc6..8182c8779ff 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -50,6 +50,8 @@ macro_rules! declare_features { }),+ ]; + const NUM_FEATURES: usize = UNSTABLE_FEATURES.len(); + /// A set of features to be used by later passes. #[derive(Clone, Default, Debug)] pub struct Features { @@ -82,8 +84,14 @@ macro_rules! declare_features { self.declared_features.insert(symbol); } - pub fn walk_feature_fields(&self, mut f: impl FnMut(&str, bool)) { - $(f(stringify!($feature), self.$feature);)+ + /// This is intended for hashing the set of active features. + /// + /// The expectation is that this produces much smaller code than other alternatives. + /// + /// Note that the total feature count is pretty small, so this is not a huge array. + #[inline] + pub fn all_features(&self) -> [u8; NUM_FEATURES] { + [$(self.$feature as u8),+] } /// Is the given feature explicitly declared, i.e. named in a @@ -147,7 +155,7 @@ macro_rules! declare_features { // was set. // // Note that the features are grouped into internal/user-facing and then -// sorted by version inside those groups. This is enforced with tidy. +// sorted alphabetically inside those groups. This is enforced with tidy. // // N.B., `tools/tidy/src/features.rs` parses this information directly out of the // source, so take care when modifying it. @@ -512,6 +520,8 @@ declare_features! ( (unstable, native_link_modifiers_as_needed, "1.53.0", Some(81490), None), /// Allow negative trait implementations. (unstable, negative_impls, "1.44.0", Some(68318), None), + /// Allows the `!` pattern. + (incomplete, never_patterns, "CURRENT_RUSTC_VERSION", Some(118155), None), /// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. (unstable, never_type, "1.13.0", Some(35121), None), /// Allows diverging expressions to fall back to `!` rather than `()`. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index d2b83d0eb00..81733d8f64e 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -7,8 +7,8 @@ use crate::LangItem; use rustc_ast as ast; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, TraitObjectSyntax, UintTy}; -pub use rustc_ast::{BindingAnnotation, BorrowKind, ByRef, ImplPolarity, IsAuto}; -pub use rustc_ast::{CaptureBy, Movability, Mutability}; +pub use rustc_ast::{BinOp, BinOpKind, BindingAnnotation, BorrowKind, ByRef, CaptureBy}; +pub use rustc_ast::{ImplPolarity, IsAuto, Movability, Mutability, UnOp}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; @@ -1002,7 +1002,7 @@ impl<'hir> Pat<'hir> { use PatKind::*; match self.kind { - Wild | Lit(_) | Range(..) | Binding(.., None) | Path(_) => true, + Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) => true, Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it), Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)), TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)), @@ -1029,7 +1029,7 @@ impl<'hir> Pat<'hir> { use PatKind::*; match self.kind { - Wild | Lit(_) | Range(..) | Binding(.., None) | Path(_) => {} + Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) => {} Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it), Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)), TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)), @@ -1142,6 +1142,9 @@ pub enum PatKind<'hir> { /// Invariant: `pats.len() >= 2`. Or(&'hir [Pat<'hir>]), + /// A never pattern `!`. + Never, + /// A path pattern for a unit struct/variant or a (maybe-associated) constant. Path(QPath<'hir>), @@ -1174,155 +1177,6 @@ pub enum PatKind<'hir> { Slice(&'hir [Pat<'hir>], Option<&'hir Pat<'hir>>, &'hir [Pat<'hir>]), } -#[derive(Copy, Clone, PartialEq, Debug, HashStable_Generic)] -pub enum BinOpKind { - /// The `+` operator (addition). - Add, - /// The `-` operator (subtraction). - Sub, - /// The `*` operator (multiplication). - Mul, - /// The `/` operator (division). - Div, - /// The `%` operator (modulus). - Rem, - /// The `&&` operator (logical and). - And, - /// The `||` operator (logical or). - Or, - /// The `^` operator (bitwise xor). - BitXor, - /// The `&` operator (bitwise and). - BitAnd, - /// The `|` operator (bitwise or). - BitOr, - /// The `<<` operator (shift left). - Shl, - /// The `>>` operator (shift right). - Shr, - /// The `==` operator (equality). - Eq, - /// The `<` operator (less than). - Lt, - /// The `<=` operator (less than or equal to). - Le, - /// The `!=` operator (not equal to). - Ne, - /// The `>=` operator (greater than or equal to). - Ge, - /// The `>` operator (greater than). - Gt, -} - -impl BinOpKind { - pub fn as_str(self) -> &'static str { - match self { - BinOpKind::Add => "+", - BinOpKind::Sub => "-", - BinOpKind::Mul => "*", - BinOpKind::Div => "/", - BinOpKind::Rem => "%", - BinOpKind::And => "&&", - BinOpKind::Or => "||", - BinOpKind::BitXor => "^", - BinOpKind::BitAnd => "&", - BinOpKind::BitOr => "|", - BinOpKind::Shl => "<<", - BinOpKind::Shr => ">>", - BinOpKind::Eq => "==", - BinOpKind::Lt => "<", - BinOpKind::Le => "<=", - BinOpKind::Ne => "!=", - BinOpKind::Ge => ">=", - BinOpKind::Gt => ">", - } - } - - pub fn is_lazy(self) -> bool { - matches!(self, BinOpKind::And | BinOpKind::Or) - } - - pub fn is_comparison(self) -> bool { - match self { - BinOpKind::Eq - | BinOpKind::Lt - | BinOpKind::Le - | BinOpKind::Ne - | BinOpKind::Gt - | BinOpKind::Ge => true, - BinOpKind::And - | BinOpKind::Or - | BinOpKind::Add - | BinOpKind::Sub - | BinOpKind::Mul - | BinOpKind::Div - | BinOpKind::Rem - | BinOpKind::BitXor - | BinOpKind::BitAnd - | BinOpKind::BitOr - | BinOpKind::Shl - | BinOpKind::Shr => false, - } - } - - /// Returns `true` if the binary operator takes its arguments by value. - pub fn is_by_value(self) -> bool { - !self.is_comparison() - } -} - -impl Into<ast::BinOpKind> for BinOpKind { - fn into(self) -> ast::BinOpKind { - match self { - BinOpKind::Add => ast::BinOpKind::Add, - BinOpKind::Sub => ast::BinOpKind::Sub, - BinOpKind::Mul => ast::BinOpKind::Mul, - BinOpKind::Div => ast::BinOpKind::Div, - BinOpKind::Rem => ast::BinOpKind::Rem, - BinOpKind::And => ast::BinOpKind::And, - BinOpKind::Or => ast::BinOpKind::Or, - BinOpKind::BitXor => ast::BinOpKind::BitXor, - BinOpKind::BitAnd => ast::BinOpKind::BitAnd, - BinOpKind::BitOr => ast::BinOpKind::BitOr, - BinOpKind::Shl => ast::BinOpKind::Shl, - BinOpKind::Shr => ast::BinOpKind::Shr, - BinOpKind::Eq => ast::BinOpKind::Eq, - BinOpKind::Lt => ast::BinOpKind::Lt, - BinOpKind::Le => ast::BinOpKind::Le, - BinOpKind::Ne => ast::BinOpKind::Ne, - BinOpKind::Ge => ast::BinOpKind::Ge, - BinOpKind::Gt => ast::BinOpKind::Gt, - } - } -} - -pub type BinOp = Spanned<BinOpKind>; - -#[derive(Copy, Clone, PartialEq, Debug, HashStable_Generic)] -pub enum UnOp { - /// The `*` operator (dereferencing). - Deref, - /// The `!` operator (logical negation). - Not, - /// The `-` operator (negation). - Neg, -} - -impl UnOp { - pub fn as_str(self) -> &'static str { - match self { - Self::Deref => "*", - Self::Not => "!", - Self::Neg => "-", - } - } - - /// Returns `true` if the unary operator takes its argument by value. - pub fn is_by_value(self) -> bool { - matches!(self, Self::Neg | Self::Not) - } -} - /// A statement. #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Stmt<'hir> { diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 8a672855989..963b324ca13 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -660,7 +660,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) { walk_list!(visitor, visit_expr, lower_bound); walk_list!(visitor, visit_expr, upper_bound); } - PatKind::Wild => (), + PatKind::Never | PatKind::Wild => (), PatKind::Slice(prepatterns, ref slice_pattern, postpatterns) => { walk_list!(visitor, visit_pat, prepatterns); walk_list!(visitor, visit_pat, slice_pattern); diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 94b182e09f6..b9a4806e6c2 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -26,12 +26,13 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{walk_generics, Visitor as _}; use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin}; -use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::{ - self, Const, GenericArgKind, GenericArgsRef, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, + self, Const, GenericArgKind, GenericArgsRef, IsSuggestable, ParamEnv, Ty, TyCtxt, + TypeVisitableExt, }; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; use rustc_span::edit_distance::find_best_match_for_name; @@ -39,8 +40,7 @@ use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::{sym, BytePos, Span, DUMMY_SP}; use rustc_target::spec::abi; use rustc_trait_selection::traits::wf::object_region_bounds; -use rustc_trait_selection::traits::{self, NormalizeExt, ObligationCtxt}; -use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; +use rustc_trait_selection::traits::{self, ObligationCtxt}; use std::fmt::Display; use std::slice; @@ -1606,133 +1606,110 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // FIXME(inherent_associated_types): Acquiring the ParamEnv this early leads to cycle errors // when inside of an ADT (#108491) or where clause. let param_env = tcx.param_env(block.owner); - let cause = ObligationCause::misc(span, block.owner.def_id); - let mut fulfillment_errors = Vec::new(); - let mut applicable_candidates: Vec<_> = infcx.probe(|_| { - // Regions are not considered during selection. - let self_ty = self_ty - .fold_with(&mut BoundVarEraser { tcx, universe: infcx.create_next_universe() }); - - struct BoundVarEraser<'tcx> { - tcx: TyCtxt<'tcx>, - universe: ty::UniverseIndex, - } - - // FIXME(non_lifetime_binders): Don't assign the same universe to each placeholder. - impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarEraser<'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { - self.tcx - } + let mut universes = if self_ty.has_escaping_bound_vars() { + vec![None; self_ty.outer_exclusive_binder().as_usize()] + } else { + vec![] + }; - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - // FIXME(@lcnr): This is broken, erasing bound regions - // impacts selection as it results in different types. - if r.is_bound() { self.tcx.lifetimes.re_erased } else { r } - } + let (impl_, (assoc_item, def_scope)) = + crate::traits::project::with_replaced_escaping_bound_vars( + infcx, + &mut universes, + self_ty, + |self_ty| { + self.select_inherent_assoc_type_candidates( + infcx, name, span, self_ty, param_env, candidates, + ) + }, + )?; + + self.check_assoc_ty(assoc_item, name, def_scope, block, span); + + // FIXME(fmease): Currently creating throwaway `parent_args` to please + // `create_args_for_associated_item`. Modify the latter instead (or sth. similar) to + // not require the parent args logic. + let parent_args = ty::GenericArgs::identity_for_item(tcx, impl_); + let args = self.create_args_for_associated_item(span, assoc_item, segment, parent_args); + let args = tcx.mk_args_from_iter( + std::iter::once(ty::GenericArg::from(self_ty)) + .chain(args.into_iter().skip(parent_args.len())), + ); - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match *ty.kind() { - ty::Bound(_, bv) => Ty::new_placeholder( - self.tcx, - ty::PlaceholderType { universe: self.universe, bound: bv }, - ), - _ => ty.super_fold_with(self), - } - } + let ty = Ty::new_alias(tcx, ty::Inherent, ty::AliasTy::new(tcx, assoc_item, args)); - fn fold_const( - &mut self, - ct: ty::Const<'tcx>, - ) -> <TyCtxt<'tcx> as rustc_type_ir::Interner>::Const { - assert!(!ct.ty().has_escaping_bound_vars()); - - match ct.kind() { - ty::ConstKind::Bound(_, bv) => ty::Const::new_placeholder( - self.tcx, - ty::PlaceholderConst { universe: self.universe, bound: bv }, - ct.ty(), - ), - _ => ct.super_fold_with(self), - } - } - } + Ok(Some((ty, assoc_item))) + } - let InferOk { value: self_ty, obligations } = - infcx.at(&cause, param_env).normalize(self_ty); + fn select_inherent_assoc_type_candidates( + &self, + infcx: &InferCtxt<'tcx>, + name: Ident, + span: Span, + self_ty: Ty<'tcx>, + param_env: ParamEnv<'tcx>, + candidates: Vec<(DefId, (DefId, DefId))>, + ) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> { + let tcx = self.tcx(); + let mut fulfillment_errors = Vec::new(); - candidates - .iter() - .copied() - .filter(|&(impl_, _)| { - infcx.probe(|_| { - let ocx = ObligationCtxt::new(infcx); - ocx.register_obligations(obligations.clone()); - - let impl_args = infcx.fresh_args_for_item(span, impl_); - let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args); - let impl_ty = ocx.normalize(&cause, param_env, impl_ty); - - // Check that the self types can be related. - if ocx.eq(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err() { - return false; - } + let applicable_candidates: Vec<_> = candidates + .iter() + .copied() + .filter(|&(impl_, _)| { + infcx.probe(|_| { + let ocx = ObligationCtxt::new(infcx); + let self_ty = ocx.normalize(&ObligationCause::dummy(), param_env, self_ty); + + let impl_args = infcx.fresh_args_for_item(span, impl_); + let impl_ty = tcx.type_of(impl_).instantiate(tcx, impl_args); + let impl_ty = ocx.normalize(&ObligationCause::dummy(), param_env, impl_ty); + + // Check that the self types can be related. + if ocx.eq(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err() { + return false; + } - // Check whether the impl imposes obligations we have to worry about. - let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args); - let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds); - let impl_obligations = traits::predicates_for_generics( - |_, _| cause.clone(), - param_env, - impl_bounds, - ); - ocx.register_obligations(impl_obligations); + // Check whether the impl imposes obligations we have to worry about. + let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_args); + let impl_bounds = + ocx.normalize(&ObligationCause::dummy(), param_env, impl_bounds); + let impl_obligations = traits::predicates_for_generics( + |_, _| ObligationCause::dummy(), + param_env, + impl_bounds, + ); + ocx.register_obligations(impl_obligations); - let mut errors = ocx.select_where_possible(); - if !errors.is_empty() { - fulfillment_errors.append(&mut errors); - return false; - } + let mut errors = ocx.select_where_possible(); + if !errors.is_empty() { + fulfillment_errors.append(&mut errors); + return false; + } - true - }) + true }) - .collect() - }); + }) + .collect(); - if applicable_candidates.len() > 1 { - return Err(self.complain_about_ambiguous_inherent_assoc_type( + match &applicable_candidates[..] { + &[] => Err(self.complain_about_inherent_assoc_type_not_found( name, - applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(), + self_ty, + candidates, + fulfillment_errors, span, - )); - } + )), - if let Some((impl_, (assoc_item, def_scope))) = applicable_candidates.pop() { - self.check_assoc_ty(assoc_item, name, def_scope, block, span); - - // FIXME(fmease): Currently creating throwaway `parent_args` to please - // `create_args_for_associated_item`. Modify the latter instead (or sth. similar) to - // not require the parent args logic. - let parent_args = ty::GenericArgs::identity_for_item(tcx, impl_); - let args = self.create_args_for_associated_item(span, assoc_item, segment, parent_args); - let args = tcx.mk_args_from_iter( - std::iter::once(ty::GenericArg::from(self_ty)) - .chain(args.into_iter().skip(parent_args.len())), - ); - - let ty = Ty::new_alias(tcx, ty::Inherent, ty::AliasTy::new(tcx, assoc_item, args)); + &[applicable_candidate] => Ok(applicable_candidate), - return Ok(Some((ty, assoc_item))); + &[_, ..] => Err(self.complain_about_ambiguous_inherent_assoc_type( + name, + applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(), + span, + )), } - - Err(self.complain_about_inherent_assoc_type_not_found( - name, - self_ty, - candidates, - fulfillment_errors, - span, - )) } fn lookup_assoc_ty( diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 9557568b387..37b308f9f88 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -662,6 +662,7 @@ fn resolve_local<'tcx>( PatKind::Ref(_, _) | PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), ..) | PatKind::Wild + | PatKind::Never | PatKind::Path(_) | PatKind::Lit(_) | PatKind::Range(_, _, _) => false, diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index e9e8c7fd4fc..b7e7d258a90 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1724,6 +1724,7 @@ impl<'a> State<'a> { // is that it doesn't matter match pat.kind { PatKind::Wild => self.word("_"), + PatKind::Never => self.word("!"), PatKind::Binding(BindingAnnotation(by_ref, mutbl), _, ident, sub) => { if by_ref == ByRef::Yes { self.word_nbsp("ref"); diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index a29d9c95e5e..e7cbbc71335 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -139,7 +139,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &cause, Some(arm.body), arm_ty, - |err| self.suggest_removing_semicolon_for_coerce(err, expr, arm_ty, prior_arm), + |err| { + self.explain_never_type_coerced_to_unit(err, arm, arm_ty, prior_arm, expr); + }, false, ); @@ -177,6 +179,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coercion.complete(self) } + fn explain_never_type_coerced_to_unit( + &self, + err: &mut Diagnostic, + arm: &hir::Arm<'tcx>, + arm_ty: Ty<'tcx>, + prior_arm: Option<(Option<hir::HirId>, Ty<'tcx>, Span)>, + expr: &hir::Expr<'tcx>, + ) { + if let hir::ExprKind::Block(block, _) = arm.body.kind + && let Some(expr) = block.expr + && let arm_tail_ty = self.node_ty(expr.hir_id) + && arm_tail_ty.is_never() + && !arm_ty.is_never() + { + err.span_label( + expr.span, + format!( + "this expression is of type `!`, but it is coerced to `{arm_ty}` due to its \ + surrounding expression", + ), + ); + self.suggest_mismatched_types_on_tail( + err, + expr, + arm_ty, + prior_arm.map_or(arm_tail_ty, |(_, ty, _)| ty), + expr.hir_id, + ); + } + self.suggest_removing_semicolon_for_coerce(err, expr, arm_ty, prior_arm) + } + fn suggest_removing_semicolon_for_coerce( &self, diag: &mut Diagnostic, diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index d40ac59baa4..d3abe0d7e1a 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -6,9 +6,8 @@ use crate::errors; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, StashKey}; use rustc_hir as hir; -use rustc_hir::def::{self, CtorKind, DefKind, Namespace, Res}; +use rustc_hir::def::{self, CtorKind, Namespace, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::HirId; use rustc_hir_analysis::autoderef::Autoderef; use rustc_infer::{ infer, @@ -373,7 +372,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let (fn_sig, def_id) = match *callee_ty.kind() { ty::FnDef(def_id, args) => { - self.enforce_context_effects(call_expr.hir_id, call_expr.span, def_id, args); + self.enforce_context_effects(call_expr.span, def_id, args); let fn_sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, args); // Unit testing: function items annotated with @@ -770,7 +769,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[tracing::instrument(level = "debug", skip(self, span))] pub(super) fn enforce_context_effects( &self, - call_expr_hir: HirId, span: Span, callee_did: DefId, callee_args: GenericArgsRef<'tcx>, @@ -781,38 +779,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let generics = tcx.generics_of(callee_did); let Some(host_effect_index) = generics.host_effect_index else { return }; - // if the callee does have the param, we need to equate the param to some const - // value no matter whether the effects feature is enabled in the local crate, - // because inference will fail if we don't. - let mut host_always_on = - !tcx.features().effects || tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you; - - // Compute the constness required by the context. - let context = tcx.hir().enclosing_body_owner(call_expr_hir); - let const_context = tcx.hir().body_const_context(context); - - let kind = tcx.def_kind(context.to_def_id()); - debug_assert_ne!(kind, DefKind::ConstParam); - - if tcx.has_attr(context.to_def_id(), sym::rustc_do_not_const_check) { - trace!("do not const check this context"); - host_always_on = true; - } - - let effect = match const_context { - _ if host_always_on => tcx.consts.true_, - Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { .. }) => { - tcx.consts.false_ - } - Some(hir::ConstContext::ConstFn) => { - let host_idx = tcx - .generics_of(context) - .host_effect_index - .expect("ConstContext::Maybe must have host effect param"); - ty::GenericArgs::identity_for_item(tcx, context).const_at(host_idx) - } - None => tcx.consts.true_, - }; + let effect = tcx.expected_const_effect_param_for_body(self.body_id); trace!(?effect, ?generics, ?callee_args); @@ -845,7 +812,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected, ); - self.write_method_call(call_expr.hir_id, method_callee); + self.write_method_call_and_enforce_effects(call_expr.hir_id, call_expr.span, method_callee); output_type } } @@ -895,7 +862,11 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> { adjustments.extend(autoref); fcx.apply_adjustments(self.callee_expr, adjustments); - fcx.write_method_call(self.call_expr.hir_id, method_callee); + fcx.write_method_call_and_enforce_effects( + self.call_expr.hir_id, + self.call_expr.span, + method_callee, + ); } None => { // This can happen if `#![no_core]` is used and the `fn/fn_mut/fn_once` diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index ae2a4a9504c..587038d57bd 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1715,6 +1715,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { // label pointing out the cause for the type coercion will be wrong // as prior return coercions would not be relevant (#57664). let fn_decl = if let (Some(expr), Some(blk_id)) = (expression, blk_id) { + fcx.suggest_missing_semicolon(&mut err, expr, expected, false); let pointing_at_return_type = fcx.suggest_mismatched_types_on_tail(&mut err, expr, expected, found, blk_id); if let (Some(cond_expr), true, false) = ( diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index aff1baa1960..74aec897f95 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -626,7 +626,7 @@ pub struct SuggestConvertViaMethod<'tcx> { pub span: Span, #[suggestion_part(code = "")] pub borrow_removal_span: Option<Span>, - pub sugg: &'static str, + pub sugg: String, pub expected: Ty<'tcx>, pub found: Ty<'tcx>, } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index f16269795e9..ed5ac2cea38 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -663,8 +663,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coerce.coerce_forced_unit( self, &cause, - |err| { - self.suggest_mismatched_types_on_tail(err, expr, ty, e_ty, target_id); + |mut err| { + self.suggest_missing_semicolon(&mut err, expr, e_ty, false); + self.suggest_mismatched_types_on_tail( + &mut err, expr, ty, e_ty, target_id, + ); let error = Some(Sorts(ExpectedFound { expected: ty, found: e_ty })); self.annotate_loop_expected_due_to_inference(err, expr, error); if let Some(val) = ty_kind_suggestion(ty) { @@ -1312,9 +1315,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(method) => { // We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to // trigger this codepath causing `structurally_resolve_type` to emit an error. - - self.enforce_context_effects(expr.hir_id, expr.span, method.def_id, method.args); - self.write_method_call(expr.hir_id, method); + self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method); Ok(method) } Err(error) => { diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index d7cf6dba9aa..9991050d7b2 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -401,12 +401,17 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { mc.cat_pattern(discr_place.clone(), pat, |place, pat| { match &pat.kind { PatKind::Binding(.., opt_sub_pat) => { - // If the opt_sub_pat is None, than the binding does not count as + // If the opt_sub_pat is None, then the binding does not count as // a wildcard for the purpose of borrowing discr. if opt_sub_pat.is_none() { needs_to_be_read = true; } } + PatKind::Never => { + // A never pattern reads the value. + // FIXME(never_patterns): does this do what I expect? + needs_to_be_read = true; + } PatKind::Path(qpath) => { // A `Path` pattern is just a name like `Foo`. This is either a // named constant or else it refers to an ADT variant diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index c5b4acd7c86..23b9ac4139d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -159,7 +159,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) { + pub fn write_method_call_and_enforce_effects( + &self, + hir_id: hir::HirId, + span: Span, + method: MethodCallee<'tcx>, + ) { + self.enforce_context_effects(span, method.def_id, method.args); self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id))); self.write_args(hir_id, method.args); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 87c93afe540..f1720dc98e6 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -282,12 +282,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: provided_arg.span, }); } else { - self.enforce_context_effects( - provided_arg.hir_id, - provided_arg.span, - def_id, - args, - ) + self.enforce_context_effects(provided_arg.span, def_id, args) } } } else { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 6660bea03d8..a904b419a94 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -72,7 +72,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { blk_id: hir::HirId, ) -> bool { let expr = expr.peel_drop_temps(); - self.suggest_missing_semicolon(err, expr, expected, false); let mut pointing_at_return_type = false; if let hir::ExprKind::Break(..) = expr.kind { // `break` type mismatches provide better context for tail `loop` expressions. @@ -443,12 +442,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected, ) }); + + let prefix_wrap = |sugg: &str| { + if let Some(name) = self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { + format!(": {}{}", name, sugg) + } else { + sugg.to_string() + } + }; + // FIXME: This could/should be extended to suggest `as_mut` and `as_deref_mut`, // but those checks need to be a bit more delicate and the benefit is diminishing. if self.can_eq(self.param_env, found_ty_inner, peeled) && error_tys_equate_as_ref { + let sugg = prefix_wrap(".as_ref()"); err.subdiagnostic(errors::SuggestConvertViaMethod { span: expr.span.shrink_to_hi(), - sugg: ".as_ref()", + sugg, expected, found, borrow_removal_span, @@ -459,9 +468,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && self.can_eq(self.param_env, deref_ty, peeled) && error_tys_equate_as_ref { + let sugg = prefix_wrap(".as_deref()"); err.subdiagnostic(errors::SuggestConvertViaMethod { span: expr.span.shrink_to_hi(), - sugg: ".as_deref()", + sugg, expected, found, borrow_removal_span, @@ -475,10 +485,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.can_eq(self.param_env, found, expected) }) { + let sugg = prefix_wrap(".map(|x| x.as_str())"); err.span_suggestion_verbose( expr.span.shrink_to_hi(), fluent::hir_typeck_convert_to_str, - ".map(|x| x.as_str())", + sugg, Applicability::MachineApplicable, ); return true; @@ -629,12 +640,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.help("use `Box::pin`"); } _ => { + let prefix = if let Some(name) = + self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) + { + format!("{}: ", name) + } else { + String::new() + }; + let suggestion = vec![ + (expr.span.shrink_to_lo(), format!("{prefix}Box::pin(")), + (expr.span.shrink_to_hi(), ")".to_string()), + ]; err.multipart_suggestion( "you need to pin and box this expression", - vec![ - (expr.span.shrink_to_lo(), "Box::pin(".to_string()), - (expr.span.shrink_to_hi(), ")".to_string()), - ], + suggestion, Applicability::MaybeIncorrect, ); } @@ -1215,7 +1234,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span = parent_callsite; } - let sugg = if expr.precedence().order() >= PREC_POSTFIX { + let mut sugg = if expr.precedence().order() >= PREC_POSTFIX { vec![(span.shrink_to_hi(), ".into()".to_owned())] } else { vec![ @@ -1223,6 +1242,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (span.shrink_to_hi(), ").into()".to_owned()), ] }; + if let Some(name) = self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { + sugg.insert(0, (expr.span.shrink_to_lo(), format!("{}: ", name))); + } diag.multipart_suggestion( format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"), sugg, @@ -1812,6 +1834,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ".expect(\"REASON\")", ) }; + + let sugg = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { + Some(ident) => format!(": {ident}{sugg}"), + None => sugg.to_string(), + }; + err.span_suggestion_verbose( expr.span.shrink_to_hi(), msg, diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index b4591e7f4f7..a22c95ac8ff 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -438,9 +438,13 @@ fn fatally_break_rust(tcx: TyCtxt<'_>) { } } +/// `expected` here is the expected number of explicit generic arguments on the trait. fn has_expected_num_generic_args(tcx: TyCtxt<'_>, trait_did: DefId, expected: usize) -> bool { let generics = tcx.generics_of(trait_did); - generics.count() == expected + if generics.has_self { 1 } else { 0 } + generics.count() + == expected + + if generics.has_self { 1 } else { 0 } + + if generics.host_effect_index.is_some() { 1 } else { 0 } } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index 94da4bfcdc4..0bcb7c7b5d7 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -766,6 +766,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { | PatKind::Binding(.., None) | PatKind::Lit(..) | PatKind::Range(..) + | PatKind::Never | PatKind::Wild => { // always ok } diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index f40406c6726..fcb3f8f47bd 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -291,7 +291,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .push(autoref); } } - self.write_method_call(expr.hir_id, method); + self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method); method.sig.output() } @@ -781,7 +781,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { assert!(op.is_by_value()); match self.lookup_op_method(operand_ty, None, Op::Unary(op, ex.span), expected) { Ok(method) => { - self.write_method_call(ex.hir_id, method); + self.write_method_call_and_enforce_effects(ex.hir_id, ex.span, method); method.sig.output() } Err(errors) => { diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index f11ffabf4d4..1ecf553d71d 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -178,6 +178,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = match pat.kind { PatKind::Wild => expected, + // FIXME(never_patterns): check the type is uninhabited. If that is not possible within + // typeck, do that in a later phase. + PatKind::Never => expected, PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti), PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti), PatKind::Binding(ba, var_id, _, sub) => { @@ -287,9 +290,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | PatKind::Box(_) | PatKind::Range(..) | PatKind::Slice(..) => AdjustMode::Peel, + // A never pattern behaves somewhat like a literal or unit variant. + PatKind::Never => AdjustMode::Peel, // String and byte-string literals result in types `&str` and `&[u8]` respectively. // All other literals result in non-reference types. - // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo {}`. + // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`. // // Call `resolve_vars_if_possible` here for inline const blocks. PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_expr(lt)).kind() { @@ -743,6 +748,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | PatKind::Slice(..) => "binding", PatKind::Wild + | PatKind::Never | PatKind::Binding(..) | PatKind::Path(..) | PatKind::Box(..) diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index f8ca3a4f3d7..79e41ef9227 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -38,7 +38,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span_bug!(expr.span, "input to deref is not a ref?"); } let ty = self.make_overloaded_place_return_type(method).ty; - self.write_method_call(expr.hir_id, method); + self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method); Some(ty) } @@ -179,7 +179,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } self.apply_adjustments(base_expr, adjustments); - self.write_method_call(expr.hir_id, method); + self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method); return Some((input_ty, self.make_overloaded_place_return_type(method).ty)); } @@ -404,7 +404,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None => return, }; debug!("convert_place_op_to_mutable: method={:?}", method); - self.write_method_call(expr.hir_id, method); + self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method); let ty::Ref(region, _, hir::Mutability::Mut) = method.sig.inputs()[0].kind() else { span_bug!(expr.span, "input to mutable place op is not a mut ref?"); diff --git a/compiler/rustc_index_macros/src/lib.rs b/compiler/rustc_index_macros/src/lib.rs index 13500949a22..ac374a41eb6 100644 --- a/compiler/rustc_index_macros/src/lib.rs +++ b/compiler/rustc_index_macros/src/lib.rs @@ -23,14 +23,14 @@ mod newtype; /// The impls provided by default are Clone, Copy, PartialEq, Eq, and Hash. /// /// Accepted attributes for customization: -/// - #[derive(HashStable_Generic)]/#[derive(HashStable)]: derives +/// - `#[derive(HashStable_Generic)]`/`#[derive(HashStable)]`: derives /// `HashStable`, as normal. -/// - #[encodable]: derives `Encodable`/`Decodable`. -/// - #[orderable]: derives `PartialOrd`/`Ord`, plus step-related methods. -/// - #[debug_format = "Foo({})"]: derives `Debug` with particular output. -/// - #[max = 0xFFFF_FFFD]: specifies the max value, which allows niche +/// - `#[encodable]`: derives `Encodable`/`Decodable`. +/// - `#[orderable]`: derives `PartialOrd`/`Ord`, plus step-related methods. +/// - `#[debug_format = "Foo({})"]`: derives `Debug` with particular output. +/// - `#[max = 0xFFFF_FFFD]`: specifies the max value, which allows niche /// optimizations. The default max value is 0xFFFF_FF00. -/// - #[gate_rustc_only]: makes parts of the generated code nightly-only. +/// - `#[gate_rustc_only]`: makes parts of the generated code nightly-only. #[proc_macro] #[cfg_attr( feature = "nightly", diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index c32c3aa6d29..09313cd9738 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -448,7 +448,11 @@ impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)), + values: PolyTraitRefs(ExpectedFound::new( + a_is_expected, + ty::Binder::dummy(a), + ty::Binder::dummy(b), + )), } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index bf9edb5b83d..3be23796550 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1667,9 +1667,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .report(diag); (false, Mismatch::Fixed("signature")) } - ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => { - (false, Mismatch::Fixed("trait")) - } + ValuePairs::PolyTraitRefs(_) => (false, Mismatch::Fixed("trait")), ValuePairs::Aliases(infer::ExpectedFound { expected, .. }) => { (false, Mismatch::Fixed(self.tcx.def_descr(expected.def_id))) } @@ -2219,18 +2217,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer::Aliases(exp_found) => self.expected_found_str(exp_found), infer::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found), infer::ExistentialProjection(exp_found) => self.expected_found_str(exp_found), - infer::TraitRefs(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(), - }; - match self.expected_found_str(pretty_exp_found) { - Some((expected, found, _, _)) if expected == found => { - self.expected_found_str(exp_found) - } - ret => ret, - } - } infer::PolyTraitRefs(exp_found) => { let pretty_exp_found = ty::error::ExpectedFound { expected: exp_found.expected.print_only_trait_path(), diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index c38e5b8cd09..d98ca995d71 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -197,11 +197,6 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { value_pairs: &ValuePairs<'tcx>, ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> { let (expected_args, found_args, trait_def_id) = match value_pairs { - ValuePairs::TraitRefs(ExpectedFound { expected, found }) - if expected.def_id == found.def_id => - { - (expected.args, found.args, expected.def_id) - } ValuePairs::PolyTraitRefs(ExpectedFound { expected, found }) if expected.def_id() == found.def_id() => { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 24c5d7bbe21..bb16d97eb85 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -384,7 +384,6 @@ pub enum ValuePairs<'tcx> { Regions(ExpectedFound<ty::Region<'tcx>>), Terms(ExpectedFound<ty::Term<'tcx>>), Aliases(ExpectedFound<ty::AliasTy<'tcx>>), - TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>), PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>), PolySigs(ExpectedFound<ty::PolyFnSig<'tcx>>), ExistentialTraitRef(ExpectedFound<ty::PolyExistentialTraitRef<'tcx>>), diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index 32966011932..b3cfd843ace 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -101,12 +101,19 @@ pub fn report_object_safety_error<'tcx>( to be resolvable dynamically; for more information visit \ <https://doc.rust-lang.org/reference/items/traits.html#object-safety>", ); + + // Only provide the help if its a local trait, otherwise it's not actionable. if trait_span.is_some() { let mut reported_violations: Vec<_> = reported_violations.into_iter().collect(); reported_violations.sort(); - for violation in reported_violations { - // Only provide the help if its a local trait, otherwise it's not actionable. - violation.solution(&mut err); + + let mut potential_solutions: Vec<_> = + reported_violations.into_iter().map(|violation| violation.solution()).collect(); + potential_solutions.sort(); + // Allows us to skip suggesting that the same item should be moved to another trait multiple times. + potential_solutions.dedup(); + for solution in potential_solutions { + solution.add_to(&mut err); } } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 91fd4b4a1d0..8a6d8d3d42e 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -1,7 +1,7 @@ use crate::util; use rustc_ast::token; -use rustc_ast::{self as ast, LitKind, MetaItemKind}; +use rustc_ast::{LitKind, MetaItemKind}; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::defer; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -15,9 +15,7 @@ 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; -use rustc_session::config::{ - self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName, OutputFilenames, -}; +use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName}; use rustc_session::filesearch::sysroot_candidates; use rustc_session::parse::ParseSess; use rustc_session::{lint, CompilerIO, EarlyErrorHandler, Session}; @@ -43,16 +41,6 @@ pub struct Compiler { pub(crate) override_queries: Option<fn(&Session, &mut Providers)>, } -impl Compiler { - pub fn build_output_filenames( - &self, - sess: &Session, - attrs: &[ast::Attribute], - ) -> OutputFilenames { - util::build_output_filenames(attrs, sess) - } -} - /// Converts strings provided as `--cfg [cfgspec]` into a `Cfg`. pub(crate) fn parse_cfg(handler: &EarlyErrorHandler, cfgs: Vec<String>) -> Cfg { cfgs.into_iter() diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 4648d83a6f3..88212d164bc 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -39,7 +39,7 @@ use std::any::Any; use std::ffi::OsString; use std::io::{self, BufWriter, Write}; use std::path::{Path, PathBuf}; -use std::sync::{Arc, LazyLock}; +use std::sync::LazyLock; use std::{env, fs, iter}; pub fn parse<'a>(sess: &'a Session) -> PResult<'a, ast::Crate> { @@ -553,13 +553,17 @@ fn resolver_for_lowering<'tcx>( tcx.arena.alloc(Steal::new((untracked_resolver_for_lowering, Lrc::new(krate)))) } -fn output_filenames(tcx: TyCtxt<'_>, (): ()) -> Arc<OutputFilenames> { +pub(crate) fn write_dep_info(tcx: TyCtxt<'_>) { + // Make sure name resolution and macro expansion is run for + // the side-effect of providing a complete set of all + // accessed files and env vars. + let _ = tcx.resolver_for_lowering(()); + let sess = tcx.sess; - let _timer = sess.timer("prepare_outputs"); - let (_, krate) = &*tcx.resolver_for_lowering(()).borrow(); + let _timer = sess.timer("write_dep_info"); let crate_name = tcx.crate_name(LOCAL_CRATE); - let outputs = util::build_output_filenames(&krate.attrs, sess); + let outputs = tcx.output_filenames(()); let output_paths = generated_output_paths(tcx, &outputs, sess.io.output_file.is_some(), crate_name); @@ -596,15 +600,12 @@ fn output_filenames(tcx: TyCtxt<'_>, (): ()) -> Arc<OutputFilenames> { } } } - - outputs.into() } pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| { let providers = &mut Providers::default(); providers.analysis = analysis; providers.hir_crate = rustc_ast_lowering::lower_to_hir; - providers.output_filenames = output_filenames; providers.resolver_for_lowering = resolver_for_lowering; providers.early_lint_checks = early_lint_checks; proc_macro_decls::provide(providers); diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index bee27dc2d69..e81c3f42a16 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -8,6 +8,7 @@ use rustc_codegen_ssa::CodegenResults; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, OnceLock, WorkerLocal}; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{StableCrateId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; use rustc_incremental::setup_dep_graph; @@ -85,7 +86,6 @@ pub struct Queries<'tcx> { hir_arena: WorkerLocal<rustc_hir::Arena<'tcx>>, parse: Query<ast::Crate>, - pre_configure: Query<(ast::Crate, ast::AttrVec)>, // This just points to what's in `gcx_cell`. gcx: Query<&'tcx GlobalCtxt<'tcx>>, } @@ -98,7 +98,6 @@ impl<'tcx> Queries<'tcx> { arena: WorkerLocal::new(|_| Arena::default()), hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()), parse: Default::default(), - pre_configure: Default::default(), gcx: Default::default(), } } @@ -113,12 +112,12 @@ impl<'tcx> Queries<'tcx> { }) } - #[deprecated = "pre_configure may be made private in the future. If you need it please open an issue with your use case."] - pub fn pre_configure(&self) -> Result<QueryResult<'_, (ast::Crate, ast::AttrVec)>> { - self.pre_configure.compute(|| { + pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> { + self.gcx.compute(|| { + let sess = &self.compiler.sess; + let mut krate = self.parse()?.steal(); - let sess = &self.compiler.sess; rustc_builtin_macros::cmdline_attrs::inject( &mut krate, &sess.parse_sess, @@ -127,15 +126,6 @@ impl<'tcx> Queries<'tcx> { let pre_configured_attrs = rustc_expand::config::pre_configure_attrs(sess, &krate.attrs); - Ok((krate, pre_configured_attrs)) - }) - } - - pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> { - self.gcx.compute(|| { - let sess = &self.compiler.sess; - #[allow(deprecated)] - let (krate, pre_configured_attrs) = self.pre_configure()?.steal(); // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches. let crate_name = find_crate_name(sess, &pre_configured_attrs); @@ -146,6 +136,7 @@ impl<'tcx> Queries<'tcx> { sess.opts.cg.metadata.clone(), sess.cfg_version, ); + let outputs = util::build_output_filenames(&pre_configured_attrs, sess); let dep_graph = setup_dep_graph(sess, crate_name, stable_crate_id)?; let cstore = FreezeLock::new(Box::new(CStore::new( @@ -180,11 +171,22 @@ impl<'tcx> Queries<'tcx> { crate_name, ))); feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs)))); + feed.output_filenames(Arc::new(outputs)); + + let feed = tcx.feed_local_def_id(CRATE_DEF_ID); + feed.def_kind(DefKind::Mod); }); Ok(qcx) }) } + pub fn write_dep_info(&'tcx self) -> Result<()> { + self.global_ctxt()?.enter(|tcx| { + passes::write_dep_info(tcx); + }); + Ok(()) + } + /// Check for the `#[rustc_error]` annotation, which forces an error in codegen. This is used /// to write UI tests that actually test that compilation succeeds without reporting /// an error. @@ -284,8 +286,13 @@ impl Linker { if sess.opts.unstable_opts.no_link { let rlink_file = self.output_filenames.with_extension(config::RLINK_EXT); - CodegenResults::serialize_rlink(sess, &rlink_file, &codegen_results) - .map_err(|error| sess.emit_fatal(FailedWritingFile { path: &rlink_file, error }))?; + CodegenResults::serialize_rlink( + sess, + &rlink_file, + &codegen_results, + &*self.output_filenames, + ) + .map_err(|error| sess.emit_fatal(FailedWritingFile { path: &rlink_file, error }))?; return Ok(()); } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index e6e132978ed..714af977fb5 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -5,10 +5,11 @@ use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig}; use rustc_session::config::{ build_configuration, build_session_options, rustc_optgroups, BranchProtection, CFGuard, Cfg, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs, - InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, LinkSelfContained, - LinkerPluginLto, LocationDetail, LtoCli, MirSpanview, OomStrategy, Options, OutFileName, - OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius, ProcMacroExecutionStrategy, Strip, - SwitchWithOptPath, SymbolManglingVersion, TraitSolver, WasiExecModel, + FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, + LinkSelfContained, LinkerPluginLto, LocationDetail, LtoCli, MirSpanview, OomStrategy, Options, + OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, Polonius, + ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, TraitSolver, + WasiExecModel, }; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; @@ -758,6 +759,7 @@ fn test_unstable_options_tracking_hash() { tracked!(flatten_format_args, false); tracked!(force_unstable_if_unmarked, true); tracked!(fuel, Some(("abc".to_string(), 99))); + tracked!(function_return, FunctionReturn::ThunkExtern); tracked!(function_sections, Some(false)); tracked!(human_readable_cgu_names, true); tracked!(incremental_ignore_spans, true); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index b3ab01a740a..c9c7ffdd937 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -126,11 +126,8 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( .deadlock_handler(|| { // On deadlock, creates a new thread and forwards information in thread // locals to it. The new thread runs the deadlock handler. - let query_map = FromDyn::from(tls::with(|tcx| { - QueryCtxt::new(tcx) - .try_collect_active_jobs() - .expect("active jobs shouldn't be locked in deadlock handler") - })); + let query_map = + FromDyn::from(tls::with(|tcx| QueryCtxt::new(tcx).collect_active_jobs())); let registry = rayon_core::Registry::current(); thread::spawn(move || deadlock(query_map.into_inner(), ®istry)); }); diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index b4535c72d6c..0a167b0893c 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -656,7 +656,7 @@ trait UnusedDelimLint { ) -> bool { if followed_by_else { match inner.kind { - ast::ExprKind::Binary(op, ..) if op.node.lazy() => return true, + ast::ExprKind::Binary(op, ..) if op.node.is_lazy() => return true, _ if classify::expr_trailing_brace(inner).is_some() => return true, _ => {} } @@ -1016,7 +1016,7 @@ impl UnusedDelimLint for UnusedParens { rustc_span::source_map::Spanned { node, .. }, _, _, - ) if node.lazy())) + ) if node.is_lazy())) { self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos, is_kw) } @@ -1154,7 +1154,7 @@ impl EarlyLintPass for UnusedParens { // Do not lint on `(..)` as that will result in the other arms being useless. Paren(_) // The other cases do not contain sub-patterns. - | Wild | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {}, + | Wild | Never | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {}, // These are list-like patterns; parens can always be removed. TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps { self.check_unused_parens_pat(cx, p, false, false, keep_space); diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h index 142384e6d0c..834120efa67 100644 --- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h +++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h @@ -42,11 +42,7 @@ #include "llvm/IR/IRPrintingPasses.h" #include "llvm/Linker/Linker.h" -#if LLVM_VERSION_GE(16, 0) #include "llvm/TargetParser/Triple.h" -#else -#include "llvm/ADT/Triple.h" -#endif extern "C" void LLVMRustSetLastError(const char *); @@ -93,6 +89,7 @@ enum LLVMRustAttribute { AllocatedPointer = 38, AllocAlign = 39, SanitizeSafeStack = 40, + FnRetThunkExtern = 41, }; typedef struct OpaqueRustString *RustStringRef; diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index d2cd79b456a..7f033265136 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -204,11 +204,7 @@ enum class LLVMRustCodeModel { None, }; -#if LLVM_VERSION_LT(16, 0) -static Optional<CodeModel::Model> -#else static std::optional<CodeModel::Model> -#endif fromRust(LLVMRustCodeModel Model) { switch (Model) { case LLVMRustCodeModel::Tiny: @@ -222,11 +218,7 @@ fromRust(LLVMRustCodeModel Model) { case LLVMRustCodeModel::Large: return CodeModel::Large; case LLVMRustCodeModel::None: -#if LLVM_VERSION_LT(16, 0) - return None; -#else return std::nullopt; -#endif default: report_fatal_error("Bad CodeModel."); } @@ -452,7 +444,6 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( if (OutputObjFile) { Options.ObjectFilenameForDebug = OutputObjFile; } -#if LLVM_VERSION_GE(16, 0) if (!strcmp("zlib", DebugInfoCompression) && llvm::compression::zlib::isAvailable()) { Options.CompressDebugSections = DebugCompressionType::Zlib; } else if (!strcmp("zstd", DebugInfoCompression) && llvm::compression::zstd::isAvailable()) { @@ -460,7 +451,6 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( } else if (!strcmp("none", DebugInfoCompression)) { Options.CompressDebugSections = DebugCompressionType::None; } -#endif Options.RelaxELFRelocations = RelaxELFRelocations; Options.UseInitArray = UseInitArray; @@ -734,22 +724,14 @@ LLVMRustOptimize( bool DebugPassManager = false; PassInstrumentationCallbacks PIC; -#if LLVM_VERSION_LT(16, 0) - StandardInstrumentations SI(DebugPassManager); -#else StandardInstrumentations SI(TheModule->getContext(), DebugPassManager); -#endif SI.registerCallbacks(PIC); if (LlvmSelfProfiler){ LLVMSelfProfileInitializeCallbacks(PIC,LlvmSelfProfiler,BeforePassCallback,AfterPassCallback); } -#if LLVM_VERSION_LT(16, 0) - Optional<PGOOptions> PGOOpt; -#else std::optional<PGOOptions> PGOOpt; -#endif #if LLVM_VERSION_GE(17, 0) auto FS = vfs::getRealFileSystem(); #endif @@ -882,12 +864,7 @@ LLVMRustOptimize( /*EagerChecks=*/true); OptimizerLastEPCallbacks.push_back( [Options](ModulePassManager &MPM, OptimizationLevel Level) { -#if LLVM_VERSION_LT(16, 0) - MPM.addPass(ModuleMemorySanitizerPass(Options)); - MPM.addPass(createModuleToFunctionPassAdaptor(MemorySanitizerPass(Options))); -#else MPM.addPass(MemorySanitizerPass(Options)); -#endif } ); } @@ -912,11 +889,7 @@ LLVMRustOptimize( /*UseAfterScope=*/true, AsanDetectStackUseAfterReturnMode::Runtime, }; -#if LLVM_VERSION_LT(16, 0) - MPM.addPass(ModuleAddressSanitizerPass(opts)); -#else MPM.addPass(AddressSanitizerPass(opts)); -#endif } ); } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 7ada2eff593..b227dd76f02 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -14,18 +14,13 @@ #include "llvm/Remarks/RemarkSerializer.h" #include "llvm/Remarks/RemarkFormat.h" #include "llvm/Support/ToolOutputFile.h" -#if LLVM_VERSION_GE(16, 0) #include "llvm/Support/ModRef.h" -#endif #include "llvm/Object/Archive.h" #include "llvm/Object/COFFImportFile.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Pass.h" #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/Support/Signals.h" -#if LLVM_VERSION_LT(16, 0) -#include "llvm/ADT/Optional.h" -#endif #include <iostream> @@ -283,6 +278,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) { return Attribute::AllocAlign; case SanitizeSafeStack: return Attribute::SafeStack; + case FnRetThunkExtern: + return Attribute::FnRetThunkExtern; } report_fatal_error("bad AttributeKind"); } @@ -347,13 +344,7 @@ extern "C" LLVMAttributeRef LLVMRustCreateUWTableAttr(LLVMContextRef C, bool Asy } extern "C" LLVMAttributeRef LLVMRustCreateAllocSizeAttr(LLVMContextRef C, uint32_t ElementSizeArg) { - return wrap(Attribute::getWithAllocSizeArgs(*unwrap(C), ElementSizeArg, -#if LLVM_VERSION_LT(16, 0) - None -#else - std::nullopt -#endif - )); + return wrap(Attribute::getWithAllocSizeArgs(*unwrap(C), ElementSizeArg, std::nullopt)); } // These values **must** match ffi::AllocKindFlags. @@ -416,7 +407,6 @@ enum class LLVMRustMemoryEffects { extern "C" LLVMAttributeRef LLVMRustCreateMemoryEffectsAttr(LLVMContextRef C, LLVMRustMemoryEffects Effects) { -#if LLVM_VERSION_GE(16, 0) switch (Effects) { case LLVMRustMemoryEffects::None: return wrap(Attribute::getWithMemoryEffects(*unwrap(C), MemoryEffects::none())); @@ -428,18 +418,6 @@ extern "C" LLVMAttributeRef LLVMRustCreateMemoryEffectsAttr(LLVMContextRef C, default: report_fatal_error("bad MemoryEffects."); } -#else - switch (Effects) { - case LLVMRustMemoryEffects::None: - return wrap(Attribute::get(*unwrap(C), Attribute::ReadNone)); - case LLVMRustMemoryEffects::ReadOnly: - return wrap(Attribute::get(*unwrap(C), Attribute::ReadOnly)); - case LLVMRustMemoryEffects::InaccessibleMemOnly: - return wrap(Attribute::get(*unwrap(C), Attribute::InaccessibleMemOnly)); - default: - report_fatal_error("bad MemoryEffects."); - } -#endif } // Enable a fast-math flag @@ -726,18 +704,10 @@ enum class LLVMRustChecksumKind { SHA256, }; -#if LLVM_VERSION_LT(16, 0) -static Optional<DIFile::ChecksumKind> fromRust(LLVMRustChecksumKind Kind) { -#else static std::optional<DIFile::ChecksumKind> fromRust(LLVMRustChecksumKind Kind) { -#endif switch (Kind) { case LLVMRustChecksumKind::None: -#if LLVM_VERSION_LT(16, 0) - return None; -#else return std::nullopt; -#endif case LLVMRustChecksumKind::MD5: return DIFile::ChecksumKind::CSK_MD5; case LLVMRustChecksumKind::SHA1: @@ -810,17 +780,8 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFile( const char *Directory, size_t DirectoryLen, LLVMRustChecksumKind CSKind, const char *Checksum, size_t ChecksumLen) { -#if LLVM_VERSION_LT(16, 0) - Optional<DIFile::ChecksumKind> llvmCSKind = fromRust(CSKind); -#else std::optional<DIFile::ChecksumKind> llvmCSKind = fromRust(CSKind); -#endif - -#if LLVM_VERSION_LT(16, 0) - Optional<DIFile::ChecksumInfo<StringRef>> CSInfo{}; -#else std::optional<DIFile::ChecksumInfo<StringRef>> CSInfo{}; -#endif if (llvmCSKind) CSInfo.emplace(*llvmCSKind, StringRef{Checksum, ChecksumLen}); return wrap(Builder->createFile(StringRef(Filename, FilenameLen), @@ -2053,17 +2014,9 @@ extern "C" bool LLVMRustIsNonGVFunctionPointerTy(LLVMValueRef V) { } extern "C" bool LLVMRustLLVMHasZlibCompressionForDebugSymbols() { -#if LLVM_VERSION_GE(16, 0) return llvm::compression::zlib::isAvailable(); -#else - return false; -#endif } extern "C" bool LLVMRustLLVMHasZstdCompressionForDebugSymbols() { -#if LLVM_VERSION_GE(16, 0) return llvm::compression::zstd::isAvailable(); -#else - return false; -#endif } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 7bf0da2f2f3..f407d30ac82 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -9,7 +9,7 @@ use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{par_for_each_in, try_par_for_each_in, DynSend, DynSync}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId, LOCAL_CRATE}; -use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; +use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::*; use rustc_index::Idx; @@ -168,98 +168,6 @@ impl<'hir> Map<'hir> { self.tcx.definitions_untracked().def_path_hash(def_id) } - /// Do not call this function directly. The query should be called. - pub(super) fn def_kind(self, local_def_id: LocalDefId) -> DefKind { - let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id); - let node = match self.find(hir_id) { - Some(node) => node, - None => match self.def_key(local_def_id).disambiguated_data.data { - // FIXME: Some anonymous constants produced by `#[rustc_legacy_const_generics]` - // do not have corresponding HIR nodes, but they are still anonymous constants. - DefPathData::AnonConst => return DefKind::AnonConst, - _ => bug!("no HIR node for def id {local_def_id:?}"), - }, - }; - match node { - Node::Item(item) => match item.kind { - ItemKind::Static(_, mt, _) => DefKind::Static(mt), - ItemKind::Const(..) => DefKind::Const, - ItemKind::Fn(..) => DefKind::Fn, - ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind), - ItemKind::Mod(..) => DefKind::Mod, - ItemKind::OpaqueTy(..) => DefKind::OpaqueTy, - ItemKind::TyAlias(..) => DefKind::TyAlias, - ItemKind::Enum(..) => DefKind::Enum, - ItemKind::Struct(..) => DefKind::Struct, - ItemKind::Union(..) => DefKind::Union, - ItemKind::Trait(..) => DefKind::Trait, - ItemKind::TraitAlias(..) => DefKind::TraitAlias, - ItemKind::ExternCrate(_) => DefKind::ExternCrate, - ItemKind::Use(..) => DefKind::Use, - ItemKind::ForeignMod { .. } => DefKind::ForeignMod, - ItemKind::GlobalAsm(..) => DefKind::GlobalAsm, - ItemKind::Impl(impl_) => DefKind::Impl { of_trait: impl_.of_trait.is_some() }, - }, - Node::ForeignItem(item) => match item.kind { - ForeignItemKind::Fn(..) => DefKind::Fn, - ForeignItemKind::Static(_, mt) => DefKind::Static(mt), - ForeignItemKind::Type => DefKind::ForeignTy, - }, - Node::TraitItem(item) => match item.kind { - TraitItemKind::Const(..) => DefKind::AssocConst, - TraitItemKind::Fn(..) => DefKind::AssocFn, - TraitItemKind::Type(..) => DefKind::AssocTy, - }, - Node::ImplItem(item) => match item.kind { - ImplItemKind::Const(..) => DefKind::AssocConst, - ImplItemKind::Fn(..) => DefKind::AssocFn, - ImplItemKind::Type(..) => DefKind::AssocTy, - }, - Node::Variant(_) => DefKind::Variant, - Node::Ctor(variant_data) => { - let ctor_of = match self.find_parent(hir_id) { - Some(Node::Item(..)) => def::CtorOf::Struct, - Some(Node::Variant(..)) => def::CtorOf::Variant, - _ => unreachable!(), - }; - match variant_data.ctor_kind() { - Some(kind) => DefKind::Ctor(ctor_of, kind), - None => bug!("constructor node without a constructor"), - } - } - Node::AnonConst(_) => DefKind::AnonConst, - Node::ConstBlock(_) => DefKind::InlineConst, - Node::Field(_) => DefKind::Field, - Node::Expr(expr) => match expr.kind { - ExprKind::Closure(_) => DefKind::Closure, - _ => bug!("def_kind: unsupported node: {}", self.node_to_string(hir_id)), - }, - Node::GenericParam(param) => match param.kind { - GenericParamKind::Lifetime { .. } => DefKind::LifetimeParam, - GenericParamKind::Type { .. } => DefKind::TyParam, - GenericParamKind::Const { .. } => DefKind::ConstParam, - }, - Node::Crate(_) => DefKind::Mod, - Node::Stmt(_) - | Node::PathSegment(_) - | Node::Ty(_) - | Node::TypeBinding(_) - | Node::Infer(_) - | Node::TraitRef(_) - | Node::Pat(_) - | Node::PatField(_) - | Node::ExprField(_) - | Node::Local(_) - | Node::Param(_) - | Node::Arm(_) - | Node::Lifetime(_) - | Node::Block(_) => span_bug!( - self.span(hir_id), - "unexpected node with def id {local_def_id:?}: {node:?}" - ), - } - } - /// Finds the id of the parent node to this one. /// /// If calling repeatedly and iterating over parents, prefer [`Map::parent_iter`]. diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index bf652fc277a..a16317a0c67 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -202,7 +202,6 @@ pub fn provide(providers: &mut Providers) { span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", def_id); } }; - providers.def_kind = |tcx, def_id| tcx.hir().def_kind(def_id); providers.all_local_trait_impls = |tcx, ()| &tcx.resolutions(()).trait_impls; providers.expn_that_defined = |tcx, id| tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root()); diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index ab8fef5129b..98642adc190 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -27,7 +27,7 @@ pub enum UnsafetyViolationKind { UnsafeFn, } -#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] +#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] pub enum UnsafetyViolationDetails { CallToUnsafeFunction, UseOfInlineAssembly, @@ -39,10 +39,17 @@ pub enum UnsafetyViolationDetails { AccessToUnionField, MutationOfLayoutConstrainedField, BorrowOfLayoutConstrainedField, - CallToFunctionWith, + CallToFunctionWith { + /// Target features enabled in callee's `#[target_feature]` but missing in + /// caller's `#[target_feature]`. + missing: Vec<Symbol>, + /// Target features in `missing` that are enabled at compile time + /// (e.g., with `-C target-feature`). + build_enabled: Vec<Symbol>, + }, } -#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] +#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] pub struct UnsafetyViolation { pub source_info: SourceInfo, pub lint_root: hir::HirId, diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 00c33113692..c48428c713c 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -635,7 +635,12 @@ impl<'tcx> Pat<'tcx> { use PatKind::*; match &self.kind { - Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } | Error(_) => {} + Wild + | Never + | Range(..) + | Binding { subpattern: None, .. } + | Constant { .. } + | Error(_) => {} AscribeUserType { subpattern, .. } | Binding { subpattern: Some(subpattern), .. } | Deref { subpattern } @@ -809,6 +814,9 @@ pub enum PatKind<'tcx> { pats: Box<[Box<Pat<'tcx>>]>, }, + /// A never pattern `!`. + Never, + /// An error has been encountered during lowering. We probably shouldn't report more lints /// related to this pattern. Error(ErrorGuaranteed), @@ -1069,6 +1077,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { match self.kind { PatKind::Wild => write!(f, "_"), + PatKind::Never => write!(f, "!"), PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{subpattern}: _"), PatKind::Binding { mutability, name, mode, ref subpattern, .. } => { let is_mut = match mode { diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 62c3ceeab8a..4943c11848b 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -227,7 +227,7 @@ pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<' is_primary: _, name: _, } => visitor.visit_pat(subpattern), - Binding { .. } | Wild | Error(_) => {} + Binding { .. } | Wild | Never | Error(_) => {} Variant { subpatterns, adt_def: _, args: _, variant_index: _ } | Leaf { subpatterns } => { for subpattern in subpatterns { visitor.visit_pat(&subpattern.pattern); diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 853eea1a609..5d0187a8598 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -832,50 +832,31 @@ impl ObjectSafetyViolation { } } - pub fn solution(&self, err: &mut Diagnostic) { + pub fn solution(&self) -> ObjectSafetyViolationSolution { match self { ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) - | ObjectSafetyViolation::SupertraitNonLifetimeBinder(..) => {} + | ObjectSafetyViolation::SupertraitNonLifetimeBinder(..) => { + ObjectSafetyViolationSolution::None + } ObjectSafetyViolation::Method( name, MethodViolationCode::StaticMethod(Some((add_self_sugg, make_sized_sugg))), _, - ) => { - err.span_suggestion( - add_self_sugg.1, - format!( - "consider turning `{name}` into a method by giving it a `&self` argument" - ), - add_self_sugg.0.to_string(), - Applicability::MaybeIncorrect, - ); - err.span_suggestion( - make_sized_sugg.1, - format!( - "alternatively, consider constraining `{name}` so it does not apply to \ - trait objects" - ), - make_sized_sugg.0.to_string(), - Applicability::MaybeIncorrect, - ); - } + ) => ObjectSafetyViolationSolution::AddSelfOrMakeSized { + name: *name, + add_self_sugg: add_self_sugg.clone(), + make_sized_sugg: make_sized_sugg.clone(), + }, ObjectSafetyViolation::Method( name, MethodViolationCode::UndispatchableReceiver(Some(span)), _, - ) => { - err.span_suggestion( - *span, - format!("consider changing method `{name}`'s `self` parameter to be `&self`"), - "&Self", - Applicability::MachineApplicable, - ); - } + ) => ObjectSafetyViolationSolution::ChangeToRefSelf(*name, *span), ObjectSafetyViolation::AssocConst(name, _) | ObjectSafetyViolation::GAT(name, _) | ObjectSafetyViolation::Method(name, ..) => { - err.help(format!("consider moving `{name}` to another trait")); + ObjectSafetyViolationSolution::MoveToAnotherTrait(*name) } } } @@ -899,6 +880,60 @@ impl ObjectSafetyViolation { } } +#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum ObjectSafetyViolationSolution { + None, + AddSelfOrMakeSized { + name: Symbol, + add_self_sugg: (String, Span), + make_sized_sugg: (String, Span), + }, + ChangeToRefSelf(Symbol, Span), + MoveToAnotherTrait(Symbol), +} + +impl ObjectSafetyViolationSolution { + pub fn add_to(self, err: &mut Diagnostic) { + match self { + ObjectSafetyViolationSolution::None => {} + ObjectSafetyViolationSolution::AddSelfOrMakeSized { + name, + add_self_sugg, + make_sized_sugg, + } => { + err.span_suggestion( + add_self_sugg.1, + format!( + "consider turning `{name}` into a method by giving it a `&self` argument" + ), + add_self_sugg.0, + Applicability::MaybeIncorrect, + ); + err.span_suggestion( + make_sized_sugg.1, + format!( + "alternatively, consider constraining `{name}` so it does not apply to \ + trait objects" + ), + make_sized_sugg.0, + Applicability::MaybeIncorrect, + ); + } + ObjectSafetyViolationSolution::ChangeToRefSelf(name, span) => { + err.span_suggestion( + span, + format!("consider changing method `{name}`'s `self` parameter to be `&self`"), + "&Self", + Applicability::MachineApplicable, + ); + } + ObjectSafetyViolationSolution::MoveToAnotherTrait(name) => { + err.help(format!("consider moving `{name}` to another trait")); + } + } + } +} + /// Reasons a method might not be object-safe. #[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)] pub enum MethodViolationCode { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 4ded61daa5c..bb02c6e0c78 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -501,6 +501,9 @@ impl<'tcx> TyCtxt<'tcx> { pub fn feed_local_crate(self) -> TyCtxtFeed<'tcx, CrateNum> { TyCtxtFeed { tcx: self, key: LOCAL_CRATE } } + pub fn feed_local_def_id(self, key: LocalDefId) -> TyCtxtFeed<'tcx, LocalDefId> { + TyCtxtFeed { tcx: self, key } + } /// In order to break cycles involving `AnonConst`, we need to set the expected type by side /// effect. However, we do not want this as a general capability, so this interface restricts @@ -973,6 +976,7 @@ impl<'tcx> TyCtxtAt<'tcx> { self, parent: LocalDefId, data: hir::definitions::DefPathData, + def_kind: DefKind, ) -> TyCtxtFeed<'tcx, LocalDefId> { // This function modifies `self.definitions` using a side-effect. // We need to ensure that these side effects are re-run by the incr. comp. engine. @@ -997,6 +1001,7 @@ impl<'tcx> TyCtxtAt<'tcx> { let key = self.untracked.definitions.write().create_def(parent, data); let feed = TyCtxtFeed { tcx: self.tcx, key }; + feed.def_kind(def_kind); feed.def_span(self.span); feed } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index da93f7f8ae6..24cba913bb8 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -202,9 +202,6 @@ pub struct ResolverAstLowering { pub def_id_to_node_id: IndexVec<LocalDefId, ast::NodeId>, pub trait_map: NodeMap<Vec<hir::TraitCandidate>>, - /// A small map keeping true kinds of built-in macros that appear to be fn-like on - /// the surface (`macro` items in libcore), but are actually attributes or derives. - pub builtin_macro_kinds: FxHashMap<LocalDefId, MacroKind>, /// List functions and methods for which lifetime elision was successful. pub lifetime_elision_allowed: FxHashSet<ast::NodeId>, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 2bde339ec77..d50743bc207 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -283,7 +283,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { /// from at least one local module, and returns `true`. If the crate defining `def_id` is /// declared with an `extern crate`, the path is guaranteed to use the `extern crate`. fn try_print_visible_def_path(&mut self, def_id: DefId) -> Result<bool, PrintError> { - if NO_VISIBLE_PATH.with(|flag| flag.get()) { + if with_no_visible_paths() { return Ok(false); } @@ -367,7 +367,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { /// Try to see if this path can be trimmed to a unique symbol name. fn try_print_trimmed_def_path(&mut self, def_id: DefId) -> Result<bool, PrintError> { - if FORCE_TRIMMED_PATH.with(|flag| flag.get()) { + if with_forced_trimmed_paths() { let trimmed = self.force_print_trimmed_def_path(def_id)?; if trimmed { return Ok(true); @@ -375,8 +375,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } if !self.tcx().sess.opts.unstable_opts.trim_diagnostic_paths || matches!(self.tcx().sess.opts.trimmed_def_paths, TrimmedDefPaths::Never) - || NO_TRIMMED_PATH.with(|flag| flag.get()) - || SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) + || with_no_trimmed_paths() + || with_crate_prefix() { return Ok(false); } @@ -861,7 +861,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { p!("@", print_def_path(did.to_def_id(), args)); } else { let span = self.tcx().def_span(did); - let preference = if FORCE_TRIMMED_PATH.with(|flag| flag.get()) { + let preference = if with_forced_trimmed_paths() { FileNameDisplayPreference::Short } else { FileNameDisplayPreference::Remapped @@ -1102,7 +1102,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { write!(self, "Sized")?; } - if !FORCE_TRIMMED_PATH.with(|flag| flag.get()) { + if !with_forced_trimmed_paths() { for re in lifetimes { write!(self, " + ")?; self.print_region(re)?; @@ -1886,7 +1886,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { // available, and filename/line-number is mostly uninteresting. let use_types = !def_id.is_local() || { // Otherwise, use filename/line-number if forced. - let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get()); + let force_no_types = with_forced_impl_filename_line(); !force_no_types }; @@ -1951,7 +1951,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { if cnum == LOCAL_CRATE { if self.tcx.sess.at_least_rust_2018() { // We add the `crate::` keyword on Rust 2018, only when desired. - if SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) { + if with_crate_prefix() { write!(self, "{}", kw::Crate)?; self.empty_path = false; } @@ -2154,7 +2154,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { return true; } - if FORCE_TRIMMED_PATH.with(|flag| flag.get()) { + if with_forced_trimmed_paths() { return false; } @@ -2437,7 +2437,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { } else { let tcx = self.tcx; - let trim_path = FORCE_TRIMMED_PATH.with(|flag| flag.get()); + let trim_path = with_forced_trimmed_paths(); // Closure used in `RegionFolder` to create names for anonymous late-bound // regions. We use two `DebruijnIndex`es (one for the currently folded // late-bound region and the other for the binder level) to determine diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index cbf1a9900d9..40d592ddef0 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -779,6 +779,57 @@ impl<'tcx> TyCtxt<'tcx> { // the language. || self.extern_crate(key.as_def_id()).is_some_and(|e| e.is_direct()) } + + pub fn expected_const_effect_param_for_body(self, def_id: LocalDefId) -> ty::Const<'tcx> { + // if the callee does have the param, we need to equate the param to some const + // value no matter whether the effects feature is enabled in the local crate, + // because inference will fail if we don't. + let mut host_always_on = + !self.features().effects || self.sess.opts.unstable_opts.unleash_the_miri_inside_of_you; + + // Compute the constness required by the context. + let const_context = self.hir().body_const_context(def_id); + + let kind = self.def_kind(def_id); + debug_assert_ne!(kind, DefKind::ConstParam); + + if self.has_attr(def_id, sym::rustc_do_not_const_check) { + trace!("do not const check this context"); + host_always_on = true; + } + + match const_context { + _ if host_always_on => self.consts.true_, + Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { .. }) => { + self.consts.false_ + } + Some(hir::ConstContext::ConstFn) => { + let host_idx = self + .generics_of(def_id) + .host_effect_index + .expect("ConstContext::Maybe must have host effect param"); + ty::GenericArgs::identity_for_item(self, def_id).const_at(host_idx) + } + None => self.consts.true_, + } + } + + /// Constructs generic args for an item, optionally appending a const effect param type + pub fn with_opt_const_effect_param( + self, + caller_def_id: LocalDefId, + callee_def_id: DefId, + args: impl IntoIterator<Item: Into<ty::GenericArg<'tcx>>>, + ) -> ty::GenericArgsRef<'tcx> { + let generics = self.generics_of(callee_def_id); + assert_eq!(generics.parent, None); + + let opt_const_param = generics.host_effect_index.is_some().then(|| { + ty::GenericArg::from(self.expected_const_effect_param_for_body(caller_def_id)) + }); + + self.mk_args_from_iter(args.into_iter().map(|arg| arg.into()).chain(opt_const_param)) + } } struct OpaqueTypeExpander<'tcx> { diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 7dd0e7d4b92..c8d6c2114e9 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -30,12 +30,32 @@ mir_build_borrow_of_moved_value = borrow of moved value mir_build_call_to_fn_with_requires_unsafe = call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block - .note = can only be called if the required target features are available + .help = in order for the call to be safe, the context requires the following additional target {$missing_target_features_count -> + [1] feature + *[count] features + }: {$missing_target_features} + .note = the {$build_target_features} target {$build_target_features_count -> + [1] feature + *[count] features + } being enabled in the build configuration does not remove the requirement to list {$build_target_features_count -> + [1] it + *[count] them + } in `#[target_feature]` .label = call to function with `#[target_feature]` mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe function or block - .note = can only be called if the required target features are available + .help = in order for the call to be safe, the context requires the following additional target {$missing_target_features_count -> + [1] feature + *[count] features + }: {$missing_target_features} + .note = the {$build_target_features} target {$build_target_features_count -> + [1] feature + *[count] features + } being enabled in the build configuration does not remove the requirement to list {$build_target_features_count -> + [1] it + *[count] them + } in `#[target_feature]` .label = call to function with `#[target_feature]` mir_build_call_to_unsafe_fn_requires_unsafe = @@ -330,7 +350,17 @@ mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_uns mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe = call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block (error E0133) - .note = can only be called if the required target features are available + .help = in order for the call to be safe, the context requires the following additional target {$missing_target_features_count -> + [1] feature + *[count] features + }: {$missing_target_features} + .note = the {$build_target_features} target {$build_target_features_count -> + [1] feature + *[count] features + } being enabled in the build configuration does not remove the requirement to list {$build_target_features_count -> + [1] it + *[count] them + } in `#[target_feature]` .label = call to function with `#[target_feature]` mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe = diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 83686667a4a..90f950d59d5 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -827,6 +827,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Constant { .. } | PatKind::Range { .. } | PatKind::Wild + | PatKind::Never | PatKind::Error(_) => {} PatKind::Deref { ref subpattern } => { diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 8a6cb26242a..a7f6f4873e3 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -194,6 +194,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Ok(()) } + PatKind::Never => { + // A never pattern acts like a load from the place. + // FIXME(never_patterns): load from the place + Ok(()) + } + PatKind::Constant { .. } => { // FIXME normalize patterns when possible Err(match_pair) diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 6bd60972c8b..642ac9b49c8 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -75,6 +75,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | PatKind::Array { .. } | PatKind::Wild | PatKind::Binding { .. } + | PatKind::Never | PatKind::Leaf { .. } | PatKind::Deref { .. } | PatKind::Error(_) => self.error_simplifiable(match_pair), @@ -107,6 +108,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Slice { .. } | PatKind::Array { .. } | PatKind::Wild + | PatKind::Never | PatKind::Or { .. } | PatKind::Binding { .. } | PatKind::AscribeUserType { .. } @@ -494,7 +496,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span)); - let method = trait_method(self.tcx, eq_def_id, sym::eq, [ty, ty]); + let method = trait_method( + self.tcx, + eq_def_id, + sym::eq, + self.tcx.with_opt_const_effect_param(self.def_id, eq_def_id, [ty, ty]), + ); let bool_ty = self.tcx.types.bool; let eq_result = self.temp(bool_ty, source_info.span); diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index bbaa02233e5..c17fdf71b55 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -1,7 +1,10 @@ +use std::borrow::Cow; + use crate::build::ExprCategory; use crate::errors::*; use rustc_middle::thir::visit::{self, Visitor}; +use rustc_errors::DiagnosticArgValue; use rustc_hir as hir; use rustc_middle::mir::BorrowKind; use rustc_middle::thir::*; @@ -247,8 +250,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { self.requires_unsafe(pat.span, AccessToUnionField); return; // we can return here since this already requires unsafe } - // wildcard doesn't take anything + // wildcard/never don't take anything PatKind::Wild | + PatKind::Never | // these just wrap other patterns PatKind::Or { .. } | PatKind::InlineConstant { .. } | @@ -392,15 +396,29 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { // the call requires `unsafe`. Don't check this on wasm // targets, though. For more information on wasm see the // is_like_wasm check in hir_analysis/src/collect.rs + let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features; if !self.tcx.sess.target.options.is_like_wasm - && !self - .tcx - .codegen_fn_attrs(func_did) - .target_features + && !callee_features .iter() .all(|feature| self.body_target_features.contains(feature)) { - self.requires_unsafe(expr.span, CallToFunctionWith(func_did)); + let missing: Vec<_> = callee_features + .iter() + .copied() + .filter(|feature| !self.body_target_features.contains(feature)) + .collect(); + let build_enabled = self + .tcx + .sess + .target_features + .iter() + .copied() + .filter(|feature| missing.contains(feature)) + .collect(); + self.requires_unsafe( + expr.span, + CallToFunctionWith { function: func_did, missing, build_enabled }, + ); } } } @@ -526,7 +544,7 @@ struct UnusedUnsafeWarning { enclosing_unsafe: Option<UnusedUnsafeEnclosing>, } -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, PartialEq)] enum UnsafeOpKind { CallToUnsafeFunction(Option<DefId>), UseOfInlineAssembly, @@ -537,7 +555,15 @@ enum UnsafeOpKind { AccessToUnionField, MutationOfLayoutConstrainedField, BorrowOfLayoutConstrainedField, - CallToFunctionWith(DefId), + CallToFunctionWith { + function: DefId, + /// Target features enabled in callee's `#[target_feature]` but missing in + /// caller's `#[target_feature]`. + missing: Vec<Symbol>, + /// Target features in `missing` that are enabled at compile time + /// (e.g., with `-C target-feature`). + build_enabled: Vec<Symbol>, + }, } use UnsafeOpKind::*; @@ -658,13 +684,22 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), - CallToFunctionWith(did) => tcx.emit_spanned_lint( + CallToFunctionWith { function, missing, build_enabled } => tcx.emit_spanned_lint( UNSAFE_OP_IN_UNSAFE_FN, hir_id, span, UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe { span, - function: &with_no_trimmed_paths!(tcx.def_path_str(*did)), + function: &with_no_trimmed_paths!(tcx.def_path_str(*function)), + missing_target_features: DiagnosticArgValue::StrListSepByAnd( + missing.iter().map(|feature| Cow::from(feature.as_str())).collect(), + ), + missing_target_features_count: missing.len(), + note: if build_enabled.is_empty() { None } else { Some(()) }, + build_target_features: DiagnosticArgValue::StrListSepByAnd( + build_enabled.iter().map(|feature| Cow::from(feature.as_str())).collect(), + ), + build_target_features_count: build_enabled.len(), unsafe_not_inherited_note, }, ), @@ -821,18 +856,38 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }); } - CallToFunctionWith(did) if unsafe_op_in_unsafe_fn_allowed => { + CallToFunctionWith { function, missing, build_enabled } + if unsafe_op_in_unsafe_fn_allowed => + { tcx.sess.emit_err(CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span, + missing_target_features: DiagnosticArgValue::StrListSepByAnd( + missing.iter().map(|feature| Cow::from(feature.as_str())).collect(), + ), + missing_target_features_count: missing.len(), + note: if build_enabled.is_empty() { None } else { Some(()) }, + build_target_features: DiagnosticArgValue::StrListSepByAnd( + build_enabled.iter().map(|feature| Cow::from(feature.as_str())).collect(), + ), + build_target_features_count: build_enabled.len(), unsafe_not_inherited_note, - function: &tcx.def_path_str(*did), + function: &tcx.def_path_str(*function), }); } - CallToFunctionWith(did) => { + CallToFunctionWith { function, missing, build_enabled } => { tcx.sess.emit_err(CallToFunctionWithRequiresUnsafe { span, + missing_target_features: DiagnosticArgValue::StrListSepByAnd( + missing.iter().map(|feature| Cow::from(feature.as_str())).collect(), + ), + missing_target_features_count: missing.len(), + note: if build_enabled.is_empty() { None } else { Some(()) }, + build_target_features: DiagnosticArgValue::StrListSepByAnd( + build_enabled.iter().map(|feature| Cow::from(feature.as_str())).collect(), + ), + build_target_features_count: build_enabled.len(), unsafe_not_inherited_note, - function: &tcx.def_path_str(*did), + function: &tcx.def_path_str(*function), }); } } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 418f9bb9de9..8d2a559e73c 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -2,6 +2,7 @@ use crate::{ fluent_generated as fluent, thir::pattern::{deconstruct_pat::WitnessPat, MatchCheckCtxt}, }; +use rustc_errors::DiagnosticArgValue; use rustc_errors::{ error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, MultiSpan, SubdiagnosticMessage, @@ -124,11 +125,17 @@ pub struct UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe { #[derive(LintDiagnostic)] #[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe)] -#[note] +#[help] pub struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe<'a> { #[label] pub span: Span, pub function: &'a str, + pub missing_target_features: DiagnosticArgValue<'a>, + pub missing_target_features_count: usize, + #[note] + pub note: Option<()>, + pub build_target_features: DiagnosticArgValue<'a>, + pub build_target_features_count: usize, #[subdiagnostic] pub unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, } @@ -369,24 +376,36 @@ pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed #[derive(Diagnostic)] #[diag(mir_build_call_to_fn_with_requires_unsafe, code = "E0133")] -#[note] +#[help] pub struct CallToFunctionWithRequiresUnsafe<'a> { #[primary_span] #[label] pub span: Span, pub function: &'a str, + pub missing_target_features: DiagnosticArgValue<'a>, + pub missing_target_features_count: usize, + #[note] + pub note: Option<()>, + pub build_target_features: DiagnosticArgValue<'a>, + pub build_target_features_count: usize, #[subdiagnostic] pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] #[diag(mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")] -#[note] +#[help] pub struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> { #[primary_span] #[label] pub span: Span, pub function: &'a str, + pub missing_target_features: DiagnosticArgValue<'a>, + pub missing_target_features_count: usize, + #[note] + pub note: Option<()>, + pub build_target_features: DiagnosticArgValue<'a>, + pub build_target_features_count: usize, #[subdiagnostic] pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 440767927d7..4e2c932d6c6 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -258,18 +258,26 @@ impl<'tcx> ConstToPat<'tcx> { #[instrument(level = "trace", skip(self), ret)] fn type_has_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool { + let tcx = self.tcx(); // double-check there even *is* a semantic `PartialEq` to dispatch to. // // (If there isn't, then we can safely issue a hard // error, because that's never worked, due to compiler // using `PartialEq::eq` in this scenario in the past.) - let partial_eq_trait_id = - self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span)); + let partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::PartialEq, Some(self.span)); let partial_eq_obligation = Obligation::new( - self.tcx(), + tcx, ObligationCause::dummy(), self.param_env, - ty::TraitRef::new(self.tcx(), partial_eq_trait_id, [ty, ty]), + ty::TraitRef::new( + tcx, + partial_eq_trait_id, + tcx.with_opt_const_effect_param( + tcx.hir().enclosing_body_owner(self.id), + partial_eq_trait_id, + [ty, ty], + ), + ), ); // This *could* accept a type that isn't actually `PartialEq`, because region bounds get 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 8ddc6c924e2..31114190f07 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -1557,6 +1557,12 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { let pats = expand_or_pat(pat); fields = Fields::from_iter(cx, pats.into_iter().map(mkpat)); } + PatKind::Never => { + // FIXME(never_patterns): handle `!` in exhaustiveness. This is a sane default + // in the meantime. + ctor = Wildcard; + fields = Fields::empty(); + } PatKind::Error(_) => { ctor = Opaque(OpaqueId::new()); fields = Fields::empty(); diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 8b2a96cff41..5edb2054fd4 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -251,6 +251,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let kind = match pat.kind { hir::PatKind::Wild => PatKind::Wild, + hir::PatKind::Never => PatKind::Never, + hir::PatKind::Lit(value) => self.lower_lit(value), hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => { diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index c3b2309b7cd..547da7e7007 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -31,8 +31,8 @@ const INDENT: &str = " "; macro_rules! print_indented { ($writer:ident, $s:expr, $indent_lvl:expr) => { - let indent = (0..$indent_lvl).map(|_| INDENT).collect::<Vec<_>>().concat(); - writeln!($writer, "{}{}", indent, $s).expect("unable to write to ThirPrinter"); + $writer.indent($indent_lvl); + writeln!($writer, "{}", $s).expect("unable to write to ThirPrinter"); }; } @@ -48,6 +48,12 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { Self { thir, fmt: String::new() } } + fn indent(&mut self, level: usize) { + for _ in 0..level { + self.fmt.push_str(INDENT); + } + } + fn print(&mut self) { print_indented!(self, "params: [", 0); for param in self.thir.params.iter() { @@ -636,6 +642,9 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { PatKind::Wild => { print_indented!(self, "Wild", depth_lvl + 1); } + PatKind::Never => { + print_indented!(self, "Never", depth_lvl + 1); + } PatKind::AscribeUserType { ascription, subpattern } => { print_indented!(self, "AscribeUserType: {", depth_lvl + 1); print_indented!(self, format!("ascription: {:?}", ascription), depth_lvl + 2); diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index 5a99afc45b0..b8dbdf18db3 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -42,8 +42,19 @@ mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in } .not_inherited = items do not inherit unsafety from separate enclosing items +mir_transform_target_feature_call_help = in order for the call to be safe, the context requires the following additional target {$missing_target_features_count -> + [1] feature + *[count] features + }: {$missing_target_features} + mir_transform_target_feature_call_label = call to function with `#[target_feature]` -mir_transform_target_feature_call_note = can only be called if the required target features are available +mir_transform_target_feature_call_note = the {$build_target_features} target {$build_target_features_count -> + [1] feature + *[count] features + } being enabled in the build configuration does not remove the requirement to list {$build_target_features_count -> + [1] it + *[count] them + } in `#[target_feature]` mir_transform_unaligned_packed_ref = reference to packed field is unaligned .note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index 85447887cb0..84e7362c3d0 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -287,19 +287,20 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> { .safety; match safety { // `unsafe` blocks are required in safe code - Safety::Safe => violations.into_iter().for_each(|&violation| { + Safety::Safe => violations.into_iter().for_each(|violation| { match violation.kind { UnsafetyViolationKind::General => {} UnsafetyViolationKind::UnsafeFn => { bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context") } } - if !self.violations.contains(&violation) { - self.violations.push(violation) + if !self.violations.contains(violation) { + self.violations.push(violation.clone()) } }), // With the RFC 2585, no longer allow `unsafe` operations in `unsafe fn`s - Safety::FnUnsafe => violations.into_iter().for_each(|&(mut violation)| { + Safety::FnUnsafe => violations.into_iter().for_each(|violation| { + let mut violation = violation.clone(); violation.kind = UnsafetyViolationKind::UnsafeFn; if !self.violations.contains(&violation) { self.violations.push(violation) @@ -367,9 +368,22 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> { // Is `callee_features` a subset of `calling_features`? if !callee_features.iter().all(|feature| self_features.contains(feature)) { + let missing: Vec<_> = callee_features + .iter() + .copied() + .filter(|feature| !self_features.contains(feature)) + .collect(); + let build_enabled = self + .tcx + .sess + .target_features + .iter() + .copied() + .filter(|feature| missing.contains(feature)) + .collect(); self.require_unsafe( UnsafetyViolationKind::General, - UnsafetyViolationDetails::CallToFunctionWith, + UnsafetyViolationDetails::CallToFunctionWith { missing, build_enabled }, ) } } @@ -385,7 +399,7 @@ pub(crate) fn provide(providers: &mut Providers) { enum Context { Safe, /// in an `unsafe fn` - UnsafeFn(HirId), + UnsafeFn, /// in a *used* `unsafe` block /// (i.e. a block without unused-unsafe warning) UnsafeBlock(HirId), @@ -407,7 +421,7 @@ impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> { }; let unused_unsafe = match (self.context, used) { (_, false) => UnusedUnsafe::Unused, - (Context::Safe, true) | (Context::UnsafeFn(_), true) => { + (Context::Safe, true) | (Context::UnsafeFn, true) => { let previous_context = self.context; self.context = Context::UnsafeBlock(block.hir_id); intravisit::walk_block(self, block); @@ -454,7 +468,7 @@ fn check_unused_unsafe( let body = tcx.hir().body(body_id); let hir_id = tcx.local_def_id_to_hir_id(def_id); let context = match tcx.hir().fn_sig_by_hir_id(hir_id) { - Some(sig) if sig.header.unsafety == hir::Unsafety::Unsafe => Context::UnsafeFn(hir_id), + Some(sig) if sig.header.unsafety == hir::Unsafety::Unsafe => Context::UnsafeFn, _ => Context::Safe, }; @@ -528,8 +542,9 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) { // Only suggest wrapping the entire function body in an unsafe block once let mut suggest_unsafe_block = true; - for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() { - let details = errors::RequiresUnsafeDetail { violation: details, span: source_info.span }; + for &UnsafetyViolation { source_info, lint_root, kind, ref details } in violations.iter() { + let details = + errors::RequiresUnsafeDetail { violation: details.clone(), span: source_info.span }; match kind { UnsafetyViolationKind::General => { diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 9a16003bdc9..b96125de95e 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -439,6 +439,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // FIXME we need to revisit this for #67176 if rvalue.has_param() { + trace!("skipping, has param"); return None; } if !rvalue @@ -707,7 +708,11 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { self.super_assign(place, rvalue, location); - let Some(()) = self.check_rvalue(rvalue) else { return }; + let Some(()) = self.check_rvalue(rvalue) else { + trace!("rvalue check failed, removing const"); + Self::remove_const(&mut self.ecx, place.local); + return; + }; match self.ecx.machine.can_const_prop[place.local] { // Do nothing if the place is indirect. diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 1cb1a9886a0..d626fed3275 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -51,7 +51,6 @@ //! Otherwise it drops all the values in scope at the last suspension point. use crate::abort_unwinding_calls; -use crate::add_call_guards; use crate::deref_separator::deref_finder; use crate::errors; use crate::pass_manager as pm; @@ -1168,18 +1167,9 @@ fn create_coroutine_drop_shim<'tcx>( simplify::remove_dead_blocks(&mut body); // Update the body's def to become the drop glue. - // This needs to be updated before the AbortUnwindingCalls pass. let coroutine_instance = body.source.instance; let drop_in_place = tcx.require_lang_item(LangItem::DropInPlace, None); let drop_instance = InstanceDef::DropGlue(drop_in_place, Some(coroutine_ty)); - body.source.instance = drop_instance; - - pm::run_passes_no_validate( - tcx, - &mut body, - &[&abort_unwinding_calls::AbortUnwindingCalls, &add_call_guards::CriticalCallEdges], - None, - ); // Temporary change MirSource to coroutine's instance so that dump_mir produces more sensible // filename. diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 5879a803946..3a5270f105a 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -1,6 +1,8 @@ +use std::borrow::Cow; + use rustc_errors::{ - Applicability, DecorateLint, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Handler, - IntoDiagnostic, + Applicability, DecorateLint, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, + EmissionGuarantee, Handler, IntoDiagnostic, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails}; @@ -9,6 +11,8 @@ use rustc_session::lint::{self, Lint}; use rustc_span::def_id::DefId; use rustc_span::Span; +use crate::fluent_generated as fluent; + #[derive(LintDiagnostic)] pub(crate) enum ConstMutate { #[diag(mir_transform_const_modify)] @@ -61,72 +65,105 @@ pub(crate) struct RequiresUnsafe { impl<'sess, G: EmissionGuarantee> IntoDiagnostic<'sess, G> for RequiresUnsafe { #[track_caller] fn into_diagnostic(self, handler: &'sess Handler) -> DiagnosticBuilder<'sess, G> { - let mut diag = - handler.struct_diagnostic(crate::fluent_generated::mir_transform_requires_unsafe); + 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); diag.span_label(self.span, self.details.label()); - diag.note(self.details.note()); let desc = handler.eagerly_translate_to_string(self.details.label(), [].into_iter()); diag.set_arg("details", desc); diag.set_arg("op_in_unsafe_fn_allowed", self.op_in_unsafe_fn_allowed); + self.details.add_subdiagnostics(&mut diag); if let Some(sp) = self.enclosing { - diag.span_label(sp, crate::fluent_generated::mir_transform_not_inherited); + diag.span_label(sp, fluent::mir_transform_not_inherited); } diag } } -#[derive(Copy, Clone)] +#[derive(Clone)] pub(crate) struct RequiresUnsafeDetail { pub span: Span, pub violation: UnsafetyViolationDetails, } impl RequiresUnsafeDetail { - fn note(self) -> DiagnosticMessage { + fn add_subdiagnostics<G: EmissionGuarantee>(&self, diag: &mut DiagnosticBuilder<'_, G>) { use UnsafetyViolationDetails::*; match self.violation { - CallToUnsafeFunction => crate::fluent_generated::mir_transform_call_to_unsafe_note, - UseOfInlineAssembly => crate::fluent_generated::mir_transform_use_of_asm_note, + CallToUnsafeFunction => { + diag.note(fluent::mir_transform_call_to_unsafe_note); + } + UseOfInlineAssembly => { + diag.note(fluent::mir_transform_use_of_asm_note); + } InitializingTypeWith => { - crate::fluent_generated::mir_transform_initializing_valid_range_note + diag.note(fluent::mir_transform_initializing_valid_range_note); + } + CastOfPointerToInt => { + diag.note(fluent::mir_transform_const_ptr2int_note); + } + UseOfMutableStatic => { + diag.note(fluent::mir_transform_use_of_static_mut_note); + } + UseOfExternStatic => { + diag.note(fluent::mir_transform_use_of_extern_static_note); + } + DerefOfRawPointer => { + diag.note(fluent::mir_transform_deref_ptr_note); + } + AccessToUnionField => { + diag.note(fluent::mir_transform_union_access_note); } - CastOfPointerToInt => crate::fluent_generated::mir_transform_const_ptr2int_note, - UseOfMutableStatic => crate::fluent_generated::mir_transform_use_of_static_mut_note, - UseOfExternStatic => crate::fluent_generated::mir_transform_use_of_extern_static_note, - DerefOfRawPointer => crate::fluent_generated::mir_transform_deref_ptr_note, - AccessToUnionField => crate::fluent_generated::mir_transform_union_access_note, MutationOfLayoutConstrainedField => { - crate::fluent_generated::mir_transform_mutation_layout_constrained_note + diag.note(fluent::mir_transform_mutation_layout_constrained_note); } BorrowOfLayoutConstrainedField => { - crate::fluent_generated::mir_transform_mutation_layout_constrained_borrow_note + diag.note(fluent::mir_transform_mutation_layout_constrained_borrow_note); + } + CallToFunctionWith { ref missing, ref build_enabled } => { + diag.help(fluent::mir_transform_target_feature_call_help); + diag.set_arg( + "missing_target_features", + DiagnosticArgValue::StrListSepByAnd( + missing.iter().map(|feature| Cow::from(feature.as_str())).collect(), + ), + ); + diag.set_arg("missing_target_features_count", missing.len()); + if !build_enabled.is_empty() { + diag.note(fluent::mir_transform_target_feature_call_note); + diag.set_arg( + "build_target_features", + DiagnosticArgValue::StrListSepByAnd( + build_enabled + .iter() + .map(|feature| Cow::from(feature.as_str())) + .collect(), + ), + ); + diag.set_arg("build_target_features_count", build_enabled.len()); + } } - CallToFunctionWith => crate::fluent_generated::mir_transform_target_feature_call_note, } } - fn label(self) -> DiagnosticMessage { + fn label(&self) -> DiagnosticMessage { use UnsafetyViolationDetails::*; match self.violation { - CallToUnsafeFunction => crate::fluent_generated::mir_transform_call_to_unsafe_label, - UseOfInlineAssembly => crate::fluent_generated::mir_transform_use_of_asm_label, - InitializingTypeWith => { - crate::fluent_generated::mir_transform_initializing_valid_range_label - } - CastOfPointerToInt => crate::fluent_generated::mir_transform_const_ptr2int_label, - UseOfMutableStatic => crate::fluent_generated::mir_transform_use_of_static_mut_label, - UseOfExternStatic => crate::fluent_generated::mir_transform_use_of_extern_static_label, - DerefOfRawPointer => crate::fluent_generated::mir_transform_deref_ptr_label, - AccessToUnionField => crate::fluent_generated::mir_transform_union_access_label, + CallToUnsafeFunction => fluent::mir_transform_call_to_unsafe_label, + UseOfInlineAssembly => fluent::mir_transform_use_of_asm_label, + InitializingTypeWith => fluent::mir_transform_initializing_valid_range_label, + CastOfPointerToInt => fluent::mir_transform_const_ptr2int_label, + UseOfMutableStatic => fluent::mir_transform_use_of_static_mut_label, + UseOfExternStatic => fluent::mir_transform_use_of_extern_static_label, + DerefOfRawPointer => fluent::mir_transform_deref_ptr_label, + AccessToUnionField => fluent::mir_transform_union_access_label, MutationOfLayoutConstrainedField => { - crate::fluent_generated::mir_transform_mutation_layout_constrained_label + fluent::mir_transform_mutation_layout_constrained_label } BorrowOfLayoutConstrainedField => { - crate::fluent_generated::mir_transform_mutation_layout_constrained_borrow_label + fluent::mir_transform_mutation_layout_constrained_borrow_label } - CallToFunctionWith => crate::fluent_generated::mir_transform_target_feature_call_label, + CallToFunctionWith { .. } => fluent::mir_transform_target_feature_call_label, } } } @@ -151,12 +188,12 @@ impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn { let desc = handler.eagerly_translate_to_string(self.details.label(), [].into_iter()); diag.set_arg("details", desc); diag.span_label(self.details.span, self.details.label()); - diag.note(self.details.note()); + self.details.add_subdiagnostics(diag); if let Some((start, end, fn_sig)) = self.suggest_unsafe_block { - diag.span_note(fn_sig, crate::fluent_generated::mir_transform_note); + diag.span_note(fn_sig, fluent::mir_transform_note); diag.tool_only_multipart_suggestion( - crate::fluent_generated::mir_transform_suggestion, + fluent::mir_transform_suggestion, vec![(start, " unsafe {".into()), (end, "}".into())], Applicability::MaybeIncorrect, ); @@ -166,7 +203,7 @@ impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn { } fn msg(&self) -> DiagnosticMessage { - crate::fluent_generated::mir_transform_unsafe_op_in_unsafe_fn + fluent::mir_transform_unsafe_op_in_unsafe_fn } } @@ -193,12 +230,8 @@ impl<'a, P: std::fmt::Debug> DecorateLint<'a, ()> for AssertLint<P> { fn msg(&self) -> DiagnosticMessage { match self { - AssertLint::ArithmeticOverflow(..) => { - crate::fluent_generated::mir_transform_arithmetic_overflow - } - AssertLint::UnconditionalPanic(..) => { - crate::fluent_generated::mir_transform_operation_will_panic - } + AssertLint::ArithmeticOverflow(..) => fluent::mir_transform_arithmetic_overflow, + AssertLint::UnconditionalPanic(..) => fluent::mir_transform_operation_will_panic, } } } @@ -255,11 +288,11 @@ impl<'a> DecorateLint<'a, ()> for MustNotSupend<'_, '_> { self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { - diag.span_label(self.yield_sp, crate::fluent_generated::_subdiag::label); + diag.span_label(self.yield_sp, fluent::_subdiag::label); if let Some(reason) = self.reason { diag.subdiagnostic(reason); } - diag.span_help(self.src_sp, crate::fluent_generated::_subdiag::help); + diag.span_help(self.src_sp, fluent::_subdiag::help); diag.set_arg("pre", self.pre); diag.set_arg("def_path", self.tcx.def_path_str(self.def_id)); diag.set_arg("post", self.post); @@ -267,7 +300,7 @@ impl<'a> DecorateLint<'a, ()> for MustNotSupend<'_, '_> { } fn msg(&self) -> rustc_errors::DiagnosticMessage { - crate::fluent_generated::mir_transform_must_not_suspend + fluent::mir_transform_must_not_suspend } } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index f24a2d07e49..fba73d5195b 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -74,11 +74,13 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' let mut body = EarlyBinder::bind(body.clone()).instantiate(tcx, args); debug!("make_shim({:?}) = {:?}", instance, body); - // Run empty passes to mark phase change and perform validation. pm::run_passes( tcx, &mut body, - &[], + &[ + &abort_unwinding_calls::AbortUnwindingCalls, + &add_call_guards::CriticalCallEdges, + ], Some(MirPhase::Runtime(RuntimePhase::Optimized)), ); diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 49a2c414467..1c3c433d8b7 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -492,9 +492,13 @@ parse_match_arm_body_without_braces = `match` arm body without braces } with a body .suggestion_use_comma_not_semicolon = replace `;` with `,` to end a `match` arm expression +parse_maybe_comparison = you might have meant to compare for equality + parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn` .suggestion = replace `fn` with `impl` here +parse_maybe_missing_let = you might have meant to continue the let-chain + parse_maybe_recover_from_bad_qpath_stage_2 = missing angle brackets in associated item path .suggestion = types that don't start with an identifier need to be surrounded with angle brackets in qualified paths @@ -721,6 +725,9 @@ parse_sugg_wrap_pattern_in_parens = wrap the pattern in parentheses parse_switch_mut_let_order = switch the order of `mut` and `let` +parse_switch_ref_box_order = switch the order of `ref` and `box` + .suggestion = swap them + parse_ternary_operator = Rust has no ternary operator .help = use an `if-else` expression instead @@ -770,6 +777,9 @@ parse_unexpected_lifetime_in_pattern = unexpected lifetime `{$symbol}` in patter parse_unexpected_parentheses_in_for_head = unexpected parentheses surrounding `for` loop head .suggestion = remove parentheses in `for` loop +parse_unexpected_parentheses_in_match_arm_pattern = unexpected parentheses surrounding `match` arm pattern + .suggestion = remove parentheses surrounding the pattern + parse_unexpected_self_in_generic_parameters = unexpected keyword `Self` in generic parameters .note = you cannot use `Self` as a generic parameter because it is reserved for associated items diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 7ce348619c6..03e047b297d 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -138,6 +138,14 @@ pub(crate) enum InvalidVariableDeclarationSub { } #[derive(Diagnostic)] +#[diag(parse_switch_ref_box_order)] +pub(crate) struct SwitchRefBoxOrder { + #[primary_span] + #[suggestion(applicability = "machine-applicable", code = "box ref")] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(parse_invalid_comparison_operator)] pub(crate) struct InvalidComparisonOperator { #[primary_span] @@ -407,6 +415,32 @@ pub(crate) struct ExpectedExpressionFoundLet { pub span: Span, #[subdiagnostic] pub reason: ForbiddenLetReason, + #[subdiagnostic] + pub missing_let: Option<MaybeMissingLet>, + #[subdiagnostic] + pub comparison: Option<MaybeComparison>, +} + +#[derive(Subdiagnostic, Clone, Copy)] +#[multipart_suggestion( + parse_maybe_missing_let, + applicability = "maybe-incorrect", + style = "verbose" +)] +pub(crate) struct MaybeMissingLet { + #[suggestion_part(code = "let ")] + pub span: Span, +} + +#[derive(Subdiagnostic, Clone, Copy)] +#[multipart_suggestion( + parse_maybe_comparison, + applicability = "maybe-incorrect", + style = "verbose" +)] +pub(crate) struct MaybeComparison { + #[suggestion_part(code = "=")] + pub span: Span, } #[derive(Diagnostic)] @@ -1241,12 +1275,28 @@ pub(crate) struct ParenthesesInForHead { #[derive(Subdiagnostic)] #[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")] pub(crate) struct ParenthesesInForHeadSugg { - #[suggestion_part(code = "{left_snippet}")] + #[suggestion_part(code = " ")] pub left: Span, - pub left_snippet: String, - #[suggestion_part(code = "{right_snippet}")] + #[suggestion_part(code = " ")] + pub right: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_unexpected_parentheses_in_match_arm_pattern)] +pub(crate) struct ParenthesesInMatchPat { + #[primary_span] + pub span: Vec<Span>, + #[subdiagnostic] + pub sugg: ParenthesesInMatchPatSugg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")] +pub(crate) struct ParenthesesInMatchPatSugg { + #[suggestion_part(code = "")] + pub left: Span, + #[suggestion_part(code = "")] pub right: Span, - pub right_snippet: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index ecb840f067e..8921c1c6a03 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -11,12 +11,12 @@ use crate::errors::{ DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon, - IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg, - PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, - StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, - StructLiteralNeedingParensSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, - TernaryOperator, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, - UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType, + IncorrectUseOfAwait, PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, + SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, + StructLiteralNeedingParens, StructLiteralNeedingParensSugg, SuggAddMissingLetStmt, + SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator, UnexpectedConstInGenericParam, + UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, + UseEqInstead, WrapType, }; use crate::fluent_generated as fluent; @@ -1994,56 +1994,6 @@ impl<'a> Parser<'a> { } } - /// Recovers a situation like `for ( $pat in $expr )` - /// and suggest writing `for $pat in $expr` instead. - /// - /// This should be called before parsing the `$block`. - pub(super) fn recover_parens_around_for_head( - &mut self, - pat: P<Pat>, - begin_paren: Option<Span>, - ) -> P<Pat> { - match (&self.token.kind, begin_paren) { - (token::CloseDelim(Delimiter::Parenthesis), Some(begin_par_sp)) => { - self.bump(); - - let sm = self.sess.source_map(); - let left = begin_par_sp; - let right = self.prev_token.span; - let left_snippet = if let Ok(snip) = sm.span_to_prev_source(left) - && !snip.ends_with(' ') - { - " ".to_string() - } else { - "".to_string() - }; - - let right_snippet = if let Ok(snip) = sm.span_to_next_source(right) - && !snip.starts_with(' ') - { - " ".to_string() - } else { - "".to_string() - }; - - self.sess.emit_err(ParenthesesInForHead { - span: vec![left, right], - // With e.g. `for (x) in y)` this would replace `(x) in y)` - // with `x) in y)` which is syntactically invalid. - // However, this is prevented before we get here. - sugg: ParenthesesInForHeadSugg { left, right, left_snippet, right_snippet }, - }); - - // Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint. - pat.and_then(|pat| match pat.kind { - PatKind::Paren(pat) => pat, - _ => P(pat), - }) - } - _ => pat, - } - } - 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 79567eb3898..b1b77305e4f 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1,3 +1,4 @@ +// ignore-tidy-filelength use super::diagnostics::SnapshotParser; use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; @@ -9,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, Path, PathSegment}; +use ast::{GenBlockKind, Pat, Path, PathSegment}; use core::mem; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; @@ -2477,7 +2478,7 @@ impl<'a> Parser<'a> { let mut cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, None)?; - CondChecker { parser: self, forbid_let_reason: None }.visit_expr(&mut cond); + CondChecker::new(self).visit_expr(&mut cond); if let ExprKind::Let(_, _, _, None) = cond.kind { // Remove the last feature gating of a `let` expression since it's stable. @@ -2493,6 +2494,8 @@ impl<'a> Parser<'a> { let err = errors::ExpectedExpressionFoundLet { span: self.token.span, reason: ForbiddenLetReason::OtherForbidden, + missing_let: None, + comparison: None, }; if self.prev_token.kind == token::BinOp(token::Or) { // This was part of a closure, the that part of the parser recover. @@ -2606,30 +2609,72 @@ impl<'a> Parser<'a> { } } - /// Parses `for <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten). - fn parse_expr_for(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> { - // Record whether we are about to parse `for (`. - // This is used below for recovery in case of `for ( $stuff ) $block` - // in which case we will suggest `for $stuff $block`. - let begin_paren = match self.token.kind { - token::OpenDelim(Delimiter::Parenthesis) => Some(self.token.span), - _ => None, + fn parse_for_head(&mut self) -> PResult<'a, (P<Pat>, P<Expr>)> { + let begin_paren = if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) { + // Record whether we are about to parse `for (`. + // This is used below for recovery in case of `for ( $stuff ) $block` + // in which case we will suggest `for $stuff $block`. + let start_span = self.token.span; + let left = self.prev_token.span.between(self.look_ahead(1, |t| t.span)); + Some((start_span, left)) + } else { + None + }; + // Try to parse the pattern `for ($PAT) in $EXPR`. + let pat = match ( + self.parse_pat_allow_top_alt( + None, + RecoverComma::Yes, + RecoverColon::Yes, + CommaRecoveryMode::LikelyTuple, + ), + begin_paren, + ) { + (Ok(pat), _) => pat, // Happy path. + (Err(err), Some((start_span, left))) if self.eat_keyword(kw::In) => { + // We know for sure we have seen `for ($SOMETHING in`. In the happy path this would + // happen right before the return of this method. + let expr = match self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None) { + Ok(expr) => expr, + Err(expr_err) => { + // We don't know what followed the `in`, so cancel and bubble up the + // original error. + expr_err.cancel(); + return Err(err); + } + }; + return if self.token.kind == token::CloseDelim(Delimiter::Parenthesis) { + // We know for sure we have seen `for ($SOMETHING in $EXPR)`, so we recover the + // parser state and emit a targetted suggestion. + let span = vec![start_span, self.token.span]; + let right = self.prev_token.span.between(self.look_ahead(1, |t| t.span)); + self.bump(); // ) + err.cancel(); + self.sess.emit_err(errors::ParenthesesInForHead { + span, + // With e.g. `for (x) in y)` this would replace `(x) in y)` + // with `x) in y)` which is syntactically invalid. + // However, this is prevented before we get here. + sugg: errors::ParenthesesInForHeadSugg { left, right }, + }); + Ok((self.mk_pat(start_span.to(right), ast::PatKind::Wild), expr)) + } else { + Err(err) // Some other error, bubble up. + }; + } + (Err(err), _) => return Err(err), // Some other error, bubble up. }; - - let pat = self.parse_pat_allow_top_alt( - None, - RecoverComma::Yes, - RecoverColon::Yes, - CommaRecoveryMode::LikelyTuple, - )?; if !self.eat_keyword(kw::In) { self.error_missing_in_for_loop(); } self.check_for_for_in_in_typo(self.prev_token.span); let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; + Ok((pat, expr)) + } - let pat = self.recover_parens_around_for_head(pat, begin_paren); - + /// Parses `for <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten). + fn parse_expr_for(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> { + let (pat, expr) = self.parse_for_head()?; // Recover from missing expression in `for` loop if matches!(expr.kind, ExprKind::Block(..)) && !matches!(self.token.kind, token::OpenDelim(Delimiter::Brace)) @@ -2850,47 +2895,10 @@ impl<'a> Parser<'a> { } pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> { - // Used to check the `let_chains` and `if_let_guard` features mostly by scanning - // `&&` tokens. - fn check_let_expr(expr: &Expr) -> (bool, bool) { - match &expr.kind { - ExprKind::Binary(BinOp { node: BinOpKind::And, .. }, lhs, rhs) => { - let lhs_rslt = check_let_expr(lhs); - let rhs_rslt = check_let_expr(rhs); - (lhs_rslt.0 || rhs_rslt.0, false) - } - ExprKind::Let(..) => (true, true), - _ => (false, true), - } - } let attrs = self.parse_outer_attributes()?; self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| { let lo = this.token.span; - let pat = this.parse_pat_allow_top_alt( - None, - RecoverComma::Yes, - RecoverColon::Yes, - CommaRecoveryMode::EitherTupleOrPipe, - )?; - let guard = if this.eat_keyword(kw::If) { - let if_span = this.prev_token.span; - let mut cond = this.parse_match_guard_condition()?; - - CondChecker { parser: this, forbid_let_reason: None }.visit_expr(&mut cond); - - let (has_let_expr, does_not_have_bin_op) = check_let_expr(&cond); - if has_let_expr { - if does_not_have_bin_op { - // Remove the last feature gating of a `let` expression since it's stable. - this.sess.gated_spans.ungate_last(sym::let_chains, cond.span); - } - let span = if_span.to(cond.span); - this.sess.gated_spans.gate(sym::if_let_guard, span); - } - Some(cond) - } else { - None - }; + let (pat, guard) = this.parse_match_arm_pat_and_guard()?; let arrow_span = this.token.span; if let Err(mut err) = this.expect(&token::FatArrow) { // We might have a `=>` -> `=` or `->` typo (issue #89396). @@ -3020,6 +3028,90 @@ impl<'a> Parser<'a> { }) } + fn parse_match_arm_guard(&mut self) -> PResult<'a, Option<P<Expr>>> { + // Used to check the `let_chains` and `if_let_guard` features mostly by scanning + // `&&` tokens. + fn check_let_expr(expr: &Expr) -> (bool, bool) { + match &expr.kind { + ExprKind::Binary(BinOp { node: BinOpKind::And, .. }, lhs, rhs) => { + let lhs_rslt = check_let_expr(lhs); + let rhs_rslt = check_let_expr(rhs); + (lhs_rslt.0 || rhs_rslt.0, false) + } + ExprKind::Let(..) => (true, true), + _ => (false, true), + } + } + if !self.eat_keyword(kw::If) { + // No match arm guard present. + return Ok(None); + } + + let if_span = self.prev_token.span; + let mut cond = self.parse_match_guard_condition()?; + + CondChecker::new(self).visit_expr(&mut cond); + + let (has_let_expr, does_not_have_bin_op) = check_let_expr(&cond); + if has_let_expr { + if does_not_have_bin_op { + // Remove the last feature gating of a `let` expression since it's stable. + self.sess.gated_spans.ungate_last(sym::let_chains, cond.span); + } + let span = if_span.to(cond.span); + self.sess.gated_spans.gate(sym::if_let_guard, span); + } + Ok(Some(cond)) + } + + fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (P<Pat>, Option<P<Expr>>)> { + if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) { + // Detect and recover from `($pat if $cond) => $arm`. + let left = self.token.span; + match self.parse_pat_allow_top_alt( + None, + RecoverComma::Yes, + RecoverColon::Yes, + CommaRecoveryMode::EitherTupleOrPipe, + ) { + Ok(pat) => Ok((pat, self.parse_match_arm_guard()?)), + Err(err) + if let prev_sp = self.prev_token.span + && let true = self.eat_keyword(kw::If) => + { + // We know for certain we've found `($pat if` so far. + let mut cond = match self.parse_match_guard_condition() { + Ok(cond) => cond, + Err(cond_err) => { + cond_err.cancel(); + return Err(err); + } + }; + err.cancel(); + CondChecker::new(self).visit_expr(&mut cond); + self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Parenthesis)]); + self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; + let right = self.prev_token.span; + self.sess.emit_err(errors::ParenthesesInMatchPat { + span: vec![left, right], + sugg: errors::ParenthesesInMatchPatSugg { left, right }, + }); + Ok((self.mk_pat(left.to(prev_sp), ast::PatKind::Wild), Some(cond))) + } + Err(err) => Err(err), + } + } else { + // Regular parser flow: + let pat = self.parse_pat_allow_top_alt( + None, + RecoverComma::Yes, + RecoverColon::Yes, + CommaRecoveryMode::EitherTupleOrPipe, + )?; + Ok((pat, self.parse_match_arm_guard()?)) + } + } + fn parse_match_guard_condition(&mut self) -> PResult<'a, P<Expr>> { self.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, None).map_err( |mut err| { @@ -3552,6 +3644,14 @@ pub(crate) enum ForbiddenLetReason { struct CondChecker<'a> { parser: &'a Parser<'a>, forbid_let_reason: Option<ForbiddenLetReason>, + missing_let: Option<errors::MaybeMissingLet>, + comparison: Option<errors::MaybeComparison>, +} + +impl<'a> CondChecker<'a> { + fn new(parser: &'a Parser<'a>) -> Self { + CondChecker { parser, forbid_let_reason: None, missing_let: None, comparison: None } + } } impl MutVisitor for CondChecker<'_> { @@ -3562,11 +3662,13 @@ impl MutVisitor for CondChecker<'_> { match e.kind { ExprKind::Let(_, _, _, ref mut is_recovered @ None) => { if let Some(reason) = self.forbid_let_reason { - *is_recovered = Some( - self.parser - .sess - .emit_err(errors::ExpectedExpressionFoundLet { span, reason }), - ); + *is_recovered = + Some(self.parser.sess.emit_err(errors::ExpectedExpressionFoundLet { + span, + reason, + missing_let: self.missing_let, + comparison: self.comparison, + })); } else { self.parser.sess.gated_spans.gate(sym::let_chains, span); } @@ -3590,9 +3692,28 @@ impl MutVisitor for CondChecker<'_> { noop_visit_expr(e, self); self.forbid_let_reason = forbid_let_reason; } + ExprKind::Assign(ref lhs, _, span) => { + let forbid_let_reason = self.forbid_let_reason; + self.forbid_let_reason = Some(OtherForbidden); + let missing_let = self.missing_let; + if let ExprKind::Binary(_, _, rhs) = &lhs.kind + && let ExprKind::Path(_, _) + | ExprKind::Struct(_) + | ExprKind::Call(_, _) + | ExprKind::Array(_) = rhs.kind + { + self.missing_let = + Some(errors::MaybeMissingLet { span: rhs.span.shrink_to_lo() }); + } + let comparison = self.comparison; + self.comparison = Some(errors::MaybeComparison { span: span.shrink_to_hi() }); + noop_visit_expr(e, self); + self.forbid_let_reason = forbid_let_reason; + self.missing_let = missing_let; + self.comparison = comparison; + } ExprKind::Unary(_, _) | ExprKind::Await(_, _) - | ExprKind::Assign(_, _, _) | ExprKind::AssignOp(_, _, _) | ExprKind::Range(_, _, _) | ExprKind::Try(_) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 23886b1208b..ab18e40482e 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1415,8 +1415,8 @@ impl<'a> Parser<'a> { self.bump(); (thin_vec![], false) } else { - self.parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant()).map_err( - |mut err| { + self.parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant(id.span)) + .map_err(|mut err| { err.span_label(id.span, "while parsing this enum"); if self.token == token::Colon { let snapshot = self.create_snapshot_for_diagnostic(); @@ -1436,20 +1436,22 @@ impl<'a> Parser<'a> { } self.restore_snapshot(snapshot); } - self.recover_stmt(); + self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Brace)]); + self.bump(); // } err - }, - )? + })? }; let enum_definition = EnumDef { variants: variants.into_iter().flatten().collect() }; Ok((id, ItemKind::Enum(enum_definition, generics))) } - fn parse_enum_variant(&mut self) -> PResult<'a, Option<Variant>> { + fn parse_enum_variant(&mut self, span: Span) -> PResult<'a, Option<Variant>> { self.recover_diff_marker(); let variant_attrs = self.parse_outer_attributes()?; self.recover_diff_marker(); + let help = "enum variants can be `Variant`, `Variant = <integer>`, \ + `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`"; self.collect_tokens_trailing_token( variant_attrs, ForceCollect::No, @@ -1476,10 +1478,39 @@ impl<'a> Parser<'a> { let struct_def = if this.check(&token::OpenDelim(Delimiter::Brace)) { // Parse a struct variant. let (fields, recovered) = - this.parse_record_struct_body("struct", ident.span, false)?; + match this.parse_record_struct_body("struct", ident.span, false) { + Ok((fields, recovered)) => (fields, recovered), + Err(mut err) => { + if this.token == token::Colon { + // We handle `enum` to `struct` suggestion in the caller. + return Err(err); + } + this.eat_to_tokens(&[&token::CloseDelim(Delimiter::Brace)]); + this.bump(); // } + err.span_label(span, "while parsing this enum"); + err.help(help); + err.emit(); + (thin_vec![], true) + } + }; VariantData::Struct(fields, recovered) } else if this.check(&token::OpenDelim(Delimiter::Parenthesis)) { - VariantData::Tuple(this.parse_tuple_struct_body()?, DUMMY_NODE_ID) + let body = match this.parse_tuple_struct_body() { + Ok(body) => body, + Err(mut err) => { + if this.token == token::Colon { + // We handle `enum` to `struct` suggestion in the caller. + return Err(err); + } + this.eat_to_tokens(&[&token::CloseDelim(Delimiter::Parenthesis)]); + this.bump(); // ) + err.span_label(span, "while parsing this enum"); + err.help(help); + err.emit(); + thin_vec![] + } + }; + VariantData::Tuple(body, DUMMY_NODE_ID) } else { VariantData::Unit(DUMMY_NODE_ID) }; @@ -1500,8 +1531,9 @@ impl<'a> Parser<'a> { Ok((Some(vr), TrailingToken::MaybeComma)) }, - ).map_err(|mut err| { - err.help("enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`"); + ) + .map_err(|mut err| { + err.help(help); err }) } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 9bd436f01ac..c680a950584 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -875,6 +875,9 @@ impl<'a> Parser<'a> { if self.token == token::Colon { // we will try to recover in `maybe_recover_struct_lit_bad_delims` return Err(expect_err); + } else if let [token::CloseDelim(Delimiter::Parenthesis)] = kets + { + return Err(expect_err); } else { expect_err.emit(); break; diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 15491cac56a..3d1d1ec8108 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -5,8 +5,8 @@ use crate::errors::{ ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern, PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern, - TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed, - UnexpectedLifetimeInPattern, UnexpectedVertVertBeforeFunctionParam, + SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, + TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, }; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; @@ -141,7 +141,19 @@ impl<'a> Parser<'a> { }; // Parse the first pattern (`p_0`). - let mut first_pat = self.parse_pat_no_top_alt(expected, syntax_loc)?; + let mut first_pat = match self.parse_pat_no_top_alt(expected, syntax_loc) { + Ok(pat) => pat, + Err(mut err) + if self.token.is_reserved_ident() + && !self.token.is_keyword(kw::In) + && !self.token.is_keyword(kw::If) => + { + err.emit(); + self.bump(); + self.mk_pat(self.token.span, PatKind::Wild) + } + Err(err) => return Err(err), + }; if rc == RecoverComma::Yes { self.maybe_recover_unexpected_comma( first_pat.span, @@ -368,12 +380,22 @@ impl<'a> Parser<'a> { self.recover_dotdotdot_rest_pat(lo) } else if let Some(form) = self.parse_range_end() { self.parse_pat_range_to(form)? // `..=X`, `...X`, or `..X`. + } else if self.eat(&token::Not) { + // Parse `!` + self.sess.gated_spans.gate(sym::never_patterns, self.prev_token.span); + PatKind::Never } else if self.eat_keyword(kw::Underscore) { - // Parse _ + // Parse `_` PatKind::Wild } else if self.eat_keyword(kw::Mut) { self.parse_pat_ident_mut(syntax_loc)? } else if self.eat_keyword(kw::Ref) { + if self.check_keyword(kw::Box) { + // Suggest `box ref`. + let span = self.prev_token.span.to(self.token.span); + self.bump(); + self.sess.emit_err(SwitchRefBoxOrder { span }); + } // Parse ref ident @ pat / ref mut ident @ pat let mutbl = self.parse_mutability(); self.parse_pat_ident(BindingAnnotation(ByRef::Yes, mutbl), syntax_loc)? @@ -829,7 +851,7 @@ impl<'a> Parser<'a> { binding_annotation: BindingAnnotation, syntax_loc: Option<PatternLocation>, ) -> PResult<'a, PatKind> { - let ident = self.parse_ident()?; + let ident = self.parse_ident_common(false)?; if self.may_recover() && !matches!(syntax_loc, Some(PatternLocation::FunctionParameter)) diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 5316dde6096..1ee5a96d5dc 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -384,10 +384,10 @@ impl<'a> Parser<'a> { fn check_let_else_init_bool_expr(&self, init: &ast::Expr) { if let ast::ExprKind::Binary(op, ..) = init.kind { - if op.node.lazy() { + if op.node.is_lazy() { self.sess.emit_err(errors::InvalidExpressionInLetElse { span: init.span, - operator: op.node.to_string(), + operator: op.node.as_str(), sugg: errors::WrapExpressionInParentheses { left: init.span.shrink_to_lo(), right: init.span.shrink_to_hi(), @@ -567,20 +567,37 @@ impl<'a> Parser<'a> { snapshot.recover_diff_marker(); } if self.token == token::Colon { - // if next token is following a colon, it's likely a path - // and we can suggest a path separator - self.bump(); - if self.token.span.lo() == self.prev_token.span.hi() { + // if a previous and next token of the current one is + // integer literal (e.g. `1:42`), it's likely a range + // expression for Pythonistas and we can suggest so. + if self.prev_token.is_integer_lit() + && self.may_recover() + && self.look_ahead(1, |token| token.is_integer_lit()) + { + // FIXME(hkmatsumoto): Might be better to trigger + // this only when parsing an index expression. err.span_suggestion_verbose( - self.prev_token.span, - "maybe write a path separator here", - "::", + self.token.span, + "you might have meant a range expression", + "..", Applicability::MaybeIncorrect, ); - } - if self.sess.unstable_features.is_nightly_build() { - // FIXME(Nilstrieb): Remove this again after a few months. - err.note("type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>"); + } else { + // if next token is following a colon, it's likely a path + // and we can suggest a path separator + self.bump(); + if self.token.span.lo() == self.prev_token.span.hi() { + err.span_suggestion_verbose( + self.prev_token.span, + "maybe write a path separator here", + "::", + Applicability::MaybeIncorrect, + ); + } + if self.sess.unstable_features.is_nightly_build() { + // FIXME(Nilstrieb): Remove this again after a few months. + err.note("type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>"); + } } } diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index de96746e215..76c7467346d 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::TyCtxt; use rustc_session::parse::feature_err; use rustc_span::{sym, Span, Symbol}; -use crate::errors::{ExprNotAllowedInContext, SkippingConstChecks}; +use crate::errors::SkippingConstChecks; /// An expression that is not *always* legal in a const context. #[derive(Clone, Copy)] @@ -138,11 +138,10 @@ impl<'tcx> CheckConstVisitor<'tcx> { match missing_gates.as_slice() { [] => { - tcx.sess.emit_err(ExprNotAllowedInContext { + span_bug!( span, - expr: expr.name(), - context: const_kind.keyword_name(), - }); + "we should not have reached this point, since `.await` is denied earlier" + ); } [missing_primary, ref missing_secondary @ ..] => { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 411c9410195..58127445322 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1005,15 +1005,6 @@ pub struct FeaturePreviouslyDeclared<'a, 'b> { pub prev_declared: &'b str, } -#[derive(Diagnostic)] -#[diag(passes_expr_not_allowed_in_context, code = "E0744")] -pub struct ExprNotAllowedInContext<'a> { - #[primary_span] - pub span: Span, - pub expr: String, - pub context: &'a str, -} - pub struct BreakNonLoop<'a> { pub span: Span, pub head: Option<Span>, diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index f915c1057d6..28354ab0986 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -286,7 +286,21 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { fn visit_pat(&mut self, p: &'v hir::Pat<'v>) { record_variants!( (self, p, p.kind, Id::Node(p.hir_id), hir, Pat, PatKind), - [Wild, Binding, Struct, TupleStruct, Or, Path, Tuple, Box, Ref, Lit, Range, Slice] + [ + Wild, + Binding, + Struct, + TupleStruct, + Or, + Never, + Path, + Tuple, + Box, + Ref, + Lit, + Range, + Slice + ] ); hir_visit::walk_pat(self, p) } @@ -554,6 +568,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { Range, Slice, Rest, + Never, Paren, MacCall ] diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 9faf63f00e2..acd3d71e636 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -80,14 +80,14 @@ impl QueryContext for QueryCtxt<'_> { tls::with_related_context(self.tcx, |icx| icx.query) } - fn try_collect_active_jobs(self) -> Option<QueryMap> { + fn collect_active_jobs(self) -> QueryMap { let mut jobs = QueryMap::default(); for collect in super::TRY_COLLECT_ACTIVE_JOBS.iter() { collect(self.tcx, &mut jobs); } - Some(jobs) + jobs } // Interactions with on_disk_cache @@ -155,11 +155,11 @@ impl QueryContext for QueryCtxt<'_> { fn depth_limit_error(self, job: QueryJobId) { let mut span = None; let mut layout_of_depth = None; - if let Some(map) = self.try_collect_active_jobs() { - if let Some((info, depth)) = job.try_find_layout_root(map, dep_kinds::layout_of) { - span = Some(info.job.span); - layout_of_depth = Some(LayoutOfDepth { desc: info.query.description, depth }); - } + if let Some((info, depth)) = + job.try_find_layout_root(self.collect_active_jobs(), dep_kinds::layout_of) + { + span = Some(info.job.span); + layout_of_depth = Some(LayoutOfDepth { desc: info.query.description, depth }); } let suggested_limit = match self.recursion_limit() { diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs index 81a7eb604f5..f2387017c82 100644 --- a/compiler/rustc_query_system/src/ich/impls_syntax.rs +++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs @@ -117,9 +117,9 @@ impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::Features { self.declared_lang_features.hash_stable(hcx, hasher); self.declared_lib_features.hash_stable(hcx, hasher); - self.walk_feature_fields(|feature_name, value| { - feature_name.hash_stable(hcx, hasher); - value.hash_stable(hcx, hasher); - }); + self.all_features()[..].hash_stable(hcx, hasher); + for feature in rustc_feature::UNSTABLE_FEATURES.iter() { + feature.feature.name.hash_stable(hcx, hasher); + } } } diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index b38d71733b5..2a55ec72c5f 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -620,13 +620,13 @@ pub fn print_query_stack<Qcx: QueryContext>( // state if it was responsible for triggering the panic. let mut count_printed = 0; let mut count_total = 0; - let query_map = qcx.try_collect_active_jobs(); + let query_map = qcx.collect_active_jobs(); if let Some(ref mut file) = file { let _ = writeln!(file, "\n\nquery stack during panic:"); } while let Some(query) = current_query { - let Some(query_info) = query_map.as_ref().and_then(|map| map.get(&query)) else { + let Some(query_info) = query_map.get(&query) else { break; }; if Some(count_printed) < num_frames || num_frames.is_none() { diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index 05dee9f12db..96a0c7a033a 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -106,7 +106,7 @@ pub trait QueryContext: HasDepContext { /// Get the query information from the TLS context. fn current_query_job(self) -> Option<QueryJobId>; - fn try_collect_active_jobs(self) -> Option<QueryMap>; + fn collect_active_jobs(self) -> QueryMap; /// Load side effects associated to the node in the previous session. fn load_side_effects(self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index ecbc7dc6b8f..2f9f094dae2 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -242,11 +242,8 @@ where Q: QueryConfig<Qcx>, Qcx: QueryContext, { - let error = try_execute.find_cycle_in_stack( - qcx.try_collect_active_jobs().unwrap(), - &qcx.current_query_job(), - span, - ); + let error = + try_execute.find_cycle_in_stack(qcx.collect_active_jobs(), &qcx.current_query_job(), span); (mk_cycle(query, qcx, error), None) } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index b1ee7f438d2..224f3f36a3f 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -2,6 +2,7 @@ use crate::{ImplTraitContext, Resolver}; use rustc_ast::visit::{self, FnKind}; use rustc_ast::*; use rustc_expand::expand::AstFragment; +use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::LocalDefId; use rustc_hir::definitions::*; use rustc_span::hygiene::LocalExpnId; @@ -26,13 +27,20 @@ struct DefCollector<'a, 'b, 'tcx> { } impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> { - fn create_def(&mut self, node_id: NodeId, data: DefPathData, span: Span) -> LocalDefId { + fn create_def( + &mut self, + node_id: NodeId, + data: DefPathData, + def_kind: DefKind, + span: Span, + ) -> LocalDefId { let parent_def = self.parent_def; debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def); self.resolver.create_def( parent_def, node_id, data, + def_kind, self.expansion.to_expn_id(), span.with_parent(None), ) @@ -68,7 +76,8 @@ impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> { self.visit_macro_invoc(field.id); } else { let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name); - let def = self.create_def(field.id, DefPathData::ValueNs(name), field.span); + let def = + self.create_def(field.id, DefPathData::ValueNs(name), DefKind::Field, field.span); self.with_parent(def, |this| visit::walk_field_def(this, field)); } } @@ -87,34 +96,43 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { // Pick the def data. This need not be unique, but the more // information we encapsulate into, the better - let def_data = match &i.kind { - ItemKind::Impl { .. } => DefPathData::Impl, - ItemKind::ForeignMod(..) => DefPathData::ForeignMod, - ItemKind::Mod(..) - | ItemKind::Trait(..) - | ItemKind::TraitAlias(..) - | ItemKind::Enum(..) - | ItemKind::Struct(..) - | ItemKind::Union(..) - | ItemKind::ExternCrate(..) - | ItemKind::TyAlias(..) => DefPathData::TypeNs(i.ident.name), - ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => { - DefPathData::ValueNs(i.ident.name) + let mut opt_macro_data = None; + let ty_data = DefPathData::TypeNs(i.ident.name); + let value_data = DefPathData::ValueNs(i.ident.name); + let (def_data, def_kind) = match &i.kind { + ItemKind::Impl(i) => { + (DefPathData::Impl, DefKind::Impl { of_trait: i.of_trait.is_some() }) + } + ItemKind::ForeignMod(..) => (DefPathData::ForeignMod, DefKind::ForeignMod), + ItemKind::Mod(..) => (ty_data, DefKind::Mod), + ItemKind::Trait(..) => (ty_data, DefKind::Trait), + ItemKind::TraitAlias(..) => (ty_data, DefKind::TraitAlias), + ItemKind::Enum(..) => (ty_data, DefKind::Enum), + ItemKind::Struct(..) => (ty_data, DefKind::Struct), + ItemKind::Union(..) => (ty_data, DefKind::Union), + ItemKind::ExternCrate(..) => (ty_data, DefKind::ExternCrate), + ItemKind::TyAlias(..) => (ty_data, DefKind::TyAlias), + ItemKind::Static(s) => (value_data, DefKind::Static(s.mutability)), + ItemKind::Const(..) => (value_data, DefKind::Const), + ItemKind::Fn(..) => (value_data, DefKind::Fn), + ItemKind::MacroDef(..) => { + let macro_data = self.resolver.compile_macro(i, self.resolver.tcx.sess.edition()); + let macro_kind = macro_data.ext.macro_kind(); + opt_macro_data = Some(macro_data); + (DefPathData::MacroNs(i.ident.name), DefKind::Macro(macro_kind)) } - ItemKind::MacroDef(..) => DefPathData::MacroNs(i.ident.name), ItemKind::MacCall(..) => { visit::walk_item(self, i); return self.visit_macro_invoc(i.id); } - ItemKind::GlobalAsm(..) => DefPathData::GlobalAsm, + ItemKind::GlobalAsm(..) => (DefPathData::GlobalAsm, DefKind::GlobalAsm), ItemKind::Use(..) => { return visit::walk_item(self, i); } }; - let def_id = self.create_def(i.id, def_data, i.span); + let def_id = self.create_def(i.id, def_data, def_kind, i.span); - if let ItemKind::MacroDef(..) = i.kind { - let macro_data = self.resolver.compile_macro(i, self.resolver.tcx.sess.edition()); + if let Some(macro_data) = opt_macro_data { self.resolver.macro_map.insert(def_id.to_def_id(), macro_data); } @@ -123,8 +141,13 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { match i.kind { ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => { // If this is a unit or tuple-like struct, register the constructor. - if let Some(ctor_node_id) = struct_def.ctor_node_id() { - this.create_def(ctor_node_id, DefPathData::Ctor, i.span); + if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(struct_def) { + this.create_def( + ctor_node_id, + DefPathData::Ctor, + DefKind::Ctor(CtorOf::Struct, ctor_kind), + i.span, + ); } } _ => {} @@ -151,7 +174,12 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { // then the closure_def will never be used, and we should avoid generating a // def-id for it. if let Some(body) = body { - let closure_def = self.create_def(closure_id, DefPathData::ClosureExpr, span); + let closure_def = self.create_def( + closure_id, + DefPathData::ClosureExpr, + DefKind::Closure, + span, + ); self.with_parent(closure_def, |this| this.visit_block(body)); } return; @@ -162,34 +190,39 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { } fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) { - self.create_def(id, DefPathData::Use, use_tree.span); + self.create_def(id, DefPathData::Use, DefKind::Use, use_tree.span); visit::walk_use_tree(self, use_tree, id); } - fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) { - if let ForeignItemKind::MacCall(_) = foreign_item.kind { - return self.visit_macro_invoc(foreign_item.id); - } + fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { + let (def_data, def_kind) = match fi.kind { + ForeignItemKind::Static(_, mt, _) => { + (DefPathData::ValueNs(fi.ident.name), DefKind::Static(mt)) + } + ForeignItemKind::Fn(_) => (DefPathData::ValueNs(fi.ident.name), DefKind::Fn), + ForeignItemKind::TyAlias(_) => (DefPathData::TypeNs(fi.ident.name), DefKind::ForeignTy), + ForeignItemKind::MacCall(_) => return self.visit_macro_invoc(fi.id), + }; - let def = self.create_def( - foreign_item.id, - DefPathData::ValueNs(foreign_item.ident.name), - foreign_item.span, - ); + let def = self.create_def(fi.id, def_data, def_kind, fi.span); - self.with_parent(def, |this| { - visit::walk_foreign_item(this, foreign_item); - }); + self.with_parent(def, |this| visit::walk_foreign_item(this, fi)); } fn visit_variant(&mut self, v: &'a Variant) { if v.is_placeholder { return self.visit_macro_invoc(v.id); } - let def = self.create_def(v.id, DefPathData::TypeNs(v.ident.name), v.span); + let def = + self.create_def(v.id, DefPathData::TypeNs(v.ident.name), DefKind::Variant, v.span); self.with_parent(def, |this| { - if let Some(ctor_node_id) = v.data.ctor_node_id() { - this.create_def(ctor_node_id, DefPathData::Ctor, v.span); + if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(&v.data) { + this.create_def( + ctor_node_id, + DefPathData::Ctor, + DefKind::Ctor(CtorOf::Variant, ctor_kind), + v.span, + ); } visit::walk_variant(this, v) }); @@ -210,12 +243,14 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { return; } let name = param.ident.name; - let def_path_data = match param.kind { - GenericParamKind::Lifetime { .. } => DefPathData::LifetimeNs(name), - GenericParamKind::Type { .. } => DefPathData::TypeNs(name), - GenericParamKind::Const { .. } => DefPathData::ValueNs(name), + let (def_path_data, def_kind) = match param.kind { + GenericParamKind::Lifetime { .. } => { + (DefPathData::LifetimeNs(name), DefKind::LifetimeParam) + } + GenericParamKind::Type { .. } => (DefPathData::TypeNs(name), DefKind::TyParam), + GenericParamKind::Const { .. } => (DefPathData::ValueNs(name), DefKind::ConstParam), }; - self.create_def(param.id, def_path_data, param.ident.span); + self.create_def(param.id, def_path_data, def_kind, param.ident.span); // impl-Trait can happen inside generic parameters, like // ``` @@ -223,19 +258,20 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { // ``` // // In that case, the impl-trait is lowered as an additional generic parameter. - self.with_impl_trait(ImplTraitContext::Universal(self.parent_def), |this| { + self.with_impl_trait(ImplTraitContext::Universal, |this| { visit::walk_generic_param(this, param) }); } fn visit_assoc_item(&mut self, i: &'a AssocItem, ctxt: visit::AssocCtxt) { - let def_data = match &i.kind { - AssocItemKind::Fn(..) | AssocItemKind::Const(..) => DefPathData::ValueNs(i.ident.name), - AssocItemKind::Type(..) => DefPathData::TypeNs(i.ident.name), + let (def_data, def_kind) = match &i.kind { + AssocItemKind::Fn(..) => (DefPathData::ValueNs(i.ident.name), DefKind::AssocFn), + AssocItemKind::Const(..) => (DefPathData::ValueNs(i.ident.name), DefKind::AssocConst), + AssocItemKind::Type(..) => (DefPathData::TypeNs(i.ident.name), DefKind::AssocTy), AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id), }; - let def = self.create_def(i.id, def_data, i.span); + let def = self.create_def(i.id, def_data, def_kind, i.span); self.with_parent(def, |this| visit::walk_assoc_item(this, i, ctxt)); } @@ -247,7 +283,12 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { } fn visit_anon_const(&mut self, constant: &'a AnonConst) { - let def = self.create_def(constant.id, DefPathData::AnonConst, constant.value.span); + let def = self.create_def( + constant.id, + DefPathData::AnonConst, + DefKind::AnonConst, + constant.value.span, + ); self.with_parent(def, |this| visit::walk_anon_const(this, constant)); } @@ -257,15 +298,31 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { ExprKind::Closure(ref closure) => { // Async closures desugar to closures inside of closures, so // we must create two defs. - let closure_def = self.create_def(expr.id, DefPathData::ClosureExpr, expr.span); + let closure_def = + self.create_def(expr.id, DefPathData::ClosureExpr, DefKind::Closure, expr.span); match closure.asyncness { - Async::Yes { closure_id, .. } => { - self.create_def(closure_id, DefPathData::ClosureExpr, expr.span) - } + Async::Yes { closure_id, .. } => self.create_def( + closure_id, + DefPathData::ClosureExpr, + DefKind::Closure, + expr.span, + ), Async::No => closure_def, } } - ExprKind::Gen(_, _, _) => self.create_def(expr.id, DefPathData::ClosureExpr, expr.span), + ExprKind::Gen(_, _, _) => { + self.create_def(expr.id, DefPathData::ClosureExpr, DefKind::Closure, expr.span) + } + ExprKind::ConstBlock(ref constant) => { + let def = self.create_def( + constant.id, + DefPathData::AnonConst, + DefKind::InlineConst, + constant.value.span, + ); + self.with_parent(def, |this| visit::walk_anon_const(this, constant)); + return; + } _ => self.parent_def, }; @@ -310,9 +367,7 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { if p.is_placeholder { self.visit_macro_invoc(p.id) } else { - self.with_impl_trait(ImplTraitContext::Universal(self.parent_def), |this| { - visit::walk_param(this, p) - }) + self.with_impl_trait(ImplTraitContext::Universal, |this| visit::walk_param(this, p)) } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 8316102b507..df30c185c60 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -744,6 +744,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { err, span, source, + path, res, &path_str, &base_error.fallback_label, @@ -1328,6 +1329,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { err: &mut Diagnostic, span: Span, source: PathSource<'_>, + path: &[Segment], res: Res, path_str: &str, fallback_label: &str, @@ -1523,12 +1525,20 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { | PathSource::Struct, ) => { err.span_label(span, fallback_label.to_string()); - err.span_suggestion_verbose( - span.shrink_to_hi(), - "use `!` to invoke the macro", - "!", - Applicability::MaybeIncorrect, - ); + + // Don't suggest `!` for a macro invocation if there are generic args + if path + .last() + .is_some_and(|segment| !segment.has_generic_args && !segment.has_lifetime_args) + { + err.span_suggestion_verbose( + span.shrink_to_hi(), + "use `!` to invoke the macro", + "!", + Applicability::MaybeIncorrect, + ); + } + if path_str == "try" && span.is_rust_2015() { err.note("if you want the `try` keyword, you need Rust 2018 or later"); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 590bbfc3df1..208391cc019 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -172,7 +172,7 @@ impl<'a> ParentScope<'a> { #[derive(Copy, Debug, Clone)] enum ImplTraitContext { Existential, - Universal(LocalDefId), + Universal, } #[derive(Debug)] @@ -1034,9 +1034,6 @@ pub struct Resolver<'a, 'tcx> { used_extern_options: FxHashSet<Symbol>, macro_names: FxHashSet<Ident>, builtin_macros: FxHashMap<Symbol, BuiltinMacroState>, - /// A small map keeping true kinds of built-in macros that appear to be fn-like on - /// the surface (`macro` items in libcore), but are actually attributes or derives. - builtin_macro_kinds: FxHashMap<LocalDefId, MacroKind>, registered_tools: &'tcx RegisteredTools, macro_use_prelude: FxHashMap<Symbol, NameBinding<'a>>, macro_map: FxHashMap<DefId, MacroData>, @@ -1216,6 +1213,7 @@ impl<'tcx> Resolver<'_, 'tcx> { parent: LocalDefId, node_id: ast::NodeId, data: DefPathData, + def_kind: DefKind, expn_id: ExpnId, span: Span, ) -> LocalDefId { @@ -1230,6 +1228,9 @@ impl<'tcx> Resolver<'_, 'tcx> { // FIXME: remove `def_span` body, pass in the right spans here and call `tcx.at().create_def()` let def_id = self.tcx.untracked().definitions.write().create_def(parent, data); + let feed = self.tcx.feed_local_def_id(def_id); + feed.def_kind(def_kind); + // Create the definition. if expn_id != ExpnId::root() { self.expn_that_defined.insert(def_id, expn_id); @@ -1403,7 +1404,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { used_extern_options: Default::default(), macro_names: FxHashSet::default(), builtin_macros: Default::default(), - builtin_macro_kinds: Default::default(), registered_tools, macro_use_prelude: FxHashMap::default(), macro_map: FxHashMap::default(), @@ -1542,7 +1542,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { node_id_to_def_id: self.node_id_to_def_id, def_id_to_node_id: self.def_id_to_node_id, trait_map: self.trait_map, - builtin_macro_kinds: self.builtin_macro_kinds, lifetime_elision_allowed: self.lifetime_elision_allowed, lint_buffer: Steal::new(self.lint_buffer), }; diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index f8274e7d7d0..5f21741223b 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -950,10 +950,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { BuiltinMacroState::NotYetSeen(builtin_ext) => { ext.kind = builtin_ext; rule_spans = Vec::new(); - if item.id != ast::DUMMY_NODE_ID { - self.builtin_macro_kinds - .insert(self.local_def_id(item.id), ext.macro_kind()); - } } BuiltinMacroState::AlreadySeen(span) => { struct_span_err!( diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index fa1b6f9f13d..3a7959c332e 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -26,6 +26,10 @@ session_file_is_not_writeable = output file {$file} is not writeable -- check it session_file_write_fail = failed to write `{$path}` due to error `{$err}` +session_function_return_requires_x86_or_x86_64 = `-Zfunction-return` (except `keep`) is only supported on x86 and x86_64 + +session_function_return_thunk_extern_requires_non_large_code_model = `-Zfunction-return=thunk-extern` is only supported on non-large code models + session_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported session_incompatible_linker_flavor = linker flavor `{$flavor}` is incompatible with the current target diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 2d2a3c3d665..77874bd9c07 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -580,7 +580,7 @@ pub enum ResolveDocLinks { /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break /// dependency tracking for command-line arguments. Also only hash keys, since tracking /// should only depend on the output types, not the paths they're written to. -#[derive(Clone, Debug, Hash, HashStable_Generic)] +#[derive(Clone, Debug, Hash, HashStable_Generic, Encodable, Decodable)] pub struct OutputTypes(BTreeMap<OutputType, Option<OutFileName>>); impl OutputTypes { @@ -818,7 +818,7 @@ impl Input { } } -#[derive(Clone, Hash, Debug, HashStable_Generic, PartialEq)] +#[derive(Clone, Hash, Debug, HashStable_Generic, PartialEq, Encodable, Decodable)] pub enum OutFileName { Real(PathBuf), Stdout, @@ -890,7 +890,7 @@ impl OutFileName { } } -#[derive(Clone, Hash, Debug, HashStable_Generic)] +#[derive(Clone, Hash, Debug, HashStable_Generic, Encodable, Decodable)] pub struct OutputFilenames { pub out_directory: PathBuf, /// Crate name. Never contains '-'. @@ -3164,9 +3164,9 @@ impl PpMode { pub(crate) mod dep_tracking { use super::{ BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, DebugInfoCompression, - ErrorOutputType, InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, - LocationDetail, LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, - Polonius, RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, + ErrorOutputType, FunctionReturn, InliningThreshold, InstrumentCoverage, InstrumentXRay, + LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, + OutputTypes, Polonius, RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, TraitSolver, TrimmedDefPaths, }; use crate::lint; @@ -3273,6 +3273,7 @@ pub(crate) mod dep_tracking { TraitSolver, Polonius, InliningThreshold, + FunctionReturn, ); impl<T1, T2> DepTrackingHash for (T1, T2) @@ -3451,3 +3452,14 @@ impl Default for InliningThreshold { Self::Sometimes(100) } } + +/// The different settings that the `-Zfunction-return` flag can have. +#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)] +pub enum FunctionReturn { + /// Keep the function return unmodified. + #[default] + Keep, + + /// Replace returns with jumps to thunk, without emitting the thunk. + ThunkExtern, +} diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 31094e0d266..70ee46ea902 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -436,3 +436,11 @@ pub struct IncompatibleLinkerFlavor { pub flavor: &'static str, pub compatible_list: String, } + +#[derive(Diagnostic)] +#[diag(session_function_return_requires_x86_or_x86_64)] +pub(crate) struct FunctionReturnRequiresX86OrX8664; + +#[derive(Diagnostic)] +#[diag(session_function_return_thunk_extern_requires_non_large_code_model)] +pub(crate) struct FunctionReturnThunkExternRequiresNonLargeCodeModel; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 4e669c81bf3..68a39de73b7 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -430,6 +430,7 @@ mod desc { pub const parse_inlining_threshold: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a non-negative number"; pub const parse_llvm_module_flag: &str = "<key>:<type>:<value>:<behavior>. Type must currently be `u32`. Behavior should be one of (`error`, `warning`, `require`, `override`, `append`, `appendunique`, `max`, `min`)"; + pub const parse_function_return: &str = "`keep` or `thunk-extern`"; } mod parse { @@ -1359,6 +1360,15 @@ mod parse { slot.push((key.to_string(), value, behavior)); true } + + pub(crate) fn parse_function_return(slot: &mut FunctionReturn, v: Option<&str>) -> bool { + match v { + Some("keep") => *slot = FunctionReturn::Keep, + Some("thunk-extern") => *slot = FunctionReturn::ThunkExtern, + _ => return false, + } + true + } } options! { @@ -1603,6 +1613,8 @@ options! { "force all crates to be `rustc_private` unstable (default: no)"), fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED], "set the optimization fuel quota for a crate"), + function_return: FunctionReturn = (FunctionReturn::default(), parse_function_return, [TRACKED], + "replace returns with jumps to `__x86_return_thunk` (default: `keep`)"), function_sections: Option<bool> = (None, parse_opt_bool, [TRACKED], "whether each function should go in its own section"), future_incompat_test: bool = (false, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 20a67d6d036..e79d7648bef 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1,7 +1,7 @@ use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo}; use crate::config::{ - self, CrateType, InstrumentCoverage, OptLevel, OutFileName, OutputType, + self, CrateType, FunctionReturn, InstrumentCoverage, OptLevel, OutFileName, OutputType, RemapPathScopeComponents, SwitchWithOptPath, }; use crate::config::{ErrorOutputType, Input}; @@ -1678,6 +1678,28 @@ fn validate_commandline_args_with_session_available(sess: &Session) { sess.emit_err(errors::IncompatibleLinkerFlavor { flavor, compatible_list }); } } + + if sess.opts.unstable_opts.function_return != FunctionReturn::default() { + if sess.target.arch != "x86" && sess.target.arch != "x86_64" { + sess.emit_err(errors::FunctionReturnRequiresX86OrX8664); + } + } + + // The code model check applies to `thunk` and `thunk-extern`, but not `thunk-inline`, so it is + // kept as a `match` to force a change if new ones are added, even if we currently only support + // `thunk-extern` like Clang. + match sess.opts.unstable_opts.function_return { + FunctionReturn::Keep => (), + FunctionReturn::ThunkExtern => { + // FIXME: In principle, the inherited base LLVM target code model could be large, + // but this only checks whether we were passed one explicitly (like Clang does). + if let Some(code_model) = sess.code_model() + && code_model == CodeModel::Large + { + sess.emit_err(errors::FunctionReturnThunkExternRequiresNonLargeCodeModel); + } + } + } } /// Holds data on the current incremental compilation session, if there is one. diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index 62a26bc089a..e9b835f90db 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -578,13 +578,13 @@ impl<'tcx> Stable<'tcx> for mir::TerminatorKind<'tcx> { } mir::TerminatorKind::SwitchInt { discr, targets } => TerminatorKind::SwitchInt { discr: discr.stable(tables), - targets: targets - .iter() - .map(|(value, target)| stable_mir::mir::SwitchTarget { - value, - target: target.as_usize(), - }) - .collect(), + targets: { + let (value_vec, mut target_vec): (Vec<_>, Vec<_>) = + targets.iter().map(|(value, target)| (value, target.as_usize())).unzip(); + // We need to push otherwise as last element to ensure it's same as in MIR. + target_vec.push(targets.otherwise().as_usize()); + stable_mir::mir::SwitchTargets { value: value_vec, targets: target_vec } + }, otherwise: targets.otherwise().as_usize(), }, mir::TerminatorKind::UnwindResume => TerminatorKind::Resume, diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 4b5bd75d5b1..b2d51ac6c0d 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -222,7 +222,6 @@ rustc_index::newtype_index! { } } -// njn: I don't understand these impl<E: Encoder> Encodable<E> for DefIndex { default fn encode(&self, _: &mut E) { panic!("cannot encode `DefIndex` with `{}`", std::any::type_name::<E>()); diff --git a/compiler/rustc_span/src/edit_distance.rs b/compiler/rustc_span/src/edit_distance.rs index 96a118e590f..14cb1d6d362 100644 --- a/compiler/rustc_span/src/edit_distance.rs +++ b/compiler/rustc_span/src/edit_distance.rs @@ -188,7 +188,11 @@ fn find_best_match_for_name_impl( return Some(*c); } - let mut dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3); + // `fn edit_distance()` use `chars()` to calculate edit distance, so we must + // also use `chars()` (and not `str::len()`) to calculate length here. + let lookup_len = lookup.chars().count(); + + let mut dist = dist.unwrap_or_else(|| cmp::max(lookup_len, 3) / 3); let mut best = None; // store the candidates with the same distance, only for `use_substring_score` current. let mut next_candidates = vec![]; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 40b03874242..9a2fe01229d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1097,6 +1097,7 @@ symbols! { negative_impls, neon, never, + never_patterns, never_type, never_type_fallback, new, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 9b0fedba092..dbce2f30f93 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1155,10 +1155,6 @@ pub enum StackProbeType { } impl StackProbeType { - // LLVM X86 targets (ix86 and x86_64) can use inline-asm stack probes starting with LLVM 16. - // Notable past issues were rust#83139 (fixed in 14) and rust#84667 (fixed in 16). - const X86: Self = Self::InlineOrCall { min_llvm_version_for_inline: (16, 0, 0) }; - fn from_json(json: &Json) -> Result<Self, String> { let object = json.as_object().ok_or_else(|| "expected a JSON object")?; let kind = object diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs index 88fa6d5a762..63a8144f69f 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs @@ -14,6 +14,11 @@ pub fn target() -> Target { let opts = TargetOptions { linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), + // Enable the Cortex-A53 errata 843419 mitigation by default + pre_link_args: TargetOptions::link_args( + LinkerFlavor::Gnu(Cc::No, Lld::No), + &["--fix-cortex-a53-843419"], + ), features: "+v8a,+strict-align,+neon,+fp-armv8".into(), supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, relocation_model: RelocModel::Static, diff --git a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs index ed2c990ffa6..ce0d604f57c 100644 --- a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs @@ -16,7 +16,7 @@ pub fn target() -> Target { arch: arch.target_arch(), options: TargetOptions { max_atomic_width: Some(64), - stack_probes: StackProbeType::X86, + stack_probes: StackProbeType::Inline, ..opts("ios", arch) }, } diff --git a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs b/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs index 06089391623..3ebf4bcf523 100644 --- a/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs +++ b/compiler/rustc_target/src/spec/targets/i586_pc_nto_qnx700.rs @@ -16,7 +16,7 @@ pub fn target() -> Target { &["-Vgcc_ntox86_cxx"], ), env: "nto70".into(), - stack_probes: StackProbeType::X86, + stack_probes: StackProbeType::Inline, ..base::nto_qnx::opts() }, } diff --git a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs index 242fe5ed98a..c4c9023419d 100644 --- a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { let mut base = opts("macos", arch); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m32"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; base.frame_pointer = FramePointer::Always; Target { diff --git a/compiler/rustc_target/src/spec/targets/i686_linux_android.rs b/compiler/rustc_target/src/spec/targets/i686_linux_android.rs index 987265598eb..79471040f0d 100644 --- a/compiler/rustc_target/src/spec/targets/i686_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/i686_linux_android.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { // https://developer.android.com/ndk/guides/abis.html#x86 base.cpu = "pentiumpro".into(); base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".into(); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; Target { llvm_target: "i686-linux-android".into(), diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs index 70aa0b47962..927b2ab877d 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_freebsd.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32", "-Wl,-znotext"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; Target { llvm_target: "i686-unknown-freebsd".into(), diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs index 9715f6c21d9..bc7fd6fbc68 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_haiku.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; Target { llvm_target: "i686-unknown-haiku".into(), diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs index 0ca058b2fd2..3b7be48dbbc 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_gnu.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { base.max_atomic_width = Some(64); base.supported_sanitizers = SanitizerSet::ADDRESS; base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; Target { llvm_target: "i686-unknown-linux-gnu".into(), diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs index ce0df3a7234..ef58b4fb458 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_linux_musl.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32", "-Wl,-melf_i386"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; // The unwinder used by i686-unknown-linux-musl, the LLVM libunwind // implementation, apparently relies on frame pointers existing... somehow. diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs index 2a3ac5932d3..5f3afbe5afd 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_netbsd.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; Target { llvm_target: "i686-unknown-netbsdelf".into(), diff --git a/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs index 45883542bea..f44584a10be 100644 --- a/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/i686_unknown_openbsd.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32", "-fuse-ld=lld"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; Target { llvm_target: "i686-unknown-openbsd".into(), diff --git a/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs index 965a895972c..ee501c5165e 100644 --- a/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/i686_wrs_vxworks.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { base.cpu = "pentium4".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m32"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; Target { llvm_target: "i686-unknown-linux-gnu".into(), diff --git a/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs index 75a65a26849..b80a5fbeacf 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32i_unknown_none_elf.rs @@ -11,8 +11,9 @@ pub fn target() -> Target { linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), cpu: "generic-rv32".into(), - max_atomic_width: Some(0), + max_atomic_width: Some(32), atomic_cas: false, + features: "+forced-atomics".into(), panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs index f2242bbe087..6480facb137 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32im_unknown_none_elf.rs @@ -11,9 +11,9 @@ pub fn target() -> Target { linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), cpu: "generic-rv32".into(), - max_atomic_width: Some(0), + max_atomic_width: Some(32), atomic_cas: false, - features: "+m".into(), + features: "+m,+forced-atomics".into(), panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs index 01e773fae97..13a621a6643 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32imc_unknown_none_elf.rs @@ -11,9 +11,9 @@ pub fn target() -> Target { linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), cpu: "generic-rv32".into(), - max_atomic_width: Some(0), + max_atomic_width: Some(32), atomic_cas: false, - features: "+m,+c".into(), + features: "+m,+c,+forced-atomics".into(), panic_strategy: PanicStrategy::Abort, relocation_model: RelocModel::Static, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs index 9170a10d254..81173a16f96 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { base.max_atomic_width = Some(128); // penryn+ supports cmpxchg16b base.frame_pointer = FramePointer::Always; base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m64"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD; diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs index d9f3f7de655..221635526d1 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs @@ -14,7 +14,7 @@ pub fn target() -> Target { arch: arch.target_arch(), options: TargetOptions { max_atomic_width: Some(128), - stack_probes: StackProbeType::X86, + stack_probes: StackProbeType::Inline, ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs index 5e6fbac34d7..5f6b4b500d0 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs @@ -17,7 +17,7 @@ pub fn target() -> Target { arch: arch.target_arch(), options: TargetOptions { max_atomic_width: Some(128), - stack_probes: StackProbeType::X86, + stack_probes: StackProbeType::Inline, ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs index 1c4d9196c18..a7d5f28e0e5 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { arch: arch.target_arch(), options: TargetOptions { max_atomic_width: Some(128), - stack_probes: StackProbeType::X86, + stack_probes: StackProbeType::Inline, ..opts("tvos", arch) }, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs index 9faf9b1ca3f..3c5bf30ef5f 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { arch: arch.target_arch(), options: TargetOptions { max_atomic_width: Some(128), - stack_probes: StackProbeType::X86, + stack_probes: StackProbeType::Inline, ..opts("watchos", arch) }, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs index 6cffda44fa9..0e6d41abc9b 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_linux_android.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { base.features = "+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; base.supports_xray = true; Target { diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs index ca6a6dc500b..f15ad8dda63 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { base.plt_by_default = false; base.vendor = "pc".into(); base.max_atomic_width = Some(64); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD; Target { diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs b/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs index c12cb1ab00e..e6159fca3ae 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unikraft_linux_musl.rs @@ -12,7 +12,7 @@ pub fn target() -> Target { plt_by_default: false, pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]), max_atomic_width: Some(64), - stack_probes: StackProbeType::X86, + stack_probes: StackProbeType::Inline, ..base::unikraft_linux_musl::opts() }, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs index 68d1a755b79..80adb8fa2d9 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_dragonfly.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; Target { llvm_target: "x86_64-unknown-dragonfly".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs index e3f29fa5afa..fa321035367 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_freebsd.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::MEMORY | SanitizerSet::THREAD; base.supports_xray = true; diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs index c8850d703e3..f0515615b19 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { base.cpu = "x86-64".into(); base.plt_by_default = false; base.max_atomic_width = Some(64); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI; Target { diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs index ca55e6514dd..0f927be962b 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_haiku.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; // This option is required to build executables on Haiku x86_64 base.position_independent_executables = true; diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs index 3cc50d40dda..df191f515bd 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_hermit.rs @@ -12,7 +12,7 @@ pub fn target() -> Target { features: "+rdrnd,+rdseed".into(), plt_by_default: false, max_atomic_width: Some(64), - stack_probes: StackProbeType::X86, + stack_probes: StackProbeType::Inline, ..base::hermit::opts() }, } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs index 80e267c163f..bf10f7e5d2d 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; base.static_position_independent_executables = true; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs index 622bfe8bbe8..1856c6afd52 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnux32.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { base.abi = "x32".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-mx32"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; base.has_thread_local = false; // BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI // breaks code gen. See LLVM bug 36743 diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs index d74ff466a01..8dc5503e336 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_musl.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; base.static_position_independent_executables = true; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs index 87b004df001..35862656aa2 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_ohos.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { base.cpu = "x86-64".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; base.static_position_independent_executables = true; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs index 04060513abc..e2cee0513ba 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_netbsd.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs index 9aa95a35f8e..8f7655d8ccd 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_none.rs @@ -12,7 +12,7 @@ pub fn target() -> Target { cpu: "x86-64".into(), plt_by_default: false, max_atomic_width: Some(64), - stack_probes: StackProbeType::X86, + stack_probes: StackProbeType::Inline, position_independent_executables: true, static_position_independent_executables: true, relro_level: RelroLevel::Full, diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs index 5e6e7efb2de..1133b50f3d2 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_openbsd.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; base.supports_xray = true; Target { diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs index 382ff71f019..c1f57311292 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_redox.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; Target { llvm_target: "x86_64-unknown-redox".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs index 4b221fe6959..765239bdd39 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_wrs_vxworks.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; base.disable_redzone = true; Target { diff --git a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs index a30e9d17cef..32d15c18678 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { base.max_atomic_width = Some(128); base.frame_pointer = FramePointer::Always; base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m64"]); - base.stack_probes = StackProbeType::X86; + base.stack_probes = StackProbeType::Inline; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD; diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index eb30b4cd85e..b6861d258d1 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -490,6 +490,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + #[instrument(level = "debug", skip_all)] fn assemble_unsize_to_dyn_candidate<G: GoalKind<'tcx>>( &mut self, goal: Goal<'tcx, G>, @@ -507,6 +508,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } + #[instrument(level = "debug", skip_all)] fn assemble_blanket_impl_candidates<G: GoalKind<'tcx>>( &mut self, goal: Goal<'tcx, G>, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index f8860ee87d2..5d404d7e3e9 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -146,7 +146,7 @@ pub trait InferCtxtEvalExt<'tcx> { } impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { - #[instrument(level = "debug", skip(self), ret)] + #[instrument(level = "debug", skip(self))] fn evaluate_root_goal( &self, goal: Goal<'tcx, ty::Predicate<'tcx>>, diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index b526fa19c13..b9e256236e9 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -288,6 +288,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// in [`EvalCtxt::assemble_candidates_via_self_ty`] does not have to normalize /// the self type. It is required when structurally matching on any other /// arguments of a trait goal, e.g. when assembling builtin unsize candidates. + #[instrument(level = "debug", skip(self), ret)] fn try_normalize_ty( &mut self, param_env: ty::ParamEnv<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 5d5440094fd..8268273884d 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -192,7 +192,7 @@ fn lint_object_unsafe_trait( ); if node.is_some() { // Only provide the help if its a local trait, otherwise it's not - violation.solution(err); + violation.solution().add_to(err); } err }, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 8f5afdf0a1f..3be14951703 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1454,7 +1454,18 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>( // Infer the generic parameters of the impl by unifying the // impl type with the self type of the projection. - let self_ty = alias_ty.self_ty(); + let mut self_ty = alias_ty.self_ty(); + if !selcx.infcx.next_trait_solver() { + self_ty = normalize_with_depth_to( + selcx, + param_env, + cause.clone(), + depth + 1, + self_ty, + obligations, + ); + } + match selcx.infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, impl_ty, self_ty) { Ok(mut ok) => obligations.append(&mut ok.obligations), Err(_) => { diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 612123e7901..82cd0cc50d2 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -254,13 +254,12 @@ fn associated_type_for_impl_trait_in_trait( assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait); let span = tcx.def_span(opaque_ty_def_id); - let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, DefPathData::ImplTraitAssocTy); + let trait_assoc_ty = + tcx.at(span).create_def(trait_def_id, DefPathData::ImplTraitAssocTy, DefKind::AssocTy); let local_def_id = trait_assoc_ty.def_id(); let def_id = local_def_id.to_def_id(); - trait_assoc_ty.def_kind(DefKind::AssocTy); - // There's no HIR associated with this new synthesized `def_id`, so feed // `opt_local_def_id_to_hir_id` with `None`. trait_assoc_ty.opt_local_def_id_to_hir_id(None); @@ -357,13 +356,12 @@ fn associated_type_for_impl_trait_in_impl( hir::FnRetTy::DefaultReturn(_) => tcx.def_span(impl_fn_def_id), hir::FnRetTy::Return(ty) => ty.span, }; - let impl_assoc_ty = tcx.at(span).create_def(impl_local_def_id, DefPathData::ImplTraitAssocTy); + let impl_assoc_ty = + tcx.at(span).create_def(impl_local_def_id, DefPathData::ImplTraitAssocTy, DefKind::AssocTy); let local_def_id = impl_assoc_ty.def_id(); let def_id = local_def_id.to_def_id(); - impl_assoc_ty.def_kind(DefKind::AssocTy); - // There's no HIR associated with this new synthesized `def_id`, so feed // `opt_local_def_id_to_hir_id` with `None`. impl_assoc_ty.opt_local_def_id_to_hir_id(None); diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index 1f75dfb69cf..2099c485c6f 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -16,7 +16,7 @@ //! //! The goal is to eventually be published on //! [crates.io](https://crates.io). - +#![feature(type_alias_impl_trait)] #[macro_use] extern crate scoped_tls; @@ -184,7 +184,7 @@ impl std::fmt::Display for Opaque { impl std::fmt::Debug for Opaque { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.0) + write!(f, "{}", self.0) } } diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 8d237fc9f1d..02a28687676 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -1,10 +1,9 @@ -use crate::mir::pretty::{function_body, pretty_statement}; +use crate::mir::pretty::{function_body, pretty_statement, pretty_terminator}; use crate::ty::{ AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind, }; use crate::{Error, Opaque, Span, Symbol}; -use std::io; - +use std::{io, slice}; /// The SMIR representation of a single function. #[derive(Clone, Debug)] pub struct Body { @@ -83,6 +82,8 @@ impl Body { Ok(()) }) .collect::<Vec<_>>(); + pretty_terminator(&block.terminator.kind, w)?; + writeln!(w, "").unwrap(); writeln!(w, " }}").unwrap(); Ok(()) }) @@ -100,7 +101,7 @@ pub struct LocalDecl { pub mutability: Mutability, } -#[derive(Clone, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] pub struct BasicBlock { pub statements: Vec<Statement>, pub terminator: Terminator, @@ -112,6 +113,14 @@ pub struct Terminator { pub span: Span, } +impl Terminator { + pub fn successors(&self) -> Successors<'_> { + self.kind.successors() + } +} + +pub type Successors<'a> = impl Iterator<Item = usize> + 'a; + #[derive(Clone, Debug, Eq, PartialEq)] pub enum TerminatorKind { Goto { @@ -119,7 +128,7 @@ pub enum TerminatorKind { }, SwitchInt { discr: Operand, - targets: Vec<SwitchTarget>, + targets: SwitchTargets, otherwise: usize, }, Resume, @@ -156,6 +165,58 @@ pub enum TerminatorKind { }, } +impl TerminatorKind { + pub fn successors(&self) -> Successors<'_> { + use self::TerminatorKind::*; + match *self { + Call { target: Some(t), unwind: UnwindAction::Cleanup(ref u), .. } + | Drop { target: t, unwind: UnwindAction::Cleanup(ref u), .. } + | Assert { target: t, unwind: UnwindAction::Cleanup(ref u), .. } + | InlineAsm { destination: Some(t), unwind: UnwindAction::Cleanup(ref u), .. } => { + Some(t).into_iter().chain(slice::from_ref(u).into_iter().copied()) + } + Goto { target: t } + | Call { target: None, unwind: UnwindAction::Cleanup(t), .. } + | Call { target: Some(t), unwind: _, .. } + | Drop { target: t, unwind: _, .. } + | Assert { target: t, unwind: _, .. } + | InlineAsm { destination: None, unwind: UnwindAction::Cleanup(t), .. } + | InlineAsm { destination: Some(t), unwind: _, .. } => { + Some(t).into_iter().chain((&[]).into_iter().copied()) + } + + CoroutineDrop + | Return + | Resume + | Abort + | Unreachable + | Call { target: None, unwind: _, .. } + | InlineAsm { destination: None, unwind: _, .. } => { + None.into_iter().chain((&[]).into_iter().copied()) + } + SwitchInt { ref targets, .. } => { + None.into_iter().chain(targets.targets.iter().copied()) + } + } + } + + pub fn unwind(&self) -> Option<&UnwindAction> { + match *self { + TerminatorKind::Goto { .. } + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::CoroutineDrop + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::SwitchInt { .. } => None, + TerminatorKind::Call { ref unwind, .. } + | TerminatorKind::Assert { ref unwind, .. } + | TerminatorKind::Drop { ref unwind, .. } + | TerminatorKind::InlineAsm { ref unwind, .. } => Some(unwind), + } + } +} + #[derive(Clone, Debug, Eq, PartialEq)] pub struct InlineAsmOperand { pub in_value: Option<Operand>, @@ -602,9 +663,9 @@ pub struct Constant { } #[derive(Clone, Debug, Eq, PartialEq)] -pub struct SwitchTarget { - pub value: u128, - pub target: usize, +pub struct SwitchTargets { + pub value: Vec<u128>, + pub targets: Vec<usize>, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs index e7bca295b5a..759c3b148df 100644 --- a/compiler/stable_mir/src/mir/pretty.rs +++ b/compiler/stable_mir/src/mir/pretty.rs @@ -1,7 +1,11 @@ use crate::crate_def::CrateDef; -use crate::mir::{Operand, Rvalue, StatementKind}; +use crate::mir::{Operand, Rvalue, StatementKind, UnwindAction}; use crate::ty::{DynKind, FloatTy, IntTy, RigidTy, TyKind, UintTy}; use crate::{with, Body, CrateItem, Mutability}; +use std::io::Write; +use std::{io, iter}; + +use super::{AssertMessage, BinOp, TerminatorKind}; pub fn function_name(item: CrateItem) -> String { let mut pretty_name = String::new(); @@ -70,6 +74,209 @@ pub fn pretty_statement(statement: &StatementKind) -> String { pretty } +pub fn pretty_terminator<W: io::Write>(terminator: &TerminatorKind, w: &mut W) -> io::Result<()> { + write!(w, "{}", pretty_terminator_head(terminator))?; + let successor_count = terminator.successors().count(); + let labels = pretty_successor_labels(terminator); + + let show_unwind = !matches!(terminator.unwind(), None | Some(UnwindAction::Cleanup(_))); + let fmt_unwind = |fmt: &mut dyn Write| -> io::Result<()> { + write!(fmt, "unwind ")?; + match terminator.unwind() { + None | Some(UnwindAction::Cleanup(_)) => unreachable!(), + Some(UnwindAction::Continue) => write!(fmt, "continue"), + Some(UnwindAction::Unreachable) => write!(fmt, "unreachable"), + Some(UnwindAction::Terminate) => write!(fmt, "terminate"), + } + }; + + match (successor_count, show_unwind) { + (0, false) => Ok(()), + (0, true) => { + write!(w, " -> ")?; + fmt_unwind(w)?; + Ok(()) + } + (1, false) => { + write!(w, " -> {:?}", terminator.successors().next().unwrap())?; + Ok(()) + } + _ => { + write!(w, " -> [")?; + for (i, target) in terminator.successors().enumerate() { + if i > 0 { + write!(w, ", ")?; + } + write!(w, "{}: bb{:?}", labels[i], target)?; + } + if show_unwind { + write!(w, ", ")?; + fmt_unwind(w)?; + } + write!(w, "]") + } + }?; + + Ok(()) +} + +pub fn pretty_terminator_head(terminator: &TerminatorKind) -> String { + use self::TerminatorKind::*; + let mut pretty = String::new(); + match terminator { + Goto { .. } => format!(" goto"), + SwitchInt { discr, .. } => { + format!(" switchInt(_{})", pretty_operand(discr)) + } + Resume => format!(" resume"), + Abort => format!(" abort"), + Return => format!(" return"), + Unreachable => format!(" unreachable"), + Drop { place, .. } => format!(" drop(_{:?})", place.local), + Call { func, args, destination, .. } => { + pretty.push_str(" "); + pretty.push_str(format!("_{} = ", destination.local).as_str()); + pretty.push_str(&pretty_operand(func)); + pretty.push_str("("); + args.iter().enumerate().for_each(|(i, arg)| { + if i > 0 { + pretty.push_str(", "); + } + pretty.push_str(&pretty_operand(arg)); + }); + pretty.push_str(")"); + pretty + } + Assert { cond, expected, msg, target: _, unwind: _ } => { + pretty.push_str(" assert("); + if !expected { + pretty.push_str("!"); + } + pretty.push_str(format!("{} bool),", &pretty_operand(cond)).as_str()); + pretty.push_str(&pretty_assert_message(msg)); + pretty.push_str(")"); + pretty + } + CoroutineDrop => format!(" coroutine_drop"), + InlineAsm { .. } => todo!(), + } +} + +pub fn pretty_successor_labels(terminator: &TerminatorKind) -> Vec<String> { + use self::TerminatorKind::*; + match terminator { + Resume | Abort | Return | Unreachable | CoroutineDrop => vec![], + Goto { .. } => vec!["".to_string()], + SwitchInt { targets, .. } => targets + .value + .iter() + .map(|target| format!("{}", target)) + .chain(iter::once("otherwise".into())) + .collect(), + Drop { unwind: UnwindAction::Cleanup(_), .. } => vec!["return".into(), "unwind".into()], + Drop { unwind: _, .. } => vec!["return".into()], + Call { target: Some(_), unwind: UnwindAction::Cleanup(_), .. } => { + vec!["return".into(), "unwind".into()] + } + Call { target: Some(_), unwind: _, .. } => vec!["return".into()], + Call { target: None, unwind: UnwindAction::Cleanup(_), .. } => vec!["unwind".into()], + Call { target: None, unwind: _, .. } => vec![], + Assert { unwind: UnwindAction::Cleanup(_), .. } => { + vec!["success".into(), "unwind".into()] + } + Assert { unwind: _, .. } => vec!["success".into()], + InlineAsm { .. } => todo!(), + } +} + +pub fn pretty_assert_message(msg: &AssertMessage) -> String { + let mut pretty = String::new(); + match msg { + AssertMessage::BoundsCheck { len, index } => { + let pretty_len = pretty_operand(len); + let pretty_index = pretty_operand(index); + pretty.push_str(format!("\"index out of bounds: the length is {{}} but the index is {{}}\", {pretty_len}, {pretty_index}").as_str()); + pretty + } + AssertMessage::Overflow(BinOp::Add, l, r) => { + let pretty_l = pretty_operand(l); + let pretty_r = pretty_operand(r); + pretty.push_str(format!("\"attempt to compute `{{}} + {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str()); + pretty + } + AssertMessage::Overflow(BinOp::Sub, l, r) => { + let pretty_l = pretty_operand(l); + let pretty_r = pretty_operand(r); + pretty.push_str(format!("\"attempt to compute `{{}} - {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str()); + pretty + } + AssertMessage::Overflow(BinOp::Mul, l, r) => { + let pretty_l = pretty_operand(l); + let pretty_r = pretty_operand(r); + pretty.push_str(format!("\"attempt to compute `{{}} * {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str()); + pretty + } + AssertMessage::Overflow(BinOp::Div, l, r) => { + let pretty_l = pretty_operand(l); + let pretty_r = pretty_operand(r); + pretty.push_str(format!("\"attempt to compute `{{}} / {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str()); + pretty + } + AssertMessage::Overflow(BinOp::Rem, l, r) => { + let pretty_l = pretty_operand(l); + let pretty_r = pretty_operand(r); + pretty.push_str(format!("\"attempt to compute `{{}} % {{}}`, which would overflow\", {pretty_l}, {pretty_r}").as_str()); + pretty + } + AssertMessage::Overflow(BinOp::Shr, _, r) => { + let pretty_r = pretty_operand(r); + pretty.push_str( + format!("\"attempt to shift right by `{{}}`, which would overflow\", {pretty_r}") + .as_str(), + ); + pretty + } + AssertMessage::Overflow(BinOp::Shl, _, r) => { + let pretty_r = pretty_operand(r); + pretty.push_str( + format!("\"attempt to shift left by `{{}}`, which would overflow\", {pretty_r}") + .as_str(), + ); + pretty + } + AssertMessage::OverflowNeg(op) => { + let pretty_op = pretty_operand(op); + pretty.push_str( + format!("\"attempt to negate `{{}}`, which would overflow\", {pretty_op}").as_str(), + ); + pretty + } + AssertMessage::DivisionByZero(op) => { + let pretty_op = pretty_operand(op); + pretty.push_str(format!("\"attempt to divide `{{}}` by zero\", {pretty_op}").as_str()); + pretty + } + AssertMessage::RemainderByZero(op) => { + let pretty_op = pretty_operand(op); + pretty.push_str( + format!("\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {pretty_op}").as_str(), + ); + pretty + } + AssertMessage::ResumedAfterReturn(_) => { + format!("attempt to resume a generator after completion") + } + AssertMessage::ResumedAfterPanic(_) => format!("attempt to resume a panicked generator"), + AssertMessage::MisalignedPointerDereference { required, found } => { + let pretty_required = pretty_operand(required); + let pretty_found = pretty_operand(found); + pretty.push_str(format!("\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\",{pretty_required}, {pretty_found}").as_str()); + pretty + } + _ => todo!(), + } +} + pub fn pretty_operand(operand: &Operand) -> String { let mut pretty = String::new(); match operand { diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 63aec14f481..e8afed6b35a 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -17,11 +17,11 @@ rand = { version = "0.8.5", default-features = false, features = ["alloc"] } rand_xorshift = "0.3.0" [[test]] -name = "collectionstests" +name = "alloctests" path = "tests/lib.rs" [[bench]] -name = "collectionsbenches" +name = "allocbenches" path = "benches/lib.rs" test = true diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index f83c8f83cc9..a8005b7067d 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -171,6 +171,7 @@ struct WithHeader<H>(NonNull<u8>, PhantomData<H>); /// An opaque representation of `WithHeader<H>` to avoid the /// projection invariance of `<T as Pointee>::Metadata`. #[repr(transparent)] +#[allow(unused_tuple_struct_fields)] // Field only used through `WithHeader` type above. struct WithOpaqueHeader(NonNull<u8>); impl WithOpaqueHeader { diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index 61c5950b027..00a101541c5 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -145,7 +145,7 @@ use core::alloc::Allocator; use core::fmt; -use core::iter::{FusedIterator, InPlaceIterable, SourceIter, TrustedLen}; +use core::iter::{FusedIterator, InPlaceIterable, SourceIter, TrustedFused, TrustedLen}; use core::mem::{self, swap, ManuallyDrop}; use core::num::NonZeroUsize; use core::ops::{Deref, DerefMut}; @@ -1542,6 +1542,10 @@ impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> { #[stable(feature = "fused", since = "1.26.0")] impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {} +#[doc(hidden)] +#[unstable(issue = "none", feature = "trusted_fused")] +unsafe impl<T, A: Allocator> TrustedFused for IntoIter<T, A> {} + #[stable(feature = "default_iters", since = "1.70.0")] impl<T> Default for IntoIter<T> { /// Creates an empty `binary_heap::IntoIter`. @@ -1571,7 +1575,10 @@ unsafe impl<T, A: Allocator> SourceIter for IntoIter<T, A> { #[unstable(issue = "none", feature = "inplace_iteration")] #[doc(hidden)] -unsafe impl<I, A: Allocator> InPlaceIterable for IntoIter<I, A> {} +unsafe impl<I, A: Allocator> InPlaceIterable for IntoIter<I, A> { + const EXPAND_BY: Option<NonZeroUsize> = NonZeroUsize::new(1); + const MERGE_BY: Option<NonZeroUsize> = NonZeroUsize::new(1); +} unsafe impl<I> AsVecIntoIter for IntoIter<I> { type Item = I; diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 59b2433ca74..0af3ac38ee5 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -154,6 +154,7 @@ #![feature(std_internals)] #![feature(str_internals)] #![feature(strict_provenance)] +#![feature(trusted_fused)] #![feature(trusted_len)] #![feature(trusted_random_access)] #![feature(try_trait_v2)] diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs index 5ecd0479971..e4f96fd7640 100644 --- a/library/alloc/src/vec/in_place_collect.rs +++ b/library/alloc/src/vec/in_place_collect.rs @@ -6,11 +6,11 @@ //! The specialization in this module applies to iterators in the shape of //! `source.adapter().adapter().adapter().collect::<Vec<U>>()` //! where `source` is an owning iterator obtained from [`Vec<T>`], [`Box<[T]>`][box] (by conversion to `Vec`) -//! or [`BinaryHeap<T>`], the adapters each consume one or more items per step -//! (represented by [`InPlaceIterable`]), provide transitive access to `source` (via [`SourceIter`]) -//! and thus the underlying allocation. And finally the layouts of `T` and `U` must -//! have the same size and alignment, this is currently ensured via const eval instead of trait bounds -//! in the specialized [`SpecFromIter`] implementation. +//! or [`BinaryHeap<T>`], the adapters guarantee to consume enough items per step to make room +//! for the results (represented by [`InPlaceIterable`]), provide transitive access to `source` +//! (via [`SourceIter`]) and thus the underlying allocation. +//! And finally there are alignment and size constriants to consider, this is currently ensured via +//! const eval instead of trait bounds in the specialized [`SpecFromIter`] implementation. //! //! [`BinaryHeap<T>`]: crate::collections::BinaryHeap //! [box]: crate::boxed::Box @@ -35,11 +35,28 @@ //! the step of reading a value and getting a reference to write to. Instead raw pointers must be //! used on the reader and writer side. //! -//! That writes never clobber a yet-to-be-read item is ensured by the [`InPlaceIterable`] requirements. +//! That writes never clobber a yet-to-be-read items is ensured by the [`InPlaceIterable`] requirements. //! //! # Layout constraints //! -//! [`Allocator`] requires that `allocate()` and `deallocate()` have matching alignment and size. +//! When recycling an allocation between different types we must uphold the [`Allocator`] contract +//! which means that the input and output Layouts have to "fit". +//! +//! To complicate things further `InPlaceIterable` supports splitting or merging items into smaller/ +//! larger ones to enable (de)aggregation of arrays. +//! +//! Ultimately each step of the iterator must free up enough *bytes* in the source to make room +//! for the next output item. +//! If `T` and `U` have the same size no fixup is needed. +//! If `T`'s size is a multiple of `U`'s we can compensate by multiplying the capacity accordingly. +//! Otherwise the input capacity (and thus layout) in bytes may not be representable by the output +//! `Vec<U>`. In that case `alloc.shrink()` is used to update the allocation's layout. +//! +//! Alignments of `T` must be the same or larger than `U`. Since alignments are always a power +//! of two _larger_ implies _is a multiple of_. +//! +//! See `in_place_collectible()` for the current conditions. +//! //! Additionally this specialization doesn't make sense for ZSTs as there is no reallocation to //! avoid and it would make pointer arithmetic more difficult. //! @@ -137,44 +154,73 @@ //! } //! vec.truncate(write_idx); //! ``` +use crate::alloc::{handle_alloc_error, Global}; +use core::alloc::Allocator; +use core::alloc::Layout; use core::iter::{InPlaceIterable, SourceIter, TrustedRandomAccessNoCoerce}; use core::mem::{self, ManuallyDrop, SizedTypeProperties}; -use core::ptr::{self}; +use core::num::NonZeroUsize; +use core::ptr::{self, NonNull}; use super::{InPlaceDrop, InPlaceDstBufDrop, SpecFromIter, SpecFromIterNested, Vec}; -/// Specialization marker for collecting an iterator pipeline into a Vec while reusing the -/// source allocation, i.e. executing the pipeline in place. -#[rustc_unsafe_specialization_marker] -pub(super) trait InPlaceIterableMarker {} +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>() { + return false; + } + + match (step_merge, step_expand) { + (Some(step_merge), Some(step_expand)) => { + // At least N merged source items -> at most M expanded destination items + // e.g. + // - 1 x [u8; 4] -> 4x u8, via flatten + // - 4 x u8 -> 1x [u8; 4], via array_chunks + mem::size_of::<SRC>() * step_merge.get() >= mem::size_of::<DEST>() * step_expand.get() + } + // Fall back to other from_iter impls if an overflow occurred in the step merge/expansion + // tracking. + _ => false, + } +} -impl<T> InPlaceIterableMarker for T where T: InPlaceIterable {} +/// 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 { + type Src; +} + +impl<T> InPlaceCollect for T +where + T: SourceIter<Source: AsVecIntoIter> + InPlaceIterable, +{ + type Src = <<T as SourceIter>::Source as AsVecIntoIter>::Item; +} impl<T, I> SpecFromIter<T, I> for Vec<T> where - I: Iterator<Item = T> + SourceIter<Source: AsVecIntoIter> + InPlaceIterableMarker, + I: Iterator<Item = T> + InPlaceCollect, + <I as SourceIter>::Source: AsVecIntoIter, { default fn from_iter(mut iterator: I) -> Self { // See "Layout constraints" section in the module documentation. We rely on const // optimization here since these conditions currently cannot be expressed as trait bounds - if T::IS_ZST - || mem::size_of::<T>() - != mem::size_of::<<<I as SourceIter>::Source as AsVecIntoIter>::Item>() - || mem::align_of::<T>() - != mem::align_of::<<<I as SourceIter>::Source as AsVecIntoIter>::Item>() - { + if const { !in_place_collectible::<T, I::Src>(I::MERGE_BY, I::EXPAND_BY) } { // fallback to more generic implementations return SpecFromIterNested::from_iter(iterator); } - let (src_buf, src_ptr, dst_buf, dst_end, cap) = unsafe { + let (src_buf, src_ptr, src_cap, mut dst_buf, dst_end, dst_cap) = unsafe { let inner = iterator.as_inner().as_into_iter(); ( inner.buf.as_ptr(), inner.ptr, + inner.cap, inner.buf.as_ptr() as *mut T, inner.end as *const T, - inner.cap, + inner.cap * mem::size_of::<I::Src>() / mem::size_of::<T>(), ) }; @@ -196,18 +242,55 @@ where } // The ownership of the allocation and the new `T` values is temporarily moved into `dst_guard`. - // This is safe because `forget_allocation_drop_remaining` immediately forgets the allocation + // This is safe because + // * `forget_allocation_drop_remaining` immediately forgets the allocation // before any panic can occur in order to avoid any double free, and then proceeds to drop // any remaining values at the tail of the source. + // * the shrink either panics without invalidating the allocation, aborts or + // succeeds. In the last case we disarm the guard. // // Note: This access to the source wouldn't be allowed by the TrustedRandomIteratorNoCoerce // contract (used by SpecInPlaceCollect below). But see the "O(1) collect" section in the // module documentation why this is ok anyway. - let dst_guard = InPlaceDstBufDrop { ptr: dst_buf, len, cap }; + let dst_guard = InPlaceDstBufDrop { ptr: dst_buf, len, cap: dst_cap }; src.forget_allocation_drop_remaining(); + + // Adjust the allocation if the alignment didn't match or the source had a capacity in bytes + // 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>() } + { + let alloc = Global; + unsafe { + // The old allocation exists, therefore it must have a valid layout. + let src_align = mem::align_of::<I::Src>(); + let src_size = mem::size_of::<I::Src>().unchecked_mul(src_cap); + let old_layout = Layout::from_size_align_unchecked(src_size, src_align); + + // The must be equal or smaller for in-place iteration to be possible + // therefore the new layout must be ≤ the old one and therefore valid. + let dst_align = mem::align_of::<T>(); + let dst_size = mem::size_of::<T>().unchecked_mul(dst_cap); + let new_layout = Layout::from_size_align_unchecked(dst_size, dst_align); + + let result = alloc.shrink( + NonNull::new_unchecked(dst_buf as *mut u8), + old_layout, + new_layout, + ); + let Ok(reallocated) = result else { handle_alloc_error(new_layout) }; + dst_buf = reallocated.as_ptr() as *mut T; + } + } + mem::forget(dst_guard); - let vec = unsafe { Vec::from_raw_parts(dst_buf, len, cap) }; + let vec = unsafe { Vec::from_raw_parts(dst_buf, len, dst_cap) }; vec } diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index d51f5a548b5..b03e04b7c70 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -7,7 +7,8 @@ use crate::raw_vec::RawVec; use core::array; use core::fmt; use core::iter::{ - FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce, + FusedIterator, InPlaceIterable, SourceIter, TrustedFused, TrustedLen, + TrustedRandomAccessNoCoerce, }; use core::marker::PhantomData; use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties}; @@ -337,6 +338,10 @@ impl<T, A: Allocator> ExactSizeIterator for IntoIter<T, A> { #[stable(feature = "fused", since = "1.26.0")] impl<T, A: Allocator> FusedIterator for IntoIter<T, A> {} +#[doc(hidden)] +#[unstable(issue = "none", feature = "trusted_fused")] +unsafe impl<T, A: Allocator> TrustedFused for IntoIter<T, A> {} + #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<T, A: Allocator> TrustedLen for IntoIter<T, A> {} @@ -421,7 +426,10 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for IntoIter<T, A> { // also refer to the vec::in_place_collect module documentation to get an overview #[unstable(issue = "none", feature = "inplace_iteration")] #[doc(hidden)] -unsafe impl<T, A: Allocator> InPlaceIterable for IntoIter<T, A> {} +unsafe impl<T, A: Allocator> InPlaceIterable for IntoIter<T, A> { + const EXPAND_BY: Option<NonZeroUsize> = NonZeroUsize::new(1); + const MERGE_BY: Option<NonZeroUsize> = NonZeroUsize::new(1); +} #[unstable(issue = "none", feature = "inplace_iteration")] #[doc(hidden)] diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 6d5c17ef023..ded6b2079d2 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -1,5 +1,6 @@ #![feature(allocator_api)] #![feature(alloc_layout_extra)] +#![feature(iter_array_chunks)] #![feature(assert_matches)] #![feature(btree_extract_if)] #![feature(cow_is_borrowed)] diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index cb59a9d4ab2..df8a260624a 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1171,6 +1171,17 @@ fn test_iterator() { } #[test] +fn test_iterator_advance() { + let s = "「赤錆」と呼ばれる鉄錆は、水の存在下での鉄の自然酸化によって生じる、オキシ水酸化鉄(III) 等の(含水)酸化物粒子の疎な凝集膜であるとみなせる。"; + let chars: Vec<char> = s.chars().collect(); + let mut it = s.chars(); + it.advance_by(1).unwrap(); + assert_eq!(it.next(), Some(chars[1])); + it.advance_by(33).unwrap(); + assert_eq!(it.next(), Some(chars[35])); +} + +#[test] fn test_rev_iterator() { let s = "ศไทย中华Việt Nam"; let v = ['m', 'a', 'N', ' ', 't', 'ệ', 'i', 'V', '华', '中', 'ย', 'ท', 'ไ', 'ศ']; diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index d44dcfbf673..81de7085e09 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1,6 +1,7 @@ +use alloc::vec::Vec; use core::alloc::{Allocator, Layout}; -use core::assert_eq; -use core::iter::IntoIterator; +use core::{assert_eq, assert_ne}; +use core::iter::{IntoIterator, Iterator}; use core::num::NonZeroUsize; use core::ptr::NonNull; use std::alloc::System; @@ -1185,6 +1186,46 @@ fn test_from_iter_specialization_with_iterator_adapters() { } #[test] +fn test_in_place_specialization_step_up_down() { + fn assert_in_place_trait<T: InPlaceIterable>(_: &T) {} + let src = vec![[0u8; 4]; 256]; + let srcptr = src.as_ptr(); + let src_cap = src.capacity(); + let iter = src.into_iter().flatten(); + assert_in_place_trait(&iter); + let sink = iter.collect::<Vec<_>>(); + let sinkptr = sink.as_ptr(); + assert_eq!(srcptr as *const u8, sinkptr); + assert_eq!(src_cap * 4, sink.capacity()); + + let iter = sink.into_iter().array_chunks::<4>(); + assert_in_place_trait(&iter); + let sink = iter.collect::<Vec<_>>(); + let sinkptr = sink.as_ptr(); + assert_eq!(srcptr, sinkptr); + assert_eq!(src_cap, sink.capacity()); + + let mut src: Vec<u8> = Vec::with_capacity(17); + let src_bytes = src.capacity(); + src.resize(8, 0u8); + let sink: Vec<[u8; 4]> = src.into_iter().array_chunks::<4>().collect(); + let sink_bytes = sink.capacity() * 4; + assert_ne!(src_bytes, sink_bytes); + assert_eq!(sink.len(), 2); + + let src = vec![[0u8; 4]; 256]; + let srcptr = src.as_ptr(); + let iter = src + .into_iter() + .flat_map(|a| { + a.into_iter().map(|b| b.wrapping_add(1)) + }); + assert_in_place_trait(&iter); + let sink = iter.collect::<Vec<_>>(); + assert_eq!(srcptr as *const u8, sink.as_ptr()); +} + +#[test] fn test_from_iter_specialization_head_tail_drop() { let drop_count: Vec<_> = (0..=2).map(|_| Rc::new(())).collect(); let src: Vec<_> = drop_count.iter().cloned().collect(); diff --git a/library/core/benches/lib.rs b/library/core/benches/lib.rs index 74ef0949b8a..fdefc9a714e 100644 --- a/library/core/benches/lib.rs +++ b/library/core/benches/lib.rs @@ -5,6 +5,7 @@ #![feature(trusted_random_access)] #![feature(iter_array_chunks)] #![feature(iter_next_chunk)] +#![feature(iter_advance_by)] extern crate test; diff --git a/library/core/benches/str.rs b/library/core/benches/str.rs index 78865d81fb9..7d36eff3d6c 100644 --- a/library/core/benches/str.rs +++ b/library/core/benches/str.rs @@ -3,6 +3,7 @@ use test::{black_box, Bencher}; mod char_count; mod corpora; +mod iter; #[bench] fn str_validate_emoji(b: &mut Bencher) { diff --git a/library/core/benches/str/iter.rs b/library/core/benches/str/iter.rs new file mode 100644 index 00000000000..58ae71fc10f --- /dev/null +++ b/library/core/benches/str/iter.rs @@ -0,0 +1,17 @@ +use super::corpora; +use test::{black_box, Bencher}; + +#[bench] +fn chars_advance_by_1000(b: &mut Bencher) { + b.iter(|| black_box(corpora::ru::LARGE).chars().advance_by(1000)); +} + +#[bench] +fn chars_advance_by_0010(b: &mut Bencher) { + b.iter(|| black_box(corpora::ru::LARGE).chars().advance_by(10)); +} + +#[bench] +fn chars_advance_by_0001(b: &mut Bencher) { + b.iter(|| black_box(corpora::ru::LARGE).chars().advance_by(1)); +} diff --git a/library/core/src/internal_macros.rs b/library/core/src/internal_macros.rs index 5774107f520..bf53b2245ac 100644 --- a/library/core/src/internal_macros.rs +++ b/library/core/src/internal_macros.rs @@ -31,6 +31,7 @@ macro_rules! forward_ref_binop { type Output = <$t as $imp<$u>>::Output; #[inline] + #[track_caller] fn $method(self, other: $u) -> <$t as $imp<$u>>::Output { $imp::$method(*self, other) } @@ -41,6 +42,7 @@ macro_rules! forward_ref_binop { type Output = <$t as $imp<$u>>::Output; #[inline] + #[track_caller] fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output { $imp::$method(self, *other) } @@ -51,6 +53,7 @@ macro_rules! forward_ref_binop { type Output = <$t as $imp<$u>>::Output; #[inline] + #[track_caller] fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output { $imp::$method(*self, *other) } @@ -69,6 +72,7 @@ macro_rules! forward_ref_op_assign { #[$attr] impl $imp<&$u> for $t { #[inline] + #[track_caller] fn $method(&mut self, other: &$u) { $imp::$method(self, *other); } diff --git a/library/core/src/iter/adapters/array_chunks.rs b/library/core/src/iter/adapters/array_chunks.rs index 13719c727e9..319af4408d7 100644 --- a/library/core/src/iter/adapters/array_chunks.rs +++ b/library/core/src/iter/adapters/array_chunks.rs @@ -1,5 +1,9 @@ use crate::array; -use crate::iter::{ByRefSized, FusedIterator, Iterator, TrustedRandomAccessNoCoerce}; +use crate::iter::adapters::SourceIter; +use crate::iter::{ + ByRefSized, FusedIterator, InPlaceIterable, Iterator, TrustedFused, TrustedRandomAccessNoCoerce, +}; +use crate::num::NonZeroUsize; use crate::ops::{ControlFlow, NeverShortCircuit, Try}; /// An iterator over `N` elements of the iterator at a time. @@ -159,6 +163,9 @@ where #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] impl<I, const N: usize> FusedIterator for ArrayChunks<I, N> where I: FusedIterator {} +#[unstable(issue = "none", feature = "trusted_fused")] +unsafe impl<I, const N: usize> TrustedFused for ArrayChunks<I, N> where I: TrustedFused + Iterator {} + #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] impl<I, const N: usize> ExactSizeIterator for ArrayChunks<I, N> where @@ -229,3 +236,28 @@ where accum } } + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<I, const N: usize> SourceIter for ArrayChunks<I, N> +where + I: SourceIter + Iterator, +{ + type Source = I::Source; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut I::Source { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<I: InPlaceIterable + Iterator, const N: usize> InPlaceIterable for ArrayChunks<I, N> { + const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY; + const MERGE_BY: Option<NonZeroUsize> = const { + match (I::MERGE_BY, NonZeroUsize::new(N)) { + (Some(m), Some(n)) => m.checked_mul(n), + _ => None, + } + }; +} diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index 00c1c377bf9..92f465ccdb4 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -1,7 +1,7 @@ use crate::iter::adapters::{ zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce, }; -use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; +use crate::iter::{FusedIterator, InPlaceIterable, TrustedFused, TrustedLen}; use crate::num::NonZeroUsize; use crate::ops::Try; @@ -243,6 +243,9 @@ where #[stable(feature = "fused", since = "1.26.0")] impl<I> FusedIterator for Enumerate<I> where I: FusedIterator {} +#[unstable(issue = "none", feature = "trusted_fused")] +unsafe impl<I: TrustedFused> TrustedFused for Enumerate<I> {} + #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<I> TrustedLen for Enumerate<I> where I: TrustedLen {} @@ -261,7 +264,10 @@ where } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<I: InPlaceIterable> InPlaceIterable for Enumerate<I> {} +unsafe impl<I: InPlaceIterable> InPlaceIterable for Enumerate<I> { + const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY; + const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY; +} #[stable(feature = "default_iters", since = "1.70.0")] impl<I: Default> Default for Enumerate<I> { diff --git a/library/core/src/iter/adapters/filter.rs b/library/core/src/iter/adapters/filter.rs index 723657b9e43..882f3e3bc60 100644 --- a/library/core/src/iter/adapters/filter.rs +++ b/library/core/src/iter/adapters/filter.rs @@ -1,5 +1,6 @@ use crate::fmt; -use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedFused}; +use crate::num::NonZeroUsize; use crate::ops::Try; use core::array; use core::mem::{ManuallyDrop, MaybeUninit}; @@ -189,6 +190,9 @@ where #[stable(feature = "fused", since = "1.26.0")] impl<I: FusedIterator, P> FusedIterator for Filter<I, P> where P: FnMut(&I::Item) -> bool {} +#[unstable(issue = "none", feature = "trusted_fused")] +unsafe impl<I: TrustedFused, F> TrustedFused for Filter<I, F> {} + #[unstable(issue = "none", feature = "inplace_iteration")] unsafe impl<P, I> SourceIter for Filter<I, P> where @@ -204,4 +208,7 @@ where } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<I: InPlaceIterable, P> InPlaceIterable for Filter<I, P> where P: FnMut(&I::Item) -> bool {} +unsafe impl<I: InPlaceIterable, P> InPlaceIterable for Filter<I, P> { + const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY; + const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY; +} diff --git a/library/core/src/iter/adapters/filter_map.rs b/library/core/src/iter/adapters/filter_map.rs index 32308c84d71..81ac0eaa67e 100644 --- a/library/core/src/iter/adapters/filter_map.rs +++ b/library/core/src/iter/adapters/filter_map.rs @@ -1,5 +1,6 @@ -use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedFused}; use crate::mem::{ManuallyDrop, MaybeUninit}; +use crate::num::NonZeroUsize; use crate::ops::{ControlFlow, Try}; use crate::{array, fmt}; @@ -190,6 +191,9 @@ where #[stable(feature = "fused", since = "1.26.0")] impl<B, I: FusedIterator, F> FusedIterator for FilterMap<I, F> where F: FnMut(I::Item) -> Option<B> {} +#[unstable(issue = "none", feature = "trusted_fused")] +unsafe impl<I: TrustedFused, F> TrustedFused for FilterMap<I, F> {} + #[unstable(issue = "none", feature = "inplace_iteration")] unsafe impl<I, F> SourceIter for FilterMap<I, F> where @@ -205,7 +209,7 @@ where } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<B, I: InPlaceIterable, F> InPlaceIterable for FilterMap<I, F> where - F: FnMut(I::Item) -> Option<B> -{ +unsafe impl<I: InPlaceIterable, F> InPlaceIterable for FilterMap<I, F> { + const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY; + const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY; } diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index eee6e5bccec..09428350fd9 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -1,7 +1,13 @@ -use crate::fmt; -use crate::iter::{DoubleEndedIterator, Fuse, FusedIterator, Iterator, Map, TrustedLen}; +use crate::iter::adapters::SourceIter; +use crate::iter::{ + Cloned, Copied, DoubleEndedIterator, Filter, FilterMap, Fuse, FusedIterator, InPlaceIterable, + Iterator, Map, TrustedFused, TrustedLen, +}; +use crate::iter::{Once, OnceWith}; use crate::num::NonZeroUsize; use crate::ops::{ControlFlow, Try}; +use crate::result; +use crate::{array, fmt, option}; /// An iterator that maps each element to an iterator, and yields the elements /// of the produced iterators. @@ -145,6 +151,91 @@ where { } +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<I, U, F> InPlaceIterable for FlatMap<I, U, F> +where + I: InPlaceIterable, + U: BoundedSize + IntoIterator, +{ + const EXPAND_BY: Option<NonZeroUsize> = const { + match (I::EXPAND_BY, U::UPPER_BOUND) { + (Some(m), Some(n)) => m.checked_mul(n), + _ => None, + } + }; + const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY; +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<I, U, F> SourceIter for FlatMap<I, U, F> +where + I: SourceIter + TrustedFused, + U: IntoIterator, +{ + type Source = I::Source; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut I::Source { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.inner.iter) } + } +} + +/// Marker trait for iterators/iterables which have a statically known upper +/// bound of the number of items they can produce. +/// +/// # Safety +/// +/// Implementations must not yield more elements than indicated by UPPER_BOUND if it is `Some`. +/// Used in specializations. Implementations must not be conditional on lifetimes or +/// user-implementable traits. +#[rustc_specialization_trait] +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe trait BoundedSize { + const UPPER_BOUND: Option<NonZeroUsize> = NonZeroUsize::new(1); +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<T> BoundedSize for Option<T> {} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<T> BoundedSize for option::IntoIter<T> {} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<T, U> BoundedSize for Result<T, U> {} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<T> BoundedSize for result::IntoIter<T> {} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<T> BoundedSize for Once<T> {} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<T> BoundedSize for OnceWith<T> {} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<T, const N: usize> BoundedSize for [T; N] { + const UPPER_BOUND: Option<NonZeroUsize> = NonZeroUsize::new(N); +} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<T, const N: usize> BoundedSize for array::IntoIter<T, N> { + const UPPER_BOUND: Option<NonZeroUsize> = NonZeroUsize::new(N); +} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<I: BoundedSize, P> BoundedSize for Filter<I, P> { + const UPPER_BOUND: Option<NonZeroUsize> = I::UPPER_BOUND; +} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<I: BoundedSize, P> BoundedSize for FilterMap<I, P> { + const UPPER_BOUND: Option<NonZeroUsize> = I::UPPER_BOUND; +} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<I: BoundedSize, F> BoundedSize for Map<I, F> { + const UPPER_BOUND: Option<NonZeroUsize> = I::UPPER_BOUND; +} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<I: BoundedSize> BoundedSize for Copied<I> { + const UPPER_BOUND: Option<NonZeroUsize> = I::UPPER_BOUND; +} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<I: BoundedSize> BoundedSize for Cloned<I> { + const UPPER_BOUND: Option<NonZeroUsize> = I::UPPER_BOUND; +} + /// An iterator that flattens one level of nesting in an iterator of things /// that can be turned into iterators. /// @@ -289,6 +380,36 @@ where { } +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<I> InPlaceIterable for Flatten<I> +where + I: InPlaceIterable + Iterator, + <I as Iterator>::Item: IntoIterator + BoundedSize, +{ + const EXPAND_BY: Option<NonZeroUsize> = const { + match (I::EXPAND_BY, I::Item::UPPER_BOUND) { + (Some(m), Some(n)) => m.checked_mul(n), + _ => None, + } + }; + const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY; +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<I> SourceIter for Flatten<I> +where + I: SourceIter + TrustedFused + Iterator, + <I as Iterator>::Item: IntoIterator, +{ + type Source = I::Source; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut I::Source { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.inner.iter) } + } +} + #[stable(feature = "default_iters", since = "1.70.0")] impl<I> Default for Flatten<I> where diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index b1fa4f92117..3234cade50d 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -1,8 +1,9 @@ use crate::intrinsics; use crate::iter::adapters::zip::try_get_unchecked; +use crate::iter::adapters::SourceIter; use crate::iter::{ - DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen, TrustedRandomAccess, - TrustedRandomAccessNoCoerce, + DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedFused, TrustedLen, + TrustedRandomAccess, TrustedRandomAccessNoCoerce, }; use crate::ops::Try; @@ -29,6 +30,9 @@ impl<I> Fuse<I> { #[stable(feature = "fused", since = "1.26.0")] impl<I> FusedIterator for Fuse<I> where I: Iterator {} +#[unstable(issue = "none", feature = "trusted_fused")] +unsafe impl<I> TrustedFused for Fuse<I> where I: TrustedFused {} + // Any specialized implementation here is made internal // to avoid exposing default fns outside this trait. #[stable(feature = "rust1", since = "1.0.0")] @@ -418,6 +422,23 @@ where } } +// This is used by Flatten's SourceIter impl +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl<I> SourceIter for Fuse<I> +where + I: SourceIter + TrustedFused, +{ + type Source = I::Source; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut I::Source { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements. + // TrustedFused guarantees that we'll never encounter a case where `self.iter` would + // be set to None. + unsafe { SourceIter::as_inner(self.iter.as_mut().unwrap_unchecked()) } + } +} + #[inline] fn and_then_or_clear<T, U>(opt: &mut Option<T>, f: impl FnOnce(&mut T) -> Option<U>) -> Option<U> { let x = f(opt.as_mut()?); diff --git a/library/core/src/iter/adapters/inspect.rs b/library/core/src/iter/adapters/inspect.rs index 19839fdfe5b..fd2d830b693 100644 --- a/library/core/src/iter/adapters/inspect.rs +++ b/library/core/src/iter/adapters/inspect.rs @@ -1,5 +1,6 @@ use crate::fmt; -use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedFused}; +use crate::num::NonZeroUsize; use crate::ops::Try; /// An iterator that calls a function with a reference to each element before @@ -148,6 +149,9 @@ where #[stable(feature = "fused", since = "1.26.0")] impl<I: FusedIterator, F> FusedIterator for Inspect<I, F> where F: FnMut(&I::Item) {} +#[unstable(issue = "none", feature = "trusted_fused")] +unsafe impl<I: TrustedFused, F> TrustedFused for Inspect<I, F> {} + #[unstable(issue = "none", feature = "inplace_iteration")] unsafe impl<I, F> SourceIter for Inspect<I, F> where @@ -163,4 +167,7 @@ where } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<I: InPlaceIterable, F> InPlaceIterable for Inspect<I, F> where F: FnMut(&I::Item) {} +unsafe impl<I: InPlaceIterable, F> InPlaceIterable for Inspect<I, F> { + const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY; + const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY; +} diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index 31d02a4da6e..e27fc7257f6 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -2,7 +2,8 @@ use crate::fmt; use crate::iter::adapters::{ zip::try_get_unchecked, SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce, }; -use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen, UncheckedIterator}; +use crate::iter::{FusedIterator, InPlaceIterable, TrustedFused, TrustedLen, UncheckedIterator}; +use crate::num::NonZeroUsize; use crate::ops::Try; /// An iterator that maps the values of `iter` with `f`. @@ -179,6 +180,9 @@ where #[stable(feature = "fused", since = "1.26.0")] impl<B, I: FusedIterator, F> FusedIterator for Map<I, F> where F: FnMut(I::Item) -> B {} +#[unstable(issue = "none", feature = "trusted_fused")] +unsafe impl<I: TrustedFused, F> TrustedFused for Map<I, F> {} + #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<B, I, F> TrustedLen for Map<I, F> where @@ -228,4 +232,7 @@ where } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<B, I: InPlaceIterable, F> InPlaceIterable for Map<I, F> where F: FnMut(I::Item) -> B {} +unsafe impl<I: InPlaceIterable, F> InPlaceIterable for Map<I, F> { + const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY; + const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY; +} diff --git a/library/core/src/iter/adapters/map_while.rs b/library/core/src/iter/adapters/map_while.rs index fbdeca4d4ee..bcae73cbe09 100644 --- a/library/core/src/iter/adapters/map_while.rs +++ b/library/core/src/iter/adapters/map_while.rs @@ -1,5 +1,6 @@ use crate::fmt; use crate::iter::{adapters::SourceIter, InPlaceIterable}; +use crate::num::NonZeroUsize; use crate::ops::{ControlFlow, Try}; /// An iterator that only accepts elements while `predicate` returns `Some(_)`. @@ -82,7 +83,7 @@ where } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<B, I: InPlaceIterable, P> InPlaceIterable for MapWhile<I, P> where - P: FnMut(I::Item) -> Option<B> -{ +unsafe impl<I: InPlaceIterable, P> InPlaceIterable for MapWhile<I, P> { + const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY; + const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY; } diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 6f4fa7010f4..a691039c789 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -1,4 +1,5 @@ use crate::iter::{InPlaceIterable, Iterator}; +use crate::num::NonZeroUsize; use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; mod array_chunks; @@ -119,8 +120,9 @@ pub unsafe trait SourceIter { /// /// # Safety /// - /// Implementations of must return the same mutable reference for their lifetime, unless + /// Implementations must return the same mutable reference for their lifetime, unless /// replaced by a caller. + /// /// Callers may only replace the reference when they stopped iteration and drop the /// iterator pipeline after extracting the source. /// @@ -228,7 +230,10 @@ where // in order to return `Some(_)`. Since `iter` has type `I: InPlaceIterable` it's // guaranteed that at least one item will be moved out from the underlying source. #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<I, T, R> InPlaceIterable for GenericShunt<'_, I, R> where - I: Iterator<Item: Try<Output = T, Residual = R>> + InPlaceIterable +unsafe impl<I, R> InPlaceIterable for GenericShunt<'_, I, R> +where + I: InPlaceIterable, { + const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY; + const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY; } diff --git a/library/core/src/iter/adapters/scan.rs b/library/core/src/iter/adapters/scan.rs index 62470512cc7..635bad199ff 100644 --- a/library/core/src/iter/adapters/scan.rs +++ b/library/core/src/iter/adapters/scan.rs @@ -1,5 +1,6 @@ use crate::fmt; use crate::iter::{adapters::SourceIter, InPlaceIterable}; +use crate::num::NonZeroUsize; use crate::ops::{ControlFlow, Try}; /// An iterator to maintain state while iterating another iterator. @@ -92,7 +93,7 @@ where } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<St, F, B, I: InPlaceIterable> InPlaceIterable for Scan<I, St, F> where - F: FnMut(&mut St, I::Item) -> Option<B> -{ +unsafe impl<St, F, I: InPlaceIterable> InPlaceIterable for Scan<I, St, F> { + const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY; + const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY; } diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs index 306338bc7cc..e6c946e7f88 100644 --- a/library/core/src/iter/adapters/skip.rs +++ b/library/core/src/iter/adapters/skip.rs @@ -1,4 +1,5 @@ use crate::intrinsics::unlikely; +use crate::iter::TrustedFused; use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; use crate::num::NonZeroUsize; use crate::ops::{ControlFlow, Try}; @@ -214,6 +215,9 @@ where #[stable(feature = "fused", since = "1.26.0")] impl<I> FusedIterator for Skip<I> where I: FusedIterator {} +#[unstable(issue = "none", feature = "trusted_fused")] +unsafe impl<I: TrustedFused> TrustedFused for Skip<I> {} + #[unstable(issue = "none", feature = "inplace_iteration")] unsafe impl<I> SourceIter for Skip<I> where @@ -229,4 +233,7 @@ where } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<I: InPlaceIterable> InPlaceIterable for Skip<I> {} +unsafe impl<I: InPlaceIterable> InPlaceIterable for Skip<I> { + const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY; + const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY; +} diff --git a/library/core/src/iter/adapters/skip_while.rs b/library/core/src/iter/adapters/skip_while.rs index f29661779c0..3a661973e5f 100644 --- a/library/core/src/iter/adapters/skip_while.rs +++ b/library/core/src/iter/adapters/skip_while.rs @@ -1,5 +1,6 @@ use crate::fmt; -use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedFused}; +use crate::num::NonZeroUsize; use crate::ops::Try; /// An iterator that rejects elements while `predicate` returns `true`. @@ -104,6 +105,9 @@ where { } +#[unstable(issue = "none", feature = "trusted_fused")] +unsafe impl<I: TrustedFused, P> TrustedFused for SkipWhile<I, P> {} + #[unstable(issue = "none", feature = "inplace_iteration")] unsafe impl<P, I> SourceIter for SkipWhile<I, P> where @@ -119,7 +123,7 @@ where } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<I: InPlaceIterable, F> InPlaceIterable for SkipWhile<I, F> where - F: FnMut(&I::Item) -> bool -{ +unsafe impl<I: InPlaceIterable, F> InPlaceIterable for SkipWhile<I, F> { + const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY; + const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY; } diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs index c1d8cc4ff57..80e06066d28 100644 --- a/library/core/src/iter/adapters/take.rs +++ b/library/core/src/iter/adapters/take.rs @@ -1,6 +1,7 @@ use crate::cmp; use crate::iter::{ - adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen, TrustedRandomAccess, + adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedFused, TrustedLen, + TrustedRandomAccess, }; use crate::num::NonZeroUsize; use crate::ops::{ControlFlow, Try}; @@ -143,7 +144,10 @@ where } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<I: InPlaceIterable> InPlaceIterable for Take<I> {} +unsafe impl<I: InPlaceIterable> InPlaceIterable for Take<I> { + const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY; + const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY; +} #[stable(feature = "double_ended_take_iterator", since = "1.38.0")] impl<I> DoubleEndedIterator for Take<I> @@ -241,6 +245,9 @@ impl<I> ExactSizeIterator for Take<I> where I: ExactSizeIterator {} #[stable(feature = "fused", since = "1.26.0")] impl<I> FusedIterator for Take<I> where I: FusedIterator {} +#[unstable(issue = "none", feature = "trusted_fused")] +unsafe impl<I: TrustedFused> TrustedFused for Take<I> {} + #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<I: TrustedLen> TrustedLen for Take<I> {} diff --git a/library/core/src/iter/adapters/take_while.rs b/library/core/src/iter/adapters/take_while.rs index ec66dc3aec3..e55d55a6d23 100644 --- a/library/core/src/iter/adapters/take_while.rs +++ b/library/core/src/iter/adapters/take_while.rs @@ -1,5 +1,6 @@ use crate::fmt; -use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedFused}; +use crate::num::NonZeroUsize; use crate::ops::{ControlFlow, Try}; /// An iterator that only accepts elements while `predicate` returns `true`. @@ -105,6 +106,9 @@ where { } +#[unstable(issue = "none", feature = "trusted_fused")] +unsafe impl<I: TrustedFused, P> TrustedFused for TakeWhile<I, P> {} + #[unstable(issue = "none", feature = "inplace_iteration")] unsafe impl<P, I> SourceIter for TakeWhile<I, P> where @@ -120,7 +124,7 @@ where } #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<I: InPlaceIterable, F> InPlaceIterable for TakeWhile<I, F> where - F: FnMut(&I::Item) -> bool -{ +unsafe impl<I: InPlaceIterable, F> InPlaceIterable for TakeWhile<I, F> { + const EXPAND_BY: Option<NonZeroUsize> = I::EXPAND_BY; + const MERGE_BY: Option<NonZeroUsize> = I::MERGE_BY; } diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 77ccf508502..e3041519be7 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -1,7 +1,8 @@ use crate::cmp; use crate::fmt::{self, Debug}; -use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator}; +use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator, TrustedFused}; use crate::iter::{InPlaceIterable, SourceIter, TrustedLen, UncheckedIterator}; +use crate::num::NonZeroUsize; /// An iterator that iterates two other iterators simultaneously. /// @@ -446,6 +447,14 @@ where { } +#[unstable(issue = "none", feature = "trusted_fused")] +unsafe impl<A, B> TrustedFused for Zip<A, B> +where + A: TrustedFused, + B: TrustedFused, +{ +} + #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<A, B> TrustedLen for Zip<A, B> where @@ -479,7 +488,10 @@ where // Since SourceIter forwards the left hand side we do the same here #[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<A: InPlaceIterable, B: Iterator> InPlaceIterable for Zip<A, B> {} +unsafe impl<A: InPlaceIterable, B> InPlaceIterable for Zip<A, B> { + const EXPAND_BY: Option<NonZeroUsize> = A::EXPAND_BY; + const MERGE_BY: Option<NonZeroUsize> = A::MERGE_BY; +} #[stable(feature = "rust1", since = "1.0.0")] impl<A: Debug, B: Debug> Debug for Zip<A, B> { diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 937a149acaa..44fef3e145b 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -417,6 +417,8 @@ pub use self::sources::{successors, Successors}; pub use self::traits::FusedIterator; #[unstable(issue = "none", feature = "inplace_iteration")] pub use self::traits::InPlaceIterable; +#[unstable(issue = "none", feature = "trusted_fused")] +pub use self::traits::TrustedFused; #[unstable(feature = "trusted_len", issue = "37572")] pub use self::traits::TrustedLen; #[unstable(feature = "trusted_step", issue = "85731")] diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs index c21a2aac1c9..e7c1f195aac 100644 --- a/library/core/src/iter/traits/marker.rs +++ b/library/core/src/iter/traits/marker.rs @@ -1,4 +1,16 @@ use crate::iter::Step; +use crate::num::NonZeroUsize; + +/// Same as FusedIterator +/// +/// # Safety +/// +/// This is used for specialization. Therefore implementations must not +/// be lifetime-dependent. +#[unstable(issue = "none", feature = "trusted_fused")] +#[doc(hidden)] +#[rustc_specialization_trait] +pub unsafe trait TrustedFused {} /// An iterator that always continues to yield `None` when exhausted. /// @@ -14,6 +26,8 @@ use crate::iter::Step; /// [`Fuse`]: crate::iter::Fuse #[stable(feature = "fused", since = "1.26.0")] #[rustc_unsafe_specialization_marker] +// FIXME: this should be a #[marker] and have another blanket impl for T: TrustedFused +// but that ICEs iter::Fuse specializations. pub trait FusedIterator: Iterator {} #[stable(feature = "fused", since = "1.26.0")] @@ -71,7 +85,19 @@ unsafe impl<I: TrustedLen + ?Sized> TrustedLen for &mut I {} /// [`try_fold()`]: Iterator::try_fold #[unstable(issue = "none", feature = "inplace_iteration")] #[doc(hidden)] -pub unsafe trait InPlaceIterable: Iterator {} +#[rustc_specialization_trait] +pub unsafe trait InPlaceIterable { + /// The product of one-to-many item expansions that happen throughout the iterator pipeline. + /// E.g. [[u8; 4]; 4].iter().flatten().flatten() would have a `EXPAND_BY` of 16. + /// This is an upper bound, i.e. the transformations will produce at most this many items per + /// input. It's meant for layout calculations. + const EXPAND_BY: Option<NonZeroUsize>; + /// The product of many-to-one item reductions that happen throughout the iterator pipeline. + /// E.g. [u8].iter().array_chunks::<4>().array_chunks::<4>() would have a `MERGE_BY` of 16. + /// This is a lower bound, i.e. the transformations will consume at least this many items per + /// output. + const MERGE_BY: Option<NonZeroUsize>; +} /// A type that upholds all invariants of [`Step`]. /// diff --git a/library/core/src/iter/traits/mod.rs b/library/core/src/iter/traits/mod.rs index 41ea29e6a84..d4c9cc4b160 100644 --- a/library/core/src/iter/traits/mod.rs +++ b/library/core/src/iter/traits/mod.rs @@ -18,6 +18,8 @@ pub use self::{ #[unstable(issue = "none", feature = "inplace_iteration")] pub use self::marker::InPlaceIterable; +#[unstable(issue = "none", feature = "trusted_fused")] +pub use self::marker::TrustedFused; #[unstable(feature = "trusted_step", issue = "85731")] pub use self::marker::TrustedStep; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 86f5fc56361..dec9a6d991d 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -24,9 +24,8 @@ //! which are generated by Rust codegen backends. Additionally, this library can make explicit //! calls to `strlen`. Their signatures are the same as found in C, but there are extra //! assumptions about their semantics: For `memcpy`, `memmove`, `memset`, `memcmp`, and `bcmp`, if -//! the `n` parameter is 0, the function is assumed to not be UB. Furthermore, for `memcpy`, if -//! source and target pointer are equal, the function is assumed to not be UB. -//! (Note that these are standard assumptions among compilers: +//! the `n` parameter is 0, the function is assumed to not be UB, even if the pointers are NULL or +//! dangling. (Note that making extra assumptions about these functions is common among compilers: //! [clang](https://reviews.llvm.org/D86993) and [GCC](https://gcc.gnu.org/onlinedocs/gcc/Standards.html#C-Language) do the same.) //! These functions are often provided by the system libc, but can also be provided by the //! [compiler-builtins crate](https://crates.io/crates/compiler_builtins). diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 2a0b31404f0..695e87aaabf 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -474,7 +474,7 @@ impl isize { } } -/// If 6th bit is set ascii is lower case. +/// If the 6th bit is set ascii is lower case. const ASCII_CASE_MASK: u8 = 0b0010_0000; impl u8 { @@ -549,7 +549,7 @@ impl u8 { #[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.52.0")] #[inline] pub const fn to_ascii_uppercase(&self) -> u8 { - // Toggle the fifth bit if this is a lowercase letter + // Toggle the 6th bit if this is a lowercase letter *self ^ ((self.is_ascii_lowercase() as u8) * ASCII_CASE_MASK) } @@ -574,7 +574,7 @@ impl u8 { #[rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.52.0")] #[inline] pub const fn to_ascii_lowercase(&self) -> u8 { - // Set the fifth bit if this is an uppercase letter + // Set the 6th bit if this is an uppercase letter *self | (self.is_ascii_uppercase() as u8 * ASCII_CASE_MASK) } diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index cc94ee280c6..f5ecf501ce9 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -353,8 +353,13 @@ macro_rules! nonzero_unsigned_operations { #[inline] pub const fn checked_add(self, other: $Int) -> Option<$Ty> { if let Some(result) = self.get().checked_add(other) { - // SAFETY: $Int::checked_add returns None on overflow - // so the result cannot be zero. + // SAFETY: + // - `checked_add` returns `None` on overflow + // - `self` is non-zero + // - the only way to get zero from an addition without overflow is for both + // sides to be zero + // + // So the result cannot be zero. Some(unsafe { $Ty::new_unchecked(result) }) } else { None @@ -386,8 +391,13 @@ macro_rules! nonzero_unsigned_operations { without modifying the original"] #[inline] pub const fn saturating_add(self, other: $Int) -> $Ty { - // SAFETY: $Int::saturating_add returns $Int::MAX on overflow - // so the result cannot be zero. + // SAFETY: + // - `saturating_add` returns `u*::MAX` on overflow, which is non-zero + // - `self` is non-zero + // - the only way to get zero from an addition without overflow is for both + // sides to be zero + // + // So the result cannot be zero. unsafe { $Ty::new_unchecked(self.get().saturating_add(other)) } } @@ -1000,9 +1010,13 @@ macro_rules! nonzero_unsigned_signed_operations { #[inline] pub const fn checked_mul(self, other: $Ty) -> Option<$Ty> { if let Some(result) = self.get().checked_mul(other.get()) { - // SAFETY: checked_mul returns None on overflow - // and `other` is also non-null - // so the result cannot be zero. + // SAFETY: + // - `checked_mul` returns `None` on overflow + // - `self` and `other` are non-zero + // - the only way to get zero from a multiplication without overflow is for one + // of the sides to be zero + // + // So the result cannot be zero. Some(unsafe { $Ty::new_unchecked(result) }) } else { None @@ -1034,9 +1048,14 @@ macro_rules! nonzero_unsigned_signed_operations { without modifying the original"] #[inline] pub const fn saturating_mul(self, other: $Ty) -> $Ty { - // SAFETY: saturating_mul returns u*::MAX on overflow - // and `other` is also non-null - // so the result cannot be zero. + // SAFETY: + // - `saturating_mul` returns `u*::MAX`/`i*::MAX`/`i*::MIN` on overflow/underflow, + // all of which are non-zero + // - `self` and `other` are non-zero + // - the only way to get zero from a multiplication without overflow is for one + // of the sides to be zero + // + // So the result cannot be zero. unsafe { $Ty::new_unchecked(self.get().saturating_mul(other.get())) } } @@ -1107,8 +1126,13 @@ macro_rules! nonzero_unsigned_signed_operations { #[inline] pub const fn checked_pow(self, other: u32) -> Option<$Ty> { if let Some(result) = self.get().checked_pow(other) { - // SAFETY: checked_pow returns None on overflow - // so the result cannot be zero. + // SAFETY: + // - `checked_pow` returns `None` on overflow/underflow + // - `self` is non-zero + // - the only way to get zero from an exponentiation without overflow is + // for base to be zero + // + // So the result cannot be zero. Some(unsafe { $Ty::new_unchecked(result) }) } else { None @@ -1149,8 +1173,14 @@ macro_rules! nonzero_unsigned_signed_operations { without modifying the original"] #[inline] pub const fn saturating_pow(self, other: u32) -> $Ty { - // SAFETY: saturating_pow returns u*::MAX on overflow - // so the result cannot be zero. + // SAFETY: + // - `saturating_pow` returns `u*::MAX`/`i*::MAX`/`i*::MIN` on overflow/underflow, + // all of which are non-zero + // - `self` is non-zero + // - the only way to get zero from an exponentiation without overflow is + // for base to be zero + // + // So the result cannot be zero. unsafe { $Ty::new_unchecked(self.get().saturating_pow(other)) } } } diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index 840c8cd2fe8..1773fdbf37c 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -98,6 +98,7 @@ macro_rules! add_impl { type Output = $t; #[inline] + #[track_caller] #[rustc_inherit_overflow_checks] fn add(self, other: $t) -> $t { self + other } } @@ -206,6 +207,7 @@ macro_rules! sub_impl { type Output = $t; #[inline] + #[track_caller] #[rustc_inherit_overflow_checks] fn sub(self, other: $t) -> $t { self - other } } @@ -335,6 +337,7 @@ macro_rules! mul_impl { type Output = $t; #[inline] + #[track_caller] #[rustc_inherit_overflow_checks] fn mul(self, other: $t) -> $t { self * other } } @@ -474,6 +477,7 @@ macro_rules! div_impl_integer { type Output = $t; #[inline] + #[track_caller] fn div(self, other: $t) -> $t { self / other } } @@ -575,6 +579,7 @@ macro_rules! rem_impl_integer { type Output = $t; #[inline] + #[track_caller] fn rem(self, other: $t) -> $t { self % other } } @@ -749,6 +754,7 @@ macro_rules! add_assign_impl { #[stable(feature = "op_assign_traits", since = "1.8.0")] impl AddAssign for $t { #[inline] + #[track_caller] #[rustc_inherit_overflow_checks] fn add_assign(&mut self, other: $t) { *self += other } } @@ -815,6 +821,7 @@ macro_rules! sub_assign_impl { #[stable(feature = "op_assign_traits", since = "1.8.0")] impl SubAssign for $t { #[inline] + #[track_caller] #[rustc_inherit_overflow_checks] fn sub_assign(&mut self, other: $t) { *self -= other } } @@ -872,6 +879,7 @@ macro_rules! mul_assign_impl { #[stable(feature = "op_assign_traits", since = "1.8.0")] impl MulAssign for $t { #[inline] + #[track_caller] #[rustc_inherit_overflow_checks] fn mul_assign(&mut self, other: $t) { *self *= other } } @@ -929,6 +937,7 @@ macro_rules! div_assign_impl { #[stable(feature = "op_assign_traits", since = "1.8.0")] impl DivAssign for $t { #[inline] + #[track_caller] fn div_assign(&mut self, other: $t) { *self /= other } } @@ -989,6 +998,7 @@ macro_rules! rem_assign_impl { #[stable(feature = "op_assign_traits", since = "1.8.0")] impl RemAssign for $t { #[inline] + #[track_caller] fn rem_assign(&mut self, other: $t) { *self %= other } } diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index a7e20407cec..e5d7e964381 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1629,7 +1629,7 @@ mod prim_ref {} /// /// ### Trait implementations /// -/// In this documentation the shorthand `fn (T₁, T₂, …, Tₙ)` is used to represent non-variadic +/// In this documentation the shorthand `fn(T₁, T₂, …, Tₙ)` is used to represent non-variadic /// function pointers of varying length. Note that this is a convenience notation to avoid /// repetitive documentation, not valid Rust syntax. /// diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 36685f756d0..c8a0eb4ffc2 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1644,6 +1644,24 @@ impl<T> *const [T] { metadata(self) } + /// Returns `true` if the raw slice has a length of 0. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_ptr_len)] + /// use std::ptr; + /// + /// let slice: *const [i8] = ptr::slice_from_raw_parts(ptr::null(), 3); + /// assert!(!slice.is_empty()); + /// ``` + #[inline(always)] + #[unstable(feature = "slice_ptr_len", issue = "71146")] + #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")] + pub const fn is_empty(self) -> bool { + self.len() == 0 + } + /// Returns a raw pointer to the slice's buffer. /// /// This is equivalent to casting `self` to `*const T`, but more type-safe. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index bc362fb627f..ce0e6d6f297 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1920,10 +1920,10 @@ impl<T> *mut [T] { /// /// ``` /// #![feature(slice_ptr_len)] + /// use std::ptr; /// - /// let mut a = [1, 2, 3]; - /// let ptr = &mut a as *mut [_]; - /// assert!(!ptr.is_empty()); + /// let slice: *mut [i8] = ptr::slice_from_raw_parts_mut(ptr::null_mut(), 3); + /// assert!(!slice.is_empty()); /// ``` #[inline(always)] #[unstable(feature = "slice_ptr_len", issue = "71146")] diff --git a/library/core/src/slice/memchr.rs b/library/core/src/slice/memchr.rs index 3a8b59d727b..da7ceb2dd0a 100644 --- a/library/core/src/slice/memchr.rs +++ b/library/core/src/slice/memchr.rs @@ -20,20 +20,6 @@ const fn contains_zero_byte(x: usize) -> bool { x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0 } -#[inline] -#[cfg(target_pointer_width = "16")] -#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")] -const fn repeat_byte(b: u8) -> usize { - (b as usize) << 8 | b as usize -} - -#[inline] -#[cfg(not(target_pointer_width = "16"))] -#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")] -const fn repeat_byte(b: u8) -> usize { - (b as usize) * (usize::MAX / 255) -} - /// Returns the first index matching the byte `x` in `text`. #[inline] #[must_use] @@ -93,7 +79,7 @@ const fn memchr_aligned(x: u8, text: &[u8]) -> Option<usize> { } // search the body of the text - let repeated_x = repeat_byte(x); + let repeated_x = usize::repeat_u8(x); while offset <= len - 2 * USIZE_BYTES { // SAFETY: the while's predicate guarantees a distance of at least 2 * usize_bytes // between the offset and the end of the slice. @@ -149,7 +135,7 @@ pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> { // Search the body of the text, make sure we don't cross min_aligned_offset. // offset is always aligned, so just testing `>` is sufficient and avoids possible // overflow. - let repeated_x = repeat_byte(x); + let repeated_x = usize::repeat_u8(x); let chunk_bytes = mem::size_of::<Chunk>(); while offset > min_aligned_offset { diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index c30f01b3c06..dd2efb00516 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -8,6 +8,7 @@ use crate::iter::{TrustedRandomAccess, TrustedRandomAccessNoCoerce}; use crate::ops::Try; use crate::option; use crate::slice::{self, Split as SliceSplit}; +use core::num::NonZeroUsize; use super::from_utf8_unchecked; use super::pattern::Pattern; @@ -50,6 +51,55 @@ impl<'a> Iterator for Chars<'a> { } #[inline] + fn advance_by(&mut self, mut remainder: usize) -> Result<(), NonZeroUsize> { + const CHUNK_SIZE: usize = 32; + + if remainder >= CHUNK_SIZE { + let mut chunks = self.iter.as_slice().array_chunks::<CHUNK_SIZE>(); + let mut bytes_skipped: usize = 0; + + while remainder > CHUNK_SIZE + && let Some(chunk) = chunks.next() + { + bytes_skipped += CHUNK_SIZE; + + let mut start_bytes = [false; CHUNK_SIZE]; + + for i in 0..CHUNK_SIZE { + start_bytes[i] = !super::validations::utf8_is_cont_byte(chunk[i]); + } + + remainder -= start_bytes.into_iter().map(|i| i as u8).sum::<u8>() as usize; + } + + // SAFETY: The amount of bytes exists since we just iterated over them, + // so advance_by will succeed. + unsafe { self.iter.advance_by(bytes_skipped).unwrap_unchecked() }; + + // skip trailing continuation bytes + while self.iter.len() > 0 { + let b = self.iter.as_slice()[0]; + if !super::validations::utf8_is_cont_byte(b) { + break; + } + // SAFETY: We just peeked at the byte, therefore it exists + unsafe { self.iter.advance_by(1).unwrap_unchecked() }; + } + } + + while (remainder > 0) && (self.iter.len() > 0) { + remainder -= 1; + let b = self.iter.as_slice()[0]; + let slurp = super::validations::utf8_char_width(b); + // SAFETY: utf8 validity requires that the string must contain + // the continuation bytes (if any) + unsafe { self.iter.advance_by(slurp).unwrap_unchecked() }; + } + + NonZeroUsize::new(remainder).map_or(Ok(()), Err) + } + + #[inline] fn size_hint(&self) -> (usize, Option<usize>) { let len = self.iter.len(); // `(len + 3)` can't overflow, because we know that the `slice::Iter` diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs index 4d51a719f6c..d49866345cb 100644 --- a/library/std/src/io/copy.rs +++ b/library/std/src/io/copy.rs @@ -1,7 +1,6 @@ use super::{BorrowedBuf, BufReader, BufWriter, Read, Result, Write, DEFAULT_BUF_SIZE}; use crate::alloc::Allocator; use crate::cmp; -use crate::cmp::min; use crate::collections::VecDeque; use crate::io::IoSlice; use crate::mem::MaybeUninit; @@ -256,79 +255,17 @@ impl<I: Write + ?Sized> BufferedWriterSpec for BufWriter<I> { } } -impl<A: Allocator> BufferedWriterSpec for Vec<u8, A> { +impl BufferedWriterSpec for Vec<u8> { fn buffer_size(&self) -> usize { cmp::max(DEFAULT_BUF_SIZE, self.capacity() - self.len()) } fn copy_from<R: Read + ?Sized>(&mut self, reader: &mut R) -> Result<u64> { - let mut bytes = 0; - - // avoid inflating empty/small vecs before we have determined that there's anything to read - if self.capacity() < DEFAULT_BUF_SIZE { - let stack_read_limit = DEFAULT_BUF_SIZE as u64; - bytes = stack_buffer_copy(&mut reader.take(stack_read_limit), self)?; - // fewer bytes than requested -> EOF reached - if bytes < stack_read_limit { - return Ok(bytes); - } - } - - // don't immediately offer the vec's whole spare capacity, otherwise - // we might have to fully initialize it if the reader doesn't have a custom read_buf() impl - let mut max_read_size = DEFAULT_BUF_SIZE; - - loop { - self.reserve(DEFAULT_BUF_SIZE); - let mut initialized_spare_capacity = 0; - - loop { - let buf = self.spare_capacity_mut(); - let read_size = min(max_read_size, buf.len()); - let mut buf = BorrowedBuf::from(&mut buf[..read_size]); - // SAFETY: init is either 0 or the init_len from the previous iteration. - unsafe { - buf.set_init(initialized_spare_capacity); - } - match reader.read_buf(buf.unfilled()) { - Ok(()) => { - let bytes_read = buf.len(); - - // EOF - if bytes_read == 0 { - return Ok(bytes); - } - - // the reader is returning short reads but it doesn't call ensure_init() - if buf.init_len() < buf.capacity() { - max_read_size = usize::MAX; - } - // the reader hasn't returned short reads so far - if bytes_read == buf.capacity() { - max_read_size *= 2; - } - - initialized_spare_capacity = buf.init_len() - bytes_read; - bytes += bytes_read as u64; - // SAFETY: BorrowedBuf guarantees all of its filled bytes are init - // and the number of read bytes can't exceed the spare capacity since - // that's what the buffer is borrowing from. - unsafe { self.set_len(self.len() + bytes_read) }; - - // spare capacity full, reserve more - if self.len() == self.capacity() { - break; - } - } - Err(e) if e.is_interrupted() => continue, - Err(e) => return Err(e), - } - } - } + reader.read_to_end(self).map(|bytes| u64::try_from(bytes).expect("usize overflowed u64")) } } -fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>( +pub fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>( reader: &mut R, writer: &mut W, ) -> Result<u64> { diff --git a/library/std/src/io/copy/tests.rs b/library/std/src/io/copy/tests.rs index af137eaf856..a1f909a3c53 100644 --- a/library/std/src/io/copy/tests.rs +++ b/library/std/src/io/copy/tests.rs @@ -82,13 +82,16 @@ fn copy_specializes_bufreader() { #[test] fn copy_specializes_to_vec() { - let cap = 123456; - let mut source = ShortReader { cap, observed_buffer: 0, read_size: 1337 }; + let cap = DEFAULT_BUF_SIZE * 10; + let mut source = ShortReader { cap, observed_buffer: 0, read_size: DEFAULT_BUF_SIZE }; let mut sink = Vec::new(); - assert_eq!(cap as u64, io::copy(&mut source, &mut sink).unwrap()); + let copied = io::copy(&mut source, &mut sink).unwrap(); + assert_eq!(cap as u64, copied); + assert_eq!(sink.len() as u64, copied); assert!( source.observed_buffer > DEFAULT_BUF_SIZE, - "expected a large buffer to be provided to the reader" + "expected a large buffer to be provided to the reader, got {}", + source.observed_buffer ); } diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index c8507a956ff..e3aa973741f 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -397,12 +397,16 @@ where } } -// This uses an adaptive system to extend the vector when it fills. We want to -// avoid paying to allocate and zero a huge chunk of memory if the reader only -// has 4 bytes while still making large reads if the reader does have a ton -// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every -// time is 4,500 times (!) slower than a default reservation size of 32 if the -// reader has a very small amount of data to return. +// Here we must serve many masters with conflicting goals: +// +// - avoid allocating unless necessary +// - avoid overallocating if we know the exact size (#89165) +// - avoid passing large buffers to readers that always initialize the free capacity if they perform short reads (#23815, #23820) +// - pass large buffers to readers that do not initialize the spare capacity. this can amortize per-call overheads +// - and finally pass not-too-small and not-too-large buffers to Windows read APIs because they manage to suffer from both problems +// at the same time, i.e. small reads suffer from syscall overhead, all reads incur initialization cost +// proportional to buffer size (#110650) +// pub(crate) fn default_read_to_end<R: Read + ?Sized>( r: &mut R, buf: &mut Vec<u8>, @@ -412,20 +416,58 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>( let start_cap = buf.capacity(); // Optionally limit the maximum bytes read on each iteration. // This adds an arbitrary fiddle factor to allow for more data than we expect. - let max_read_size = - size_hint.and_then(|s| s.checked_add(1024)?.checked_next_multiple_of(DEFAULT_BUF_SIZE)); + let mut max_read_size = size_hint + .and_then(|s| s.checked_add(1024)?.checked_next_multiple_of(DEFAULT_BUF_SIZE)) + .unwrap_or(DEFAULT_BUF_SIZE); let mut initialized = 0; // Extra initialized bytes from previous loop iteration + + const PROBE_SIZE: usize = 32; + + fn small_probe_read<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> { + let mut probe = [0u8; PROBE_SIZE]; + + loop { + match r.read(&mut probe) { + Ok(n) => { + buf.extend_from_slice(&probe[..n]); + return Ok(n); + } + Err(ref e) if e.is_interrupted() => continue, + Err(e) => return Err(e), + } + } + } + + // avoid inflating empty/small vecs before we have determined that there's anything to read + if (size_hint.is_none() || size_hint == Some(0)) && buf.capacity() - buf.len() < PROBE_SIZE { + let read = small_probe_read(r, buf)?; + + if read == 0 { + return Ok(0); + } + } + loop { + if buf.len() == buf.capacity() && buf.capacity() == start_cap { + // The buffer might be an exact fit. Let's read into a probe buffer + // and see if it returns `Ok(0)`. If so, we've avoided an + // unnecessary doubling of the capacity. But if not, append the + // probe buffer to the primary buffer and let its capacity grow. + let read = small_probe_read(r, buf)?; + + if read == 0 { + return Ok(buf.len() - start_len); + } + } + if buf.len() == buf.capacity() { - buf.reserve(32); // buf is full, need more space + buf.reserve(PROBE_SIZE); // buf is full, need more space } let mut spare = buf.spare_capacity_mut(); - if let Some(size) = max_read_size { - let len = cmp::min(spare.len(), size); - spare = &mut spare[..len] - } + let buf_len = cmp::min(spare.len(), max_read_size); + spare = &mut spare[..buf_len]; let mut read_buf: BorrowedBuf<'_> = spare.into(); // SAFETY: These bytes were initialized but not filled in the previous loop @@ -434,42 +476,44 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>( } let mut cursor = read_buf.unfilled(); - match r.read_buf(cursor.reborrow()) { - Ok(()) => {} - Err(e) if e.is_interrupted() => continue, - Err(e) => return Err(e), + loop { + match r.read_buf(cursor.reborrow()) { + Ok(()) => break, + Err(e) if e.is_interrupted() => continue, + Err(e) => return Err(e), + } } - if cursor.written() == 0 { + let unfilled_but_initialized = cursor.init_ref().len(); + let bytes_read = cursor.written(); + let was_fully_initialized = read_buf.init_len() == buf_len; + + if bytes_read == 0 { return Ok(buf.len() - start_len); } // store how much was initialized but not filled - initialized = cursor.init_ref().len(); + initialized = unfilled_but_initialized; // SAFETY: BorrowedBuf's invariants mean this much memory is initialized. unsafe { - let new_len = read_buf.filled().len() + buf.len(); + let new_len = bytes_read + buf.len(); buf.set_len(new_len); } - if buf.len() == buf.capacity() && buf.capacity() == start_cap { - // The buffer might be an exact fit. Let's read into a probe buffer - // and see if it returns `Ok(0)`. If so, we've avoided an - // unnecessary doubling of the capacity. But if not, append the - // probe buffer to the primary buffer and let its capacity grow. - let mut probe = [0u8; 32]; - - loop { - match r.read(&mut probe) { - Ok(0) => return Ok(buf.len() - start_len), - Ok(n) => { - buf.extend_from_slice(&probe[..n]); - break; - } - Err(ref e) if e.is_interrupted() => continue, - Err(e) => return Err(e), - } + // Use heuristics to determine the max read size if no initial size hint was provided + if size_hint.is_none() { + // The reader is returning short reads but it doesn't call ensure_init(). + // In that case we no longer need to restrict read sizes to avoid + // initialization costs. + if !was_fully_initialized { + max_read_size = usize::MAX; + } + + // we have passed a larger buffer than previously and the + // reader still hasn't returned a short read + if buf_len >= max_read_size && bytes_read == buf_len { + max_read_size = max_read_size.saturating_mul(2); } } } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index d06012c14dc..8dc5b07ce10 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -336,6 +336,7 @@ #![feature(portable_simd)] #![feature(prelude_2024)] #![feature(ptr_as_uninit)] +#![feature(ptr_from_ref)] #![feature(raw_os_nonzero)] #![feature(round_ties_even)] #![feature(slice_internals)] diff --git a/library/std/src/process.rs b/library/std/src/process.rs index af6bef1a76e..6004ed51bd1 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1108,7 +1108,7 @@ impl fmt::Debug for Command { /// /// The default format approximates a shell invocation of the program along with its /// arguments. It does not include most of the other command properties. The output is not guaranteed to work - /// (e.g. due to lack of shell-escaping or differences in path resolution) + /// (e.g. due to lack of shell-escaping or differences in path resolution). /// On some platforms you can use [the alternate syntax] to show more fields. /// /// Note that the debug implementation is platform-specific. diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index f4963090795..52a43913243 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -13,22 +13,54 @@ use crate::sync::Once; /// /// # Examples /// +/// Using `OnceCell` to store a function’s previously computed value (a.k.a. +/// ‘lazy static’ or ‘memoizing’): +/// +/// ``` +/// use std::collections::HashMap; +/// use std::sync::OnceLock; +/// +/// fn hash_map() -> &'static HashMap<u32, char> { +/// static HASHMAP: OnceLock<HashMap<u32, char>> = OnceLock::new(); +/// HASHMAP.get_or_init(|| { +/// let mut m = HashMap::new(); +/// m.insert(0, 'a'); +/// m.insert(1, 'b'); +/// m.insert(2, 'c'); +/// m +/// }) +/// } +/// +/// // The `HashMap` is built, stored in the `OnceLock`, and returned. +/// let _ = hash_map(); +/// +/// // The `HashMap` is retrieved from the `OnceLock` and returned. +/// let _ = hash_map(); +/// ``` +/// +/// Writing to a `OnceLock` from a separate thread: +/// /// ``` /// use std::sync::OnceLock; /// -/// static CELL: OnceLock<String> = OnceLock::new(); +/// static CELL: OnceLock<usize> = OnceLock::new(); +/// +/// // `OnceLock` has not been written to yet. /// assert!(CELL.get().is_none()); /// +/// // Spawn a thread and write to `OnceLock`. /// std::thread::spawn(|| { -/// let value: &String = CELL.get_or_init(|| { -/// "Hello, World!".to_string() -/// }); -/// assert_eq!(value, "Hello, World!"); -/// }).join().unwrap(); +/// let value = CELL.get_or_init(|| 12345); +/// assert_eq!(value, &12345); +/// }) +/// .join() +/// .unwrap(); /// -/// let value: Option<&String> = CELL.get(); -/// assert!(value.is_some()); -/// assert_eq!(value.unwrap().as_str(), "Hello, World!"); +/// // `OnceLock` now contains the value. +/// assert_eq!( +/// CELL.get(), +/// Some(&12345), +/// ); /// ``` #[stable(feature = "once_cell", since = "1.70.0")] pub struct OnceLock<T> { diff --git a/library/std/src/sys/xous/mod.rs b/library/std/src/sys/xous/mod.rs index 6d5c218d195..c2550dcfd83 100644 --- a/library/std/src/sys/xous/mod.rs +++ b/library/std/src/sys/xous/mod.rs @@ -28,7 +28,6 @@ pub mod process; pub mod stdio; pub mod thread; pub mod thread_local_key; -#[path = "../unsupported/thread_parking.rs"] pub mod thread_parking; pub mod time; diff --git a/library/std/src/sys/xous/thread_parking.rs b/library/std/src/sys/xous/thread_parking.rs new file mode 100644 index 00000000000..aa39c6d2718 --- /dev/null +++ b/library/std/src/sys/xous/thread_parking.rs @@ -0,0 +1,94 @@ +use crate::os::xous::ffi::{blocking_scalar, scalar}; +use crate::os::xous::services::{ticktimer_server, TicktimerScalar}; +use crate::pin::Pin; +use crate::ptr; +use crate::sync::atomic::{ + AtomicI8, + Ordering::{Acquire, Release}, +}; +use crate::time::Duration; + +const NOTIFIED: i8 = 1; +const EMPTY: i8 = 0; +const PARKED: i8 = -1; + +pub struct Parker { + state: AtomicI8, +} + +impl Parker { + pub unsafe fn new_in_place(parker: *mut Parker) { + unsafe { parker.write(Parker { state: AtomicI8::new(EMPTY) }) } + } + + fn index(&self) -> usize { + ptr::from_ref(self).addr() + } + + pub unsafe fn park(self: Pin<&Self>) { + // Change NOTIFIED to EMPTY and EMPTY to PARKED. + let state = self.state.fetch_sub(1, Acquire); + if state == NOTIFIED { + return; + } + + // The state was set to PARKED. Wait until the `unpark` wakes us up. + blocking_scalar( + ticktimer_server(), + TicktimerScalar::WaitForCondition(self.index(), 0).into(), + ) + .expect("failed to send WaitForCondition command"); + + self.state.swap(EMPTY, Acquire); + } + + pub unsafe fn park_timeout(self: Pin<&Self>, timeout: Duration) { + // Change NOTIFIED to EMPTY and EMPTY to PARKED. + let state = self.state.fetch_sub(1, Acquire); + if state == NOTIFIED { + return; + } + + // A value of zero indicates an indefinite wait. Clamp the number of + // milliseconds to the allowed range. + let millis = usize::max(timeout.as_millis().try_into().unwrap_or(usize::MAX), 1); + + let was_timeout = blocking_scalar( + ticktimer_server(), + TicktimerScalar::WaitForCondition(self.index(), millis).into(), + ) + .expect("failed to send WaitForCondition command")[0] + != 0; + + let state = self.state.swap(EMPTY, Acquire); + if was_timeout && state == NOTIFIED { + // The state was set to NOTIFIED after we returned from the wait + // but before we reset the state. Therefore, a wakeup is on its + // way, which we need to consume here. + // NOTICE: this is a priority hole. + blocking_scalar( + ticktimer_server(), + TicktimerScalar::WaitForCondition(self.index(), 0).into(), + ) + .expect("failed to send WaitForCondition command"); + } + } + + pub fn unpark(self: Pin<&Self>) { + let state = self.state.swap(NOTIFIED, Release); + if state == PARKED { + // The thread is parked, wake it up. + blocking_scalar( + ticktimer_server(), + TicktimerScalar::NotifyCondition(self.index(), 1).into(), + ) + .expect("failed to send NotifyCondition command"); + } + } +} + +impl Drop for Parker { + fn drop(&mut self) { + scalar(ticktimer_server(), TicktimerScalar::FreeCondition(self.index()).into()).ok(); + } +} diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 5a84e37f8cf..4691fb3ad6f 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1083,6 +1083,11 @@ def bootstrap(args): include_file = 'config.{}.toml'.format(profile_aliases.get(profile) or profile) include_dir = os.path.join(rust_root, 'src', 'bootstrap', 'defaults') include_path = os.path.join(include_dir, include_file) + + if not os.path.exists(include_path): + raise Exception("Unrecognized config profile '{}'. Check src/bootstrap/defaults" + " for available options.".format(profile)) + # HACK: This works because `self.get_toml()` returns the first match it finds for a # specific key, so appending our defaults at the end allows the user to override them with open(include_path) as included_toml: diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index f710c01ca33..7c119b0273b 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -15,6 +15,7 @@ use std::fs::{self, File}; use std::io; use std::path::{Path, PathBuf}; use std::process::Command; +use std::sync::OnceLock; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::core::config::{Config, TargetSelection}; @@ -105,13 +106,16 @@ pub fn prebuilt_llvm_config( let llvm_cmake_dir = out_dir.join("lib/cmake/llvm"); let res = LlvmResult { llvm_config: build_llvm_config, llvm_cmake_dir }; - let smart_stamp_hash = generate_smart_stamp_hash( - &builder.config.src.join("src/llvm-project"), - &builder.in_tree_llvm_info.sha().unwrap_or_default(), - ); + static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new(); + let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| { + generate_smart_stamp_hash( + &builder.config.src.join("src/llvm-project"), + &builder.in_tree_llvm_info.sha().unwrap_or_default(), + ) + }); let stamp = out_dir.join("llvm-finished-building"); - let stamp = HashStamp::new(stamp, Some(&smart_stamp_hash)); + let stamp = HashStamp::new(stamp, Some(smart_stamp_hash)); if stamp.is_done() { if stamp.hash.is_none() { @@ -565,11 +569,11 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) { let version = output(cmd.arg("--version")); let mut parts = version.split('.').take(2).filter_map(|s| s.parse::<u32>().ok()); if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) { - if major >= 15 { + if major >= 16 { return; } } - panic!("\n\nbad LLVM version: {version}, need >=15.0\n\n") + panic!("\n\nbad LLVM version: {version}, need >=16.0\n\n") } fn configure_cmake( diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index ec859d30c82..77a4f2c4cb2 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -999,6 +999,7 @@ impl Step for RustdocGUI { let run = run.suite_path("tests/rustdoc-gui"); run.lazy_default_condition(Box::new(move || { builder.config.nodejs.is_some() + && builder.doc_tests != DocTests::Only && builder .config .npm @@ -1158,7 +1159,8 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/tools/tidy") + let default = run.builder.doc_tests != DocTests::Only; + run.path("src/tools/tidy").default_condition(default) } fn make_run(run: RunConfig<'_>) { @@ -1560,6 +1562,10 @@ impl Step for Compiletest { /// compiletest `mode` and `suite` arguments. For example `mode` can be /// "run-pass" or `suite` can be something like `debuginfo`. fn run(self, builder: &Builder<'_>) { + if builder.doc_tests == DocTests::Only { + return; + } + if builder.top_stage == 0 && env::var("COMPILETEST_FORCE_STAGE0").is_err() { eprintln!("\ ERROR: `--stage 0` runs compiletest on the beta compiler, not your local changes, and will almost always cause tests to fail @@ -1821,6 +1827,10 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--json"); + if builder.config.rust_debug_assertions_std { + cmd.arg("--with-debug-assertions"); + }; + let mut llvm_components_passed = false; let mut copts_passed = false; if builder.config.llvm_enabled() { @@ -2323,6 +2333,8 @@ impl Step for CrateLibrustc { } fn run(self, builder: &Builder<'_>) { + builder.ensure(compile::Std::new(self.compiler, self.target)); + builder.ensure(Crate { compiler: self.compiler, target: self.target, diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile deleted file mode 100644 index cefdcad7643..00000000000 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile +++ /dev/null @@ -1,59 +0,0 @@ -FROM ubuntu:22.04 - -ARG DEBIAN_FRONTEND=noninteractive - -RUN apt-get update && apt-get install -y --no-install-recommends \ - g++ \ - gcc-multilib \ - make \ - ninja-build \ - file \ - curl \ - ca-certificates \ - python3.11 \ - git \ - cmake \ - sudo \ - gdb \ - llvm-15-tools \ - llvm-15-dev \ - libedit-dev \ - libssl-dev \ - pkg-config \ - zlib1g-dev \ - xz-utils \ - nodejs \ - mingw-w64 \ - libgccjit-12-dev \ - && rm -rf /var/lib/apt/lists/* - -# 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 && \ - rm -f powershell.deb - -COPY scripts/sccache.sh /scripts/ -RUN sh /scripts/sccache.sh - -# Make `libgccjit.so` accessible to the linker. -RUN ln -s /usr/lib/gcc/x86_64-linux-gnu/12/libgccjit.so /usr/lib/x86_64-linux-gnu/libgccjit.so - -# We are disabling CI LLVM since this builder is intentionally using a host -# LLVM, rather than the typical src/llvm-project LLVM. -ENV NO_DOWNLOAD_CI_LLVM 1 - -# This is not the latest LLVM version, so some components required by tests may -# be missing. -ENV IS_NOT_LATEST_LLVM 1 - -# Using llvm-link-shared due to libffi issues -- see #34486 -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ - --llvm-root=/usr/lib/llvm-15 \ - --enable-llvm-link-shared \ - $USE_NEW_MANGLING \ - --set rust.thin-lto-import-instr-limit=10 - -COPY host-x86_64/x86_64-gnu-llvm-15/script.sh /tmp/ - -ENV SCRIPT /tmp/script.sh 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 c177e7387fc..4757c3e7329 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 @@ -49,6 +49,6 @@ ENV RUST_CONFIGURE_ARGS \ --enable-llvm-link-shared \ --set rust.thin-lto-import-instr-limit=10 -COPY host-x86_64/x86_64-gnu-llvm-15/script.sh /tmp/ +COPY host-x86_64/x86_64-gnu-llvm-16/script.sh /tmp/ ENV SCRIPT /tmp/script.sh diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/script.sh index 2eb751ca376..2eb751ca376 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/script.sh 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 76846f1fed7..dc5a04d4e06 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 @@ -45,6 +45,6 @@ ENV RUST_CONFIGURE_ARGS \ --enable-llvm-link-shared \ --set rust.thin-lto-import-instr-limit=10 -COPY host-x86_64/x86_64-gnu-llvm-15/script.sh /tmp/ +COPY host-x86_64/x86_64-gnu-llvm-16/script.sh /tmp/ ENV SCRIPT /tmp/script.sh diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index da29ffb8e5f..5b9c90273a3 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -334,7 +334,7 @@ jobs: - name: mingw-check-tidy <<: *job-linux-4c - - name: x86_64-gnu-llvm-15 + - name: x86_64-gnu-llvm-16 env: ENABLE_GCC_CODEGEN: "1" <<: *job-linux-16c @@ -486,11 +486,6 @@ jobs: RUST_BACKTRACE: 1 <<: *job-linux-8c - - name: x86_64-gnu-llvm-15 - env: - RUST_BACKTRACE: 1 - <<: *job-linux-8c - - name: x86_64-gnu-nopt <<: *job-linux-4c diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index 9f0662783a4..2a741fa3d02 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -121,10 +121,8 @@ export build_env=' env $build_env \ ./x.py build \ - --target aarch64-unknown-nto-qnx710 \ - --target x86_64-pc-nto-qnx710 \ - --target x86_64-unknown-linux-gnu \ - rustc library/core library/alloc + --target aarch64-unknown-nto-qnx710,x86_64-pc-nto-qnx710,x86_64-unknown-linux-gnu \ + rustc library/core library/alloc library/std ``` ## Running the Rust test suite diff --git a/src/doc/unstable-book/src/compiler-flags/function-return.md b/src/doc/unstable-book/src/compiler-flags/function-return.md new file mode 100644 index 00000000000..d044a6f68aa --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/function-return.md @@ -0,0 +1,25 @@ +# `function-return` + +The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/116853. + +------------------------ + +Option `-Zfunction-return` controls how function returns are converted. + +It is equivalent to [Clang]'s and [GCC]'s `-mfunction-return`. The Linux kernel +uses it for RETHUNK builds. For details, see [LLVM commit 2240d72f15f3] ("[X86] +initial -mfunction-return=thunk-extern support") which introduces the feature. + +Supported values for this option are: + + - `keep`: do not convert function returns. + - `thunk-extern`: convert function returns (`ret`) to jumps (`jmp`) + to an external symbol called `__x86_return_thunk`. + +Like in Clang, GCC's values `thunk` and `thunk-inline` are not supported. + +Only x86 and non-large code models are supported. + +[Clang]: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mfunction-return +[GCC]: https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#index-mfunction-return +[LLVM commit 2240d72f15f3]: https://github.com/llvm/llvm-project/commit/2240d72f15f3b7b9d9fb65450f9bf635fd310f6f diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index dc9098d3ade..fe1f43835ef 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1821,11 +1821,8 @@ fn maybe_expand_private_type_alias<'tcx>( } _ => None, }); - if let Some(ct) = const_ { - args.insert( - param.def_id.to_def_id(), - SubstParam::Constant(clean_const(ct, cx)), - ); + if let Some(_) = const_ { + args.insert(param.def_id.to_def_id(), SubstParam::Constant); } // FIXME(const_generics_defaults) indices.consts += 1; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index f079d01bd84..7a5cf803137 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2546,7 +2546,7 @@ pub(crate) enum TypeBindingKind { pub(crate) enum SubstParam { Type(Type), Lifetime(Lifetime), - Constant(Constant), + Constant, } impl SubstParam { diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index c22ad43e049..82f4a38384d 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -303,7 +303,8 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { debug!("trying to get a name from pattern: {p:?}"); Symbol::intern(&match p.kind { - PatKind::Wild | PatKind::Struct(..) => return kw::Underscore, + // FIXME(never_patterns): does this make sense? + PatKind::Wild | PatKind::Never | PatKind::Struct(..) => return kw::Underscore, PatKind::Binding(_, _, ident, _) => return ident.name, PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p), PatKind::Or(pats) => { diff --git a/src/librustdoc/formats/mod.rs b/src/librustdoc/formats/mod.rs index e607a16ad54..0056fb48530 100644 --- a/src/librustdoc/formats/mod.rs +++ b/src/librustdoc/formats/mod.rs @@ -9,21 +9,6 @@ pub(crate) use renderer::{run_format, FormatRenderer}; use crate::clean::{self, ItemId}; use crate::html::render::Context; -/// Specifies whether rendering directly implemented trait items or ones from a certain Deref -/// impl. -pub(crate) enum AssocItemRender<'a> { - All, - DerefFor { trait_: &'a clean::Path, type_: &'a clean::Type, deref_mut_: bool }, -} - -/// For different handling of associated items from the Deref target of a type rather than the type -/// itself. -#[derive(Copy, Clone, PartialEq)] -pub(crate) enum RenderMode { - Normal, - ForDeref { mut_: bool }, -} - /// Metadata about implementations for a type or trait. #[derive(Clone, Debug)] pub(crate) struct Impl { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 06bfd4652d6..bed8f6ffef5 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1305,7 +1305,7 @@ impl clean::Impl { primitive_link_fragment( f, PrimitiveType::Tuple, - format_args!("fn ({name}₁, {name}₂, …, {name}ₙ{ellipsis})"), + format_args!("fn({name}₁, {name}₂, …, {name}ₙ{ellipsis})"), "#trait-implementations-1", cx, )?; diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index ff5c761208b..348d546c236 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -66,7 +66,7 @@ use crate::clean::{self, ItemId, RenderedLink, SelfTy}; use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; -use crate::formats::{AssocItemRender, Impl, RenderMode}; +use crate::formats::Impl; use crate::html::escape::Escape; use crate::html::format::{ display_fn, href, join_with_double_colon, print_abi_with_space, print_constness_with_space, @@ -89,6 +89,21 @@ pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ { }) } +/// Specifies whether rendering directly implemented trait items or ones from a certain Deref +/// impl. +pub(crate) enum AssocItemRender<'a> { + All, + DerefFor { trait_: &'a clean::Path, type_: &'a clean::Type, deref_mut_: bool }, +} + +/// For different handling of associated items from the Deref target of a type rather than the type +/// itself. +#[derive(Copy, Clone, PartialEq)] +pub(crate) enum RenderMode { + Normal, + ForDeref { mut_: bool }, +} + // Helper structs for rendering items/sidebars and carrying along contextual // information diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 14387e0d45d..2dac943f695 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -22,12 +22,13 @@ use super::{ item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls, render_assoc_item, render_assoc_items, render_attributes_in_code, render_attributes_in_pre, render_impl, render_rightside, render_stability_since_raw, - render_stability_since_raw_with_extra, AssocItemLink, Context, ImplRenderingParameters, + render_stability_since_raw_with_extra, AssocItemLink, AssocItemRender, Context, + ImplRenderingParameters, RenderMode, }; use crate::clean; use crate::config::ModuleSorting; use crate::formats::item_type::ItemType; -use crate::formats::{AssocItemRender, Impl, RenderMode}; +use crate::formats::Impl; use crate::html::escape::Escape; use crate::html::format::{ display_fn, join_with_double_colon, print_abi_with_space, print_constness_with_space, diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index d2c7c578c08..b04776e91dc 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -15,14 +15,14 @@ use rustc_span::Symbol; use serde::ser::SerializeSeq; use serde::{Serialize, Serializer}; -use super::{collect_paths_for_type, ensure_trailing_slash, Context}; +use super::{collect_paths_for_type, ensure_trailing_slash, Context, RenderMode}; use crate::clean::{Crate, Item, ItemId, ItemKind}; use crate::config::{EmitType, RenderOptions}; use crate::docfs::PathError; use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; -use crate::formats::{Impl, RenderMode}; +use crate::formats::Impl; use crate::html::format::Buffer; use crate::html::render::{AssocItemLink, ImplRenderingParameters}; use crate::html::{layout, static_files}; diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 7cc0f2e8f1e..d613997cd7f 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1318,8 +1318,7 @@ function preLoadCss(cssUrl) { const infos = [ `For a full list of all search features, take a look <a \ -href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\ -#the-search-interface">here</a>.`, +href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.html">here</a>.`, "Prefix searches with a type followed by a colon (e.g., <code>fn:</code>) to \ restrict the search to a given item kind.", "Accepted kinds are: <code>fn</code>, <code>mod</code>, <code>struct</code>, \ diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 9b13310ca596020a737aaa47daa4ed9ff8898a2 +Subproject 26333c732095d207aa05932ce863d850fb30938 diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs index 575fead5bf3..630df9a84f5 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -46,7 +46,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { pats.iter().all(unary_pattern) } match &pat.kind { - PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) | PatKind::Wild | PatKind::Or(_) => { + PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) | PatKind::Wild | PatKind::Never | PatKind::Or(_) => { false }, PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs index 70892ce608f..2ab04682f1d 100644 --- a/src/tools/clippy/clippy_lints/src/formatting.rs +++ b/src/tools/clippy/clippy_lints/src/formatting.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note}; use clippy_utils::is_span_if; use clippy_utils::source::snippet_opt; -use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; +use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind}; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -144,7 +144,7 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) { let eq_span = lhs.span.between(rhs.span); if let ExprKind::Unary(op, ref sub_rhs) = rhs.kind { if let Some(eq_snippet) = snippet_opt(cx, eq_span) { - let op = UnOp::to_string(op); + let op = op.as_str(); let eqop_span = lhs.span.between(sub_rhs.span); if eq_snippet.ends_with('=') { span_lint_and_note( @@ -177,11 +177,11 @@ fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) { && let unop_operand_span = rhs.span.until(un_rhs.span) && let Some(binop_snippet) = snippet_opt(cx, binop_span) && let Some(unop_operand_snippet) = snippet_opt(cx, unop_operand_span) - && let binop_str = BinOpKind::to_string(&binop.node) + && let binop_str = binop.node.as_str() // no space after BinOp operator and space after UnOp operator && binop_snippet.ends_with(binop_str) && unop_operand_snippet.ends_with(' ') { - let unop_str = UnOp::to_string(op); + let unop_str = op.as_str(); let eqop_span = lhs.span.between(un_rhs.span); span_lint_and_help( cx, diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index 745be671b86..cbf478620ec 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -150,6 +150,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { #[derive(Clone, Copy)] enum NormalizedPat<'a> { Wild, + Never, Struct(Option<DefId>, &'a [(Symbol, Self)]), Tuple(Option<DefId>, &'a [Self]), Or(&'a [Self]), @@ -229,6 +230,7 @@ impl<'a> NormalizedPat<'a> { PatKind::Binding(.., Some(pat)) | PatKind::Box(pat) | PatKind::Ref(pat, _) => { Self::from_pat(cx, arena, pat) }, + PatKind::Never => Self::Never, PatKind::Struct(ref path, fields, _) => { let fields = arena.alloc_from_iter(fields.iter().map(|f| (f.ident.name, Self::from_pat(cx, arena, f.pat)))); @@ -333,6 +335,7 @@ impl<'a> NormalizedPat<'a> { fn has_overlapping_values(&self, other: &Self) -> bool { match (*self, *other) { (Self::Wild, _) | (_, Self::Wild) => true, + (Self::Never, Self::Never) => true, (Self::Or(pats), ref other) | (ref other, Self::Or(pats)) => { pats.iter().any(|pat| pat.has_overlapping_values(other)) }, diff --git a/src/tools/clippy/clippy_lints/src/precedence.rs b/src/tools/clippy/clippy_lints/src/precedence.rs index b638e83997a..52cec437378 100644 --- a/src/tools/clippy/clippy_lints/src/precedence.rs +++ b/src/tools/clippy/clippy_lints/src/precedence.rs @@ -78,7 +78,7 @@ impl EarlyLintPass for Precedence { let sugg = format!( "({}) {} ({})", snippet_with_applicability(cx, left.span, "..", &mut applicability), - op.to_string(), + op.as_str(), snippet_with_applicability(cx, right.span, "..", &mut applicability) ); span_sugg(expr, sugg, applicability); @@ -87,7 +87,7 @@ impl EarlyLintPass for Precedence { let sugg = format!( "({}) {} {}", snippet_with_applicability(cx, left.span, "..", &mut applicability), - op.to_string(), + op.as_str(), snippet_with_applicability(cx, right.span, "..", &mut applicability) ); span_sugg(expr, sugg, applicability); @@ -96,7 +96,7 @@ impl EarlyLintPass for Precedence { let sugg = format!( "{} {} ({})", snippet_with_applicability(cx, left.span, "..", &mut applicability), - op.to_string(), + op.as_str(), snippet_with_applicability(cx, right.span, "..", &mut applicability) ); span_sugg(expr, sugg, applicability); diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs index 92de7917871..b332309a552 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs @@ -298,7 +298,7 @@ fn replace_left_sugg( ) -> String { format!( "{left_suggestion} {} {}", - binop.op.to_string(), + binop.op.as_str(), snippet_with_applicability(cx, binop.right.span, "..", applicability), ) } @@ -312,7 +312,7 @@ fn replace_right_sugg( format!( "{} {} {right_suggestion}", snippet_with_applicability(cx, binop.left.span, "..", applicability), - binop.op.to_string(), + binop.op.as_str(), ) } diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index 8ff088a208f..952c0dc72b1 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -226,7 +226,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us // Therefore they are not some form of constructor `C`, // with which a pattern `C(p_0)` may be formed, // which we would want to join with other `C(p_j)`s. - Ident(.., None) | Lit(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_) + Ident(.., None) | Lit(_) | Wild | Never | Path(..) | Range(..) | Rest | MacCall(_) // Skip immutable refs, as grouping them saves few characters, // and almost always requires adding parens (increasing noisiness). // In the case of only two patterns, replacement adds net characters. diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index e8842ce10f8..e83c04eda20 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -629,6 +629,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { match pat.value.kind { PatKind::Wild => kind!("Wild"), + PatKind::Never => kind!("Never"), PatKind::Binding(ann, _, name, sub) => { bind!(self, name); opt_bind!(self, sub); diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 8031e6faa74..34ec83709ff 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1017,6 +1017,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } e.hash(&mut self.s); }, + PatKind::Never => {}, PatKind::Wild => {}, } } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 172b063df31..fd37713fc60 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1707,6 +1707,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { match pat.kind { PatKind::Wild => false, + PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable. PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)), PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat), PatKind::Lit(..) | PatKind::Range(..) => true, diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index db79dd78801..f143163152e 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -382,7 +382,7 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String { | AssocOp::GreaterEqual => { format!( "{lhs} {} {rhs}", - op.to_ast_binop().expect("Those are AST ops").to_string() + op.to_ast_binop().expect("Those are AST ops").as_str() ) }, AssocOp::Assign => format!("{lhs} = {rhs}"), diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index e7d2e1aab3a..e85f6319936 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -242,6 +242,9 @@ pub struct Config { /// Run ignored tests pub run_ignored: bool, + /// Whether to run tests with `ignore-debug` header + pub with_debug_assertions: bool, + /// Only run tests that match these filters pub filters: Vec<String>, diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs index 3a1b9dff3a6..e2a04b7e558 100644 --- a/src/tools/compiletest/src/header/cfg.rs +++ b/src/tools/compiletest/src/header/cfg.rs @@ -190,8 +190,8 @@ pub(super) fn parse_cfg_name_directive<'a>( } condition! { name: "debug", - condition: cfg!(debug_assertions), - message: "when building with debug assertions", + condition: config.with_debug_assertions, + message: "when running tests with `ignore-debug` header", } condition! { name: config.debugger.as_ref().map(|d| d.to_str()), diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index bb09c03ef5b..5a80b9121f0 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -81,6 +81,7 @@ pub fn parse_config(args: Vec<String>) -> Config { ) .optopt("", "run", "whether to execute run-* tests", "auto | always | never") .optflag("", "ignored", "run tests marked as ignored") + .optflag("", "with-debug-assertions", "whether to run tests with `ignore-debug` header") .optmulti("", "skip", "skip tests matching SUBSTRING. Can be passed multiple times", "SUBSTRING") .optflag("", "exact", "filters match exactly") .optopt( @@ -203,6 +204,7 @@ pub fn parse_config(args: Vec<String>) -> Config { let src_base = opt_path(matches, "src-base"); let run_ignored = matches.opt_present("ignored"); + let with_debug_assertions = matches.opt_present("with-debug-assertions"); let mode = matches.opt_str("mode").unwrap().parse().expect("invalid mode"); let has_tidy = if mode == Mode::Rustdoc { Command::new("tidy") @@ -238,6 +240,7 @@ pub fn parse_config(args: Vec<String>) -> Config { suite: matches.opt_str("suite").unwrap(), debugger: None, run_ignored, + with_debug_assertions, filters: matches.free.clone(), skip: matches.opt_strs("skip"), filter_exact: matches.opt_present("exact"), diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 0006bbc97fe..542c0c6cee9 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -48cfbe0cdfbc812a9bd8ce0b3bf6ca003bd12e6a +c52b8763bf36027f24baabe1f97cab3d3571c9e5 diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index ba40a1b3c32..be30627cf0c 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -66,11 +66,6 @@ pub trait FileDescriptor: std::fmt::Debug + Any { fn is_tty(&self, _communicate_allowed: bool) -> bool { false } - - #[cfg(unix)] - fn as_unix_host_fd(&self) -> Option<i32> { - None - } } impl dyn FileDescriptor { @@ -150,12 +145,6 @@ impl FileDescriptor for FileHandle { Ok(Box::new(FileHandle { file: duplicated, writable: self.writable })) } - #[cfg(unix)] - fn as_unix_host_fd(&self) -> Option<i32> { - use std::os::unix::io::AsRawFd; - Some(self.file.as_raw_fd()) - } - fn is_tty(&self, communicate_allowed: bool) -> bool { communicate_allowed && self.file.is_terminal() } @@ -183,11 +172,6 @@ impl FileDescriptor for io::Stdin { Ok(Box::new(io::stdin())) } - #[cfg(unix)] - fn as_unix_host_fd(&self) -> Option<i32> { - Some(libc::STDIN_FILENO) - } - fn is_tty(&self, communicate_allowed: bool) -> bool { communicate_allowed && self.is_terminal() } @@ -220,11 +204,6 @@ impl FileDescriptor for io::Stdout { Ok(Box::new(io::stdout())) } - #[cfg(unix)] - fn as_unix_host_fd(&self) -> Option<i32> { - Some(libc::STDOUT_FILENO) - } - fn is_tty(&self, communicate_allowed: bool) -> bool { communicate_allowed && self.is_terminal() } @@ -250,11 +229,6 @@ impl FileDescriptor for io::Stderr { Ok(Box::new(io::stderr())) } - #[cfg(unix)] - fn as_unix_host_fd(&self) -> Option<i32> { - Some(libc::STDERR_FILENO) - } - fn is_tty(&self, communicate_allowed: bool) -> bool { communicate_allowed && self.is_terminal() } diff --git a/src/tools/miri/tests/fail/uninit/uninit-after-aggregate-assign.rs b/src/tools/miri/tests/fail/uninit/uninit-after-aggregate-assign.rs new file mode 100644 index 00000000000..98f9cc96fd0 --- /dev/null +++ b/src/tools/miri/tests/fail/uninit/uninit-after-aggregate-assign.rs @@ -0,0 +1,27 @@ +#![feature(core_intrinsics)] +#![feature(custom_mir)] + +use std::intrinsics::mir::*; +use std::ptr; + +#[repr(C)] +struct S(u8, u16); + +#[custom_mir(dialect = "runtime", phase = "optimized")] +fn main() { + mir! { + let s: S; + let sptr; + let sptr2; + let _val; + { + sptr = ptr::addr_of_mut!(s); + sptr2 = sptr as *mut [u8; 4]; + *sptr2 = [0; 4]; + *sptr = S(0, 0); // should reset the padding + _val = *sptr2; // should hence be UB + //~^ERROR: encountered uninitialized memory + Return() + } + } +} diff --git a/src/tools/miri/tests/fail/uninit/uninit-after-aggregate-assign.stderr b/src/tools/miri/tests/fail/uninit/uninit-after-aggregate-assign.stderr new file mode 100644 index 00000000000..5f3d9bde1f2 --- /dev/null +++ b/src/tools/miri/tests/fail/uninit/uninit-after-aggregate-assign.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value at [1]: encountered uninitialized memory, but expected an integer + --> $DIR/uninit-after-aggregate-assign.rs:LL:CC + | +LL | _val = *sptr2; // should hence be UB + | ^^^^^^^^^^^^^ constructing invalid value at [1]: encountered uninitialized memory, but expected an integer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/uninit-after-aggregate-assign.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/uninit_buffer.rs b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.rs index d622b2fa7d8..8deaa30d50f 100644 --- a/src/tools/miri/tests/fail/uninit_buffer.rs +++ b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.rs @@ -1,3 +1,4 @@ +//@compile-flags: -Zmiri-disable-validation //@error-in-other-file: memory is uninitialized at [0x4..0x10] #![allow(dropping_copy_types)] diff --git a/src/tools/miri/tests/fail/uninit_buffer.stderr b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr index 2d04c0f9be2..cca17a07ec2 100644 --- a/src/tools/miri/tests/fail/uninit_buffer.stderr +++ b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic.stderr @@ -10,7 +10,7 @@ LL | let mut order = unsafe { compare_bytes(left.as_ptr(), right.as_ptr( = note: inside `<u8 as core::slice::cmp::SliceOrd>::compare` at RUSTLIB/core/src/slice/cmp.rs:LL:CC = note: inside `core::slice::cmp::<impl std::cmp::Ord for [u8]>::cmp` at RUSTLIB/core/src/slice/cmp.rs:LL:CC note: inside `main` - --> $DIR/uninit_buffer.rs:LL:CC + --> $DIR/uninit_alloc_diagnostic.rs:LL:CC | LL | drop(slice1.cmp(slice2)); | ^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/uninit_buffer_with_provenance.rs b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.rs index ca825901372..adabff4a2ce 100644 --- a/src/tools/miri/tests/fail/uninit_buffer_with_provenance.rs +++ b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.rs @@ -1,3 +1,4 @@ +//@compile-flags: -Zmiri-disable-validation //@error-in-other-file: memory is uninitialized at [0x4..0x8] //@normalize-stderr-test: "a[0-9]+" -> "ALLOC" #![feature(strict_provenance)] diff --git a/src/tools/miri/tests/fail/uninit_buffer_with_provenance.stderr b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr index cd842f0eba5..4dc2d27ead4 100644 --- a/src/tools/miri/tests/fail/uninit_buffer_with_provenance.stderr +++ b/src/tools/miri/tests/fail/uninit/uninit_alloc_diagnostic_with_provenance.stderr @@ -10,7 +10,7 @@ LL | let mut order = unsafe { compare_bytes(left.as_ptr(), right.as_ptr( = note: inside `<u8 as core::slice::cmp::SliceOrd>::compare` at RUSTLIB/core/src/slice/cmp.rs:LL:CC = note: inside `core::slice::cmp::<impl std::cmp::Ord for [u8]>::cmp` at RUSTLIB/core/src/slice/cmp.rs:LL:CC note: inside `main` - --> $DIR/uninit_buffer_with_provenance.rs:LL:CC + --> $DIR/uninit_alloc_diagnostic_with_provenance.rs:LL:CC | LL | drop(slice1.cmp(slice2)); | ^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/miri/tests/fail/uninit_byte_read.rs b/src/tools/miri/tests/fail/uninit/uninit_byte_read.rs index f1dace0cff9..f1dace0cff9 100644 --- a/src/tools/miri/tests/fail/uninit_byte_read.rs +++ b/src/tools/miri/tests/fail/uninit/uninit_byte_read.rs diff --git a/src/tools/miri/tests/fail/uninit_byte_read.stderr b/src/tools/miri/tests/fail/uninit/uninit_byte_read.stderr index b70f0ad9950..b70f0ad9950 100644 --- a/src/tools/miri/tests/fail/uninit_byte_read.stderr +++ b/src/tools/miri/tests/fail/uninit/uninit_byte_read.stderr diff --git a/src/tools/miri/tests/fail/invalid_bool.rs b/src/tools/miri/tests/fail/validity/invalid_bool_op.rs index fe9bb3bed7f..fe9bb3bed7f 100644 --- a/src/tools/miri/tests/fail/invalid_bool.rs +++ b/src/tools/miri/tests/fail/validity/invalid_bool_op.rs diff --git a/src/tools/miri/tests/fail/invalid_bool.stderr b/src/tools/miri/tests/fail/validity/invalid_bool_op.stderr index fd1ea5087b2..b938d29e760 100644 --- a/src/tools/miri/tests/fail/invalid_bool.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_bool_op.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: interpreting an invalid 8-bit value as a bool: 0x02 - --> $DIR/invalid_bool.rs:LL:CC + --> $DIR/invalid_bool_op.rs:LL:CC | LL | let _x = b == std::hint::black_box(true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ interpreting an invalid 8-bit value as a bool: 0x02 @@ -7,7 +7,7 @@ LL | let _x = b == std::hint::black_box(true); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/invalid_bool.rs:LL:CC + = note: inside `main` at $DIR/invalid_bool_op.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/invalid_char.rs b/src/tools/miri/tests/fail/validity/invalid_char_op.rs index 69924822944..69924822944 100644 --- a/src/tools/miri/tests/fail/invalid_char.rs +++ b/src/tools/miri/tests/fail/validity/invalid_char_op.rs diff --git a/src/tools/miri/tests/fail/invalid_char.stderr b/src/tools/miri/tests/fail/validity/invalid_char_op.stderr index 81d6cdad157..113eecd9cf7 100644 --- a/src/tools/miri/tests/fail/invalid_char.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_char_op.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: interpreting an invalid 32-bit value as a char: $HEX - --> $DIR/invalid_char.rs:LL:CC + --> $DIR/invalid_char_op.rs:LL:CC | LL | let _x = c == 'x'; | ^^^^^^^^ interpreting an invalid 32-bit value as a char: $HEX @@ -7,7 +7,7 @@ LL | let _x = c == 'x'; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/invalid_char.rs:LL:CC + = note: inside `main` at $DIR/invalid_char_op.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/invalid_enum_tag.rs b/src/tools/miri/tests/fail/validity/invalid_enum_op.rs index 84fa2c29739..84fa2c29739 100644 --- a/src/tools/miri/tests/fail/invalid_enum_tag.rs +++ b/src/tools/miri/tests/fail/validity/invalid_enum_op.rs diff --git a/src/tools/miri/tests/fail/invalid_enum_tag.stderr b/src/tools/miri/tests/fail/validity/invalid_enum_op.stderr index 5a446bb2a56..e7997689c51 100644 --- a/src/tools/miri/tests/fail/invalid_enum_tag.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_enum_op.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: enum value has invalid tag: $HEX - --> $DIR/invalid_enum_tag.rs:LL:CC + --> $DIR/invalid_enum_op.rs:LL:CC | LL | let _val = mem::discriminant(&f); | ^^^^^^^^^^^^^^^^^^^^^ enum value has invalid tag: $HEX @@ -7,7 +7,7 @@ LL | let _val = mem::discriminant(&f); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/invalid_enum_tag.rs:LL:CC + = note: inside `main` at $DIR/invalid_enum_op.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/invalid_int.rs b/src/tools/miri/tests/fail/validity/invalid_int_op.rs index 2435a87a6f2..2435a87a6f2 100644 --- a/src/tools/miri/tests/fail/invalid_int.rs +++ b/src/tools/miri/tests/fail/validity/invalid_int_op.rs diff --git a/src/tools/miri/tests/fail/invalid_int.stderr b/src/tools/miri/tests/fail/validity/invalid_int_op.stderr index a450b939384..df344311b75 100644 --- a/src/tools/miri/tests/fail/invalid_int.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_int_op.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory - --> $DIR/invalid_int.rs:LL:CC + --> $DIR/invalid_int_op.rs:LL:CC | LL | let i = unsafe { std::mem::MaybeUninit::<i32>::uninit().assume_init() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory @@ -7,7 +7,7 @@ LL | let i = unsafe { std::mem::MaybeUninit::<i32>::uninit().assume_init() } = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/invalid_int.rs:LL:CC + = note: inside `main` at $DIR/invalid_int_op.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/pass/concurrency/sync.rs b/src/tools/miri/tests/pass/concurrency/sync.rs index dccc9d104dd..e93e617fd26 100644 --- a/src/tools/miri/tests/pass/concurrency/sync.rs +++ b/src/tools/miri/tests/pass/concurrency/sync.rs @@ -83,7 +83,7 @@ fn check_conditional_variables_timed_wait_notimeout() { cvar.notify_one(); }); - let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(500)).unwrap(); + let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(1000)).unwrap(); assert!(!timeout.timed_out()); handle.join().unwrap(); } diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 701e36d74a6..5a8d971c3d4 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -72,8 +72,8 @@ dependencies = [ "cfg", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "profile", + "rust-analyzer-salsa", "rustc-hash", - "salsa", "stdx", "syntax", "test-utils", @@ -160,32 +160,32 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chalk-derive" -version = "0.94.0" +version = "0.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0322d5289ceba3217a03c9af72aa403d87542822b753daa1da32e4b992a4e80" +checksum = "329427f28cd2bddaacd47c4dcd3d7082d315c61fb164394c690fe98c1b6ee9d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", "synstructure", ] [[package]] name = "chalk-ir" -version = "0.94.0" +version = "0.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0946cbc6d9136980a24a2dddf1888b5f0aa978dda300a3aa470b55b777b6bf3c" +checksum = "9e1e1659238bd598d0f7dbc5034cf1ff46010a3d6827704c9ed443c8359cb484" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", "chalk-derive", "lazy_static", ] [[package]] name = "chalk-recursive" -version = "0.94.0" +version = "0.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd93fedbeeadc0cd4d0eb73bd061b621af99f5324a6a518264c8ef5e526e0ec" +checksum = "b3e0bff0ba1bed11407384fcec0353aeb6888901e63cb47d04505ec47adad847" dependencies = [ "chalk-derive", "chalk-ir", @@ -196,15 +196,15 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.94.0" +version = "0.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a254cff72303c58c82df421cfe9465606372b81588923fcf179922b7eaad9a53" +checksum = "eb9c46d501cf83732a91056c0c846ae7a16d6b3c67a6a6bb5e9cc0a2e91563b6" dependencies = [ "chalk-derive", "chalk-ir", "ena", - "indexmap 2.1.0", - "itertools 0.10.5", + "indexmap", + "itertools", "petgraph", "rustc-hash", "tracing", @@ -216,7 +216,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5080df6b0f0ecb76cab30808f00d937ba725cebe266a3da8cd89dff92f2a9916" dependencies = [ - "nix", + "nix 0.26.2", "winapi", ] @@ -290,6 +290,16 @@ dependencies = [ ] [[package]] +name = "ctrlc" +version = "3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf" +dependencies = [ + "nix 0.27.1", + "windows-sys 0.48.0", +] + +[[package]] name = "dashmap" version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -299,7 +309,7 @@ dependencies = [ "hashbrown 0.12.3", "lock_api", "once_cell", - "parking_lot_core 0.9.6", + "parking_lot_core", ] [[package]] @@ -310,7 +320,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] @@ -450,12 +460,9 @@ checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" [[package]] name = "heck" -version = "0.3.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -477,7 +484,7 @@ dependencies = [ "hir-def", "hir-expand", "hir-ty", - "itertools 0.12.0", + "itertools", "once_cell", "profile", "rustc-hash", @@ -504,9 +511,9 @@ dependencies = [ "fst", "hashbrown 0.12.3", "hir-expand", - "indexmap 2.1.0", + "indexmap", "intern", - "itertools 0.12.0", + "itertools", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "limit", "mbe", @@ -534,7 +541,7 @@ dependencies = [ "expect-test", "hashbrown 0.12.3", "intern", - "itertools 0.12.0", + "itertools", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "limit", "mbe", @@ -566,7 +573,7 @@ dependencies = [ "hir-def", "hir-expand", "intern", - "itertools 0.12.0", + "itertools", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "limit", "nohash-hasher", @@ -613,7 +620,7 @@ dependencies = [ "ide-db", "ide-diagnostics", "ide-ssr", - "itertools 0.12.0", + "itertools", "nohash-hasher", "oorandom", "profile", @@ -639,7 +646,7 @@ dependencies = [ "expect-test", "hir", "ide-db", - "itertools 0.12.0", + "itertools", "profile", "smallvec", "sourcegen", @@ -658,7 +665,7 @@ dependencies = [ "expect-test", "hir", "ide-db", - "itertools 0.12.0", + "itertools", "once_cell", "profile", "smallvec", @@ -679,8 +686,8 @@ dependencies = [ "expect-test", "fst", "hir", - "indexmap 2.1.0", - "itertools 0.12.0", + "indexmap", + "itertools", "limit", "line-index 0.1.0-pre.1", "memchr", @@ -711,7 +718,7 @@ dependencies = [ "expect-test", "hir", "ide-db", - "itertools 0.12.0", + "itertools", "once_cell", "profile", "serde_json", @@ -730,7 +737,7 @@ dependencies = [ "expect-test", "hir", "ide-db", - "itertools 0.12.0", + "itertools", "nohash-hasher", "parser", "stdx", @@ -752,16 +759,6 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" @@ -791,15 +788,6 @@ dependencies = [ ] [[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] name = "intern" version = "0.0.0" dependencies = [ @@ -811,15 +799,6 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" @@ -931,7 +910,7 @@ dependencies = [ "crossbeam-channel", "ide", "ide-db", - "itertools 0.12.0", + "itertools", "proc-macro-api", "project-model", "tracing", @@ -961,6 +940,7 @@ name = "lsp-server" version = "0.7.4" dependencies = [ "crossbeam-channel", + "ctrlc", "log", "lsp-types", "serde", @@ -1101,6 +1081,17 @@ dependencies = [ ] [[package]] +name = "nix" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "libc", +] + +[[package]] name = "nohash-hasher" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1176,37 +1167,12 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" [[package]] name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - -[[package]] -name = "parking_lot" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.6", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -1276,7 +1242,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.1.0", + "indexmap", ] [[package]] @@ -1371,7 +1337,7 @@ dependencies = [ "cargo_metadata", "cfg", "expect-test", - "itertools 0.12.0", + "itertools", "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "paths", "profile", @@ -1436,50 +1402,43 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2ea80a299f04a896000ce17b76f3aa1d2fe59f347fbc99c4b8970316ef5a0d" +checksum = "b5f38444d48da534b3bb612713fce9b0aeeffb2e0dfa242764f55482acc5b52d" dependencies = [ "bitflags 1.3.2", - "ra-ap-rustc_index 0.19.0", + "ra-ap-rustc_index", "tracing", ] [[package]] name = "ra-ap-rustc_index" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643ca3609870b1778d9cd1f2a8e4ccb4af0f48f3637cc257a09494d087bd93dc" -dependencies = [ - "arrayvec", - "smallvec", -] - -[[package]] -name = "ra-ap-rustc_index" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4556489ef652e5eb6cdad6078fff08507badac80bfc1f79085c85a6d8b77ab5c" +checksum = "69fb5da07e1a39222d9c311203123c3b6a86420fa06dc695aa1661b0aecf8d16" dependencies = [ "arrayvec", + "ra-ap-rustc_index_macros", "smallvec", ] [[package]] -name = "ra-ap-rustc_lexer" -version = "0.14.0" +name = "ra-ap-rustc_index_macros" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ffd24f9ba4f1d25ff27ca1469b8d22a3bdfb12cf644fc8bfcb63121fa5da6b" +checksum = "3d69f9f6af58124f2da0cb8b0c3d8494e0d883a5fe0c6732258bde81ac5a87cc" dependencies = [ - "unicode-properties", - "unicode-xid", + "proc-macro2", + "quote", + "syn", + "synstructure", ] [[package]] name = "ra-ap-rustc_lexer" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e573bf707e01fe2841dbdedeed42012004274db0edc0314e6e3e58a40598fc" +checksum = "9d5e8650195795c4023d8321846466994a975bc457cb8a91c0b3b17a5fc8ba40" dependencies = [ "unicode-properties", "unicode-xid", @@ -1487,12 +1446,12 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.14.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "207b5ac1a21d4926695e03b605ffb9f63d4968e0488e9197c04c512c37303aa7" +checksum = "0a6b325ee1ec90e4dbd4394913adf4ef32e4fcf2b311ec9563a0fa50cd549af6" dependencies = [ - "ra-ap-rustc_index 0.14.0", - "ra-ap-rustc_lexer 0.14.0", + "ra-ap-rustc_index", + "ra-ap-rustc_lexer", ] [[package]] @@ -1563,7 +1522,7 @@ dependencies = [ "ide", "ide-db", "ide-ssr", - "itertools 0.12.0", + "itertools", "load-cargo", "lsp-server 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "lsp-types", @@ -1573,8 +1532,8 @@ dependencies = [ "nohash-hasher", "num_cpus", "oorandom", - "parking_lot 0.12.1", - "parking_lot_core 0.9.6", + "parking_lot", + "parking_lot_core", "parser", "proc-macro-api", "profile", @@ -1604,6 +1563,35 @@ dependencies = [ ] [[package]] +name = "rust-analyzer-salsa" +version = "0.17.0-pre.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca92b657d614d076800aa7bf5d5ba33564e71fa7f16cd79eacdfe301a50ab1c" +dependencies = [ + "crossbeam-utils", + "indexmap", + "lock_api", + "log", + "oorandom", + "parking_lot", + "rust-analyzer-salsa-macros", + "rustc-hash", + "smallvec", +] + +[[package]] +name = "rust-analyzer-salsa-macros" +version = "0.17.0-pre.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b190359266d293f2ee13eaa502a766dc8b77b63fbaa5d460d24fd0210675ceef" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "rustc-demangle" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1614,8 +1602,8 @@ name = "rustc-dependencies" version = "0.0.0" dependencies = [ "ra-ap-rustc_abi", - "ra-ap-rustc_index 0.19.0", - "ra-ap-rustc_lexer 0.19.0", + "ra-ap-rustc_index", + "ra-ap-rustc_lexer", "ra-ap-rustc_parse_format", ] @@ -1632,35 +1620,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] -name = "salsa" -version = "0.17.0-pre.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b223dccb46c32753144d0b51290da7230bb4aedcd8379d6b4c9a474c18bf17a" -dependencies = [ - "crossbeam-utils", - "indexmap 1.9.3", - "lock_api", - "log", - "oorandom", - "parking_lot 0.11.2", - "rustc-hash", - "salsa-macros", - "smallvec", -] - -[[package]] -name = "salsa-macros" -version = "0.17.0-pre.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac6c2e352df550bf019da7b16164ed2f7fa107c39653d1311d1bba42d1582ff7" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1701,22 +1660,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.192" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.192" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] @@ -1725,7 +1684,7 @@ version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ - "indexmap 2.1.0", + "indexmap", "itoa", "ryu", "serde", @@ -1739,7 +1698,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] @@ -1800,17 +1759,6 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" @@ -1828,7 +1776,7 @@ checksum = "285ba80e733fac80aa4270fbcdf83772a79b80aa35c97075320abfee4a915b06" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", "unicode-xid", ] @@ -1839,8 +1787,8 @@ dependencies = [ "cov-mark", "either", "expect-test", - "indexmap 2.1.0", - "itertools 0.12.0", + "indexmap", + "itertools", "once_cell", "parser", "proc-macro2", @@ -1874,7 +1822,7 @@ dependencies = [ name = "text-edit" version = "0.0.0" dependencies = [ - "itertools 0.12.0", + "itertools", "text-size", ] @@ -1901,7 +1849,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] @@ -2002,7 +1950,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn", ] [[package]] @@ -2113,12 +2061,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7f91c8b21fbbaa18853c3d0801c78f4fc94cdb976699bb03e832e75f7fd22f0" [[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - -[[package]] name = "unicode-xid" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2153,7 +2095,7 @@ name = "vfs" version = "0.0.0" dependencies = [ "fst", - "indexmap 2.1.0", + "indexmap", "nohash-hasher", "paths", "rustc-hash", diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml index 171c113a950..5ad88f65188 100644 --- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/base-db/Cargo.toml @@ -12,7 +12,7 @@ rust-version.workspace = true doctest = false [dependencies] -salsa = "0.17.0-pre.2" +rust-analyzer-salsa = "0.17.0-pre.3" rustc-hash = "1.1.0" triomphe.workspace = true diff --git a/src/tools/rust-analyzer/crates/base-db/src/fixture.rs b/src/tools/rust-analyzer/crates/base-db/src/fixture.rs index 3f5ccb621c7..3da555a47ac 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/fixture.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/fixture.rs @@ -13,9 +13,9 @@ use vfs::{file_set::FileSet, VfsPath}; use crate::{ input::{CrateName, CrateOrigin, LangCrateOrigin}, - Change, CrateDisplayName, CrateGraph, CrateId, Dependency, Edition, Env, FileId, FilePosition, - FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacros, ReleaseChannel, - SourceDatabaseExt, SourceRoot, SourceRootId, + Change, CrateDisplayName, CrateGraph, CrateId, Dependency, DependencyKind, Edition, Env, + FileId, FilePosition, FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, + ProcMacros, ReleaseChannel, SourceDatabaseExt, SourceRoot, SourceRootId, }; pub const WORKSPACE: SourceRootId = SourceRootId(0); @@ -237,7 +237,12 @@ impl ChangeFixture { crate_graph .add_dep( from_id, - Dependency::with_prelude(CrateName::new(&to).unwrap(), to_id, prelude), + Dependency::with_prelude( + CrateName::new(&to).unwrap(), + to_id, + prelude, + DependencyKind::Normal, + ), ) .unwrap(); } @@ -275,7 +280,14 @@ impl ChangeFixture { for krate in all_crates { crate_graph - .add_dep(krate, Dependency::new(CrateName::new("core").unwrap(), core_crate)) + .add_dep( + krate, + Dependency::new( + CrateName::new("core").unwrap(), + core_crate, + DependencyKind::Normal, + ), + ) .unwrap(); } } @@ -317,7 +329,11 @@ impl ChangeFixture { crate_graph .add_dep( krate, - Dependency::new(CrateName::new("proc_macros").unwrap(), proc_macros_crate), + Dependency::new( + CrateName::new("proc_macros").unwrap(), + proc_macros_crate, + DependencyKind::Normal, + ), ) .unwrap(); } diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index 65db5c0fc7d..e4f78321e21 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -155,6 +155,10 @@ impl CrateOrigin { pub fn is_local(&self) -> bool { matches!(self, CrateOrigin::Local { .. }) } + + pub fn is_lib(&self) -> bool { + matches!(self, CrateOrigin::Library { .. }) + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -324,6 +328,62 @@ pub struct CrateData { pub channel: Option<ReleaseChannel>, } +impl CrateData { + /// Check if [`other`] is almost equal to [`self`] ignoring `CrateOrigin` value. + pub fn eq_ignoring_origin_and_deps(&self, other: &CrateData, ignore_dev_deps: bool) -> bool { + // This method has some obscure bits. These are mostly there to be compliant with + // some patches. References to the patches are given. + if self.root_file_id != other.root_file_id { + return false; + } + + if self.display_name != other.display_name { + return false; + } + + if self.is_proc_macro != other.is_proc_macro { + return false; + } + + if self.edition != other.edition { + return false; + } + + if self.version != other.version { + return false; + } + + let mut opts = self.cfg_options.difference(&other.cfg_options); + if let Some(it) = opts.next() { + // Don't care if rust_analyzer CfgAtom is the only cfg in the difference set of self's and other's cfgs. + // https://github.com/rust-lang/rust-analyzer/blob/0840038f02daec6ba3238f05d8caa037d28701a0/crates/project-model/src/workspace.rs#L894 + if it.to_string() != "rust_analyzer" { + return false; + } + + if let Some(_) = opts.next() { + return false; + } + } + + if self.env != other.env { + return false; + } + + let slf_deps = self.dependencies.iter(); + let other_deps = other.dependencies.iter(); + + if ignore_dev_deps { + return slf_deps + .clone() + .filter(|it| it.kind != DependencyKind::Dev) + .eq(other_deps.clone().filter(|it| it.kind != DependencyKind::Dev)); + } + + slf_deps.eq(other_deps) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Edition { Edition2015, @@ -351,26 +411,43 @@ impl Env { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum DependencyKind { + Normal, + Dev, + Build, +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Dependency { pub crate_id: CrateId, pub name: CrateName, + kind: DependencyKind, prelude: bool, } impl Dependency { - pub fn new(name: CrateName, crate_id: CrateId) -> Self { - Self { name, crate_id, prelude: true } + pub fn new(name: CrateName, crate_id: CrateId, kind: DependencyKind) -> Self { + Self { name, crate_id, prelude: true, kind } } - pub fn with_prelude(name: CrateName, crate_id: CrateId, prelude: bool) -> Self { - Self { name, crate_id, prelude } + pub fn with_prelude( + name: CrateName, + crate_id: CrateId, + prelude: bool, + kind: DependencyKind, + ) -> Self { + Self { name, crate_id, prelude, kind } } /// Whether this dependency is to be added to the depending crate's extern prelude. pub fn is_prelude(&self) -> bool { self.prelude } + + pub fn kind(&self) -> DependencyKind { + self.kind + } } impl CrateGraph { @@ -574,23 +651,46 @@ impl CrateGraph { pub fn extend(&mut self, mut other: CrateGraph, proc_macros: &mut ProcMacroPaths) { let topo = other.crates_in_topological_order(); let mut id_map: FxHashMap<CrateId, CrateId> = FxHashMap::default(); - for topo in topo { let crate_data = &mut other.arena[topo]; + crate_data.dependencies.iter_mut().for_each(|dep| dep.crate_id = id_map[&dep.crate_id]); crate_data.dependencies.sort_by_key(|dep| dep.crate_id); - - let res = self.arena.iter().find_map( - |(id, data)| { - if data == crate_data { - Some(id) - } else { - None + let res = self.arena.iter().find_map(|(id, data)| { + match (&data.origin, &crate_data.origin) { + (a, b) if a == b => { + if data.eq_ignoring_origin_and_deps(&crate_data, false) { + return Some((id, false)); + } + } + (a @ CrateOrigin::Local { .. }, CrateOrigin::Library { .. }) + | (a @ CrateOrigin::Library { .. }, CrateOrigin::Local { .. }) => { + // If the origins differ, check if the two crates are equal without + // considering the dev dependencies, if they are, they most likely are in + // different loaded workspaces which may cause issues. We keep the local + // version and discard the library one as the local version may have + // dev-dependencies that we want to keep resolving. See #15656 for more + // information. + if data.eq_ignoring_origin_and_deps(&crate_data, true) { + return Some((id, if a.is_local() { false } else { true })); + } } - }, - ); - if let Some(res) = res { + (_, _) => return None, + } + + None + }); + + if let Some((res, should_update_lib_to_local)) = res { id_map.insert(topo, res); + if should_update_lib_to_local { + assert!(self.arena[res].origin.is_lib()); + assert!(crate_data.origin.is_local()); + self.arena[res].origin = crate_data.origin.clone(); + + // Move local's dev dependencies into the newly-local-formerly-lib crate. + self.arena[res].dependencies = crate_data.dependencies.clone(); + } } else { let id = self.arena.alloc(crate_data.clone()); id_map.insert(topo, id); @@ -636,9 +736,11 @@ impl CrateGraph { match (cfg_if, std) { (Some(cfg_if), Some(std)) => { self.arena[cfg_if].dependencies.clear(); - self.arena[std] - .dependencies - .push(Dependency::new(CrateName::new("cfg_if").unwrap(), cfg_if)); + self.arena[std].dependencies.push(Dependency::new( + CrateName::new("cfg_if").unwrap(), + cfg_if, + DependencyKind::Normal, + )); true } _ => false, @@ -658,6 +760,8 @@ impl ops::Index<CrateId> for CrateGraph { } impl CrateData { + /// Add a dependency to `self` without checking if the dependency + // is existent among `self.dependencies`. fn add_dep(&mut self, dep: Dependency) { self.dependencies.push(dep) } @@ -759,7 +863,7 @@ impl fmt::Display for CyclicDependenciesError { #[cfg(test)] mod tests { - use crate::CrateOrigin; + use crate::{CrateOrigin, DependencyKind}; use super::{CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId}; @@ -806,13 +910,22 @@ mod tests { None, ); assert!(graph - .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) + .add_dep( + crate1, + Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal) + ) .is_ok()); assert!(graph - .add_dep(crate2, Dependency::new(CrateName::new("crate3").unwrap(), crate3)) + .add_dep( + crate2, + Dependency::new(CrateName::new("crate3").unwrap(), crate3, DependencyKind::Normal) + ) .is_ok()); assert!(graph - .add_dep(crate3, Dependency::new(CrateName::new("crate1").unwrap(), crate1)) + .add_dep( + crate3, + Dependency::new(CrateName::new("crate1").unwrap(), crate1, DependencyKind::Normal) + ) .is_err()); } @@ -846,10 +959,16 @@ mod tests { None, ); assert!(graph - .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) + .add_dep( + crate1, + Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal) + ) .is_ok()); assert!(graph - .add_dep(crate2, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) + .add_dep( + crate2, + Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal) + ) .is_err()); } @@ -896,10 +1015,16 @@ mod tests { None, ); assert!(graph - .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) + .add_dep( + crate1, + Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal) + ) .is_ok()); assert!(graph - .add_dep(crate2, Dependency::new(CrateName::new("crate3").unwrap(), crate3)) + .add_dep( + crate2, + Dependency::new(CrateName::new("crate3").unwrap(), crate3, DependencyKind::Normal) + ) .is_ok()); } @@ -935,12 +1060,20 @@ mod tests { assert!(graph .add_dep( crate1, - Dependency::new(CrateName::normalize_dashes("crate-name-with-dashes"), crate2) + Dependency::new( + CrateName::normalize_dashes("crate-name-with-dashes"), + crate2, + DependencyKind::Normal + ) ) .is_ok()); assert_eq!( graph[crate1].dependencies, - vec![Dependency::new(CrateName::new("crate_name_with_dashes").unwrap(), crate2)] + vec![Dependency::new( + CrateName::new("crate_name_with_dashes").unwrap(), + crate2, + DependencyKind::Normal + )] ); } } diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index c5c4afa30f7..40cfab88afd 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -12,6 +12,7 @@ use rustc_hash::FxHashSet; use syntax::{ast, Parse, SourceFile, TextRange, TextSize}; use triomphe::Arc; +pub use crate::input::DependencyKind; pub use crate::{ change::Change, input::{ diff --git a/src/tools/rust-analyzer/crates/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs index 0aeb0b05052..8bbe5e2a8c2 100644 --- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs +++ b/src/tools/rust-analyzer/crates/cfg/src/lib.rs @@ -58,6 +58,13 @@ impl CfgOptions { self.enabled.insert(CfgAtom::KeyValue { key, value }); } + pub fn difference<'a>( + &'a self, + other: &'a CfgOptions, + ) -> impl Iterator<Item = &'a CfgAtom> + 'a { + self.enabled.difference(&other.enabled) + } + pub fn apply_diff(&mut self, diff: CfgDiff) { for atom in diff.enable { self.enabled.insert(atom); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs index 460a908b6db..4c1b8f306c5 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs @@ -183,15 +183,6 @@ impl DefMap { shadow: BuiltinShadowMode, expected_macro_subns: Option<MacroSubNs>, ) -> ResolvePathResult { - let graph = db.crate_graph(); - let _cx = stdx::panic_context::enter(format!( - "DefMap {:?} crate_name={:?} block={:?} path={}", - self.krate, - graph[self.krate].display_name, - self.block, - path.display(db.upcast()) - )); - let mut segments = path.segments().iter().enumerate(); let mut curr_per_ns = match path.kind { PathKind::DollarCrate(krate) => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml index f2d2451511f..bbcb76a43ff 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml @@ -23,10 +23,10 @@ oorandom = "11.1.3" tracing.workspace = true rustc-hash = "1.1.0" scoped-tls = "1.0.0" -chalk-solve = { version = "0.94.0", default-features = false } -chalk-ir = "0.94.0" -chalk-recursive = { version = "0.94.0", default-features = false } -chalk-derive = "0.94.0" +chalk-solve = { version = "0.95.0", default-features = false } +chalk-ir = "0.95.0" +chalk-recursive = { version = "0.95.0", default-features = false } +chalk-derive = "0.95.0" la-arena.workspace = true once_cell = "1.17.0" triomphe.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 0a68a9f3b58..ac39bdf5bf5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -43,7 +43,7 @@ where } impl<T: HasInterner<Interner = Interner>> Canonicalized<T> { - pub(super) fn apply_solution( + pub(crate) fn apply_solution( &self, ctx: &mut InferenceTable<'_>, solution: Canonical<Substitution>, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index c8a85b4a9ff..04005311b67 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -1097,10 +1097,25 @@ impl<'a> TyLoweringContext<'a> { binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), ); if let Some(type_ref) = &binding.type_ref { - let ty = self.lower_ty(type_ref); - let alias_eq = - AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty }; - predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq))); + if let (TypeRef::ImplTrait(bounds), ImplTraitLoweringState::Disallowed) = + (type_ref, &self.impl_trait_mode) + { + for bound in bounds { + predicates.extend( + self.lower_type_bound( + bound, + TyKind::Alias(AliasTy::Projection(projection_ty.clone())) + .intern(Interner), + false, + ), + ); + } + } else { + let ty = self.lower_ty(type_ref); + let alias_eq = + AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty }; + predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq))); + } } for bound in binding.bounds.iter() { predicates.extend(self.lower_type_bound( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 87c93283361..732643566a2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -27,8 +27,9 @@ use crate::{ primitive::{FloatTy, IntTy, UintTy}, static_lifetime, to_chalk_trait_id, utils::all_super_traits, - AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, InEnvironment, - Interner, Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, + AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, Goal, Guidance, + InEnvironment, Interner, Scalar, Solution, Substitution, TraitEnvironment, TraitRef, + TraitRefExt, Ty, TyBuilder, TyExt, }; /// This is used as a key for indexing impls. @@ -1478,26 +1479,52 @@ fn is_valid_fn_candidate( // We need to consider the bounds on the impl to distinguish functions of the same name // for a type. let predicates = db.generic_predicates(impl_id.into()); - let valid = predicates - .iter() - .map(|predicate| { - let (p, b) = predicate - .clone() - .substitute(Interner, &impl_subst) - // Skipping the inner binders is ok, as we don't handle quantified where - // clauses yet. - .into_value_and_skipped_binders(); - stdx::always!(b.len(Interner) == 0); - p - }) - // It's ok to get ambiguity here, as we may not have enough information to prove - // obligations. We'll check if the user is calling the selected method properly - // later anyway. - .all(|p| table.try_obligation(p.cast(Interner)).is_some()); - match valid { - true => IsValidCandidate::Yes, - false => IsValidCandidate::No, + let goals = predicates.iter().map(|p| { + let (p, b) = p + .clone() + .substitute(Interner, &impl_subst) + // Skipping the inner binders is ok, as we don't handle quantified where + // clauses yet. + .into_value_and_skipped_binders(); + stdx::always!(b.len(Interner) == 0); + + p.cast::<Goal>(Interner) + }); + + for goal in goals.clone() { + let in_env = InEnvironment::new(&table.trait_env.env, goal); + let canonicalized = table.canonicalize(in_env); + let solution = table.db.trait_solve( + table.trait_env.krate, + table.trait_env.block, + canonicalized.value.clone(), + ); + + match solution { + Some(Solution::Unique(canonical_subst)) => { + canonicalized.apply_solution( + table, + Canonical { + binders: canonical_subst.binders, + value: canonical_subst.value.subst, + }, + ); + } + Some(Solution::Ambig(Guidance::Definite(substs))) => { + canonicalized.apply_solution(table, substs); + } + Some(_) => (), + None => return IsValidCandidate::No, + } } + + for goal in goals { + if table.try_obligation(goal).is_none() { + return IsValidCandidate::No; + } + } + + IsValidCandidate::Yes } else { // For `ItemContainerId::TraitId`, we check if `self_ty` implements the trait in // `iterate_trait_method_candidates()`. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 48dd9540329..003ae60e8e5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -2598,6 +2598,34 @@ fn test<T: Trait>() { } #[test] +fn associated_type_in_type_bound() { + check_types( + r#" +//- minicore: deref +fn fb(f: Foo<&u8>) { + f.foobar(); + //^^^^^^^^^^ u8 +} +trait Bar { + fn bar(&self) -> u8; +} +impl Bar for u8 { + fn bar(&self) -> u8 { *self } +} + +struct Foo<F> { + foo: F, +} +impl<F: core::ops::Deref<Target = impl Bar>> Foo<F> { + fn foobar(&self) -> u8 { + self.foo.deref().bar() + } +} +"#, + ) +} + +#[test] fn dyn_trait_through_chalk() { check_types( r#" diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index bdc11aa3561..1bfbf7212bf 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -667,21 +667,21 @@ impl Module { let items = &db.trait_data(trait_.into()).items; let required_items = items.iter().filter(|&(_, assoc)| match *assoc { AssocItemId::FunctionId(it) => !db.function_data(it).has_body(), - AssocItemId::ConstId(_) => true, + AssocItemId::ConstId(id) => Const::from(id).value(db).is_none(), AssocItemId::TypeAliasId(it) => db.type_alias_data(it).type_ref.is_none(), }); - impl_assoc_items_scratch.extend(db.impl_data(impl_def.id).items.iter().map( + impl_assoc_items_scratch.extend(db.impl_data(impl_def.id).items.iter().filter_map( |&item| { - ( + Some(( item, match item { AssocItemId::FunctionId(it) => db.function_data(it).name.clone(), AssocItemId::ConstId(it) => { - db.const_data(it).name.as_ref().unwrap().clone() + db.const_data(it).name.as_ref()?.clone() } AssocItemId::TypeAliasId(it) => db.type_alias_data(it).name.clone(), }, - ) + )) }, )); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs index b7d57f02be5..f864ee50c81 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs @@ -55,7 +55,7 @@ pub(crate) fn toggle_ignore(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio } fn has_ignore_attribute(fn_def: &ast::Fn) -> Option<ast::Attr> { - fn_def.attrs().find(|attr| attr.path().map(|it| it.syntax().text() == "ignore") == Some(true)) + fn_def.attrs().find(|attr| attr.path().is_some_and(|it| it.syntax().text() == "ignore")) } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs index 0bf1782a489..0876246e90b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs @@ -91,7 +91,7 @@ fn add_import( ) { if let Some(path_segment) = qualifier.segment() { // for `<i32 as std::ops::Add>` - let path_type = path_segment.syntax().children().filter_map(ast::PathType::cast).last(); + let path_type = path_segment.qualifying_trait(); let import = match path_type { Some(it) => { if let Some(path) = it.path() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs index c5bbb7f8d75..5bcc867fe18 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs @@ -1095,4 +1095,81 @@ fn test(s: S<Unknown>) { "#]], ); } + + #[test] + fn assoc_impl_1() { + check( + r#" +//- minicore: deref +fn main() { + let foo: Foo<&u8> = Foo::new(&42_u8); + foo.$0 +} + +trait Bar { + fn bar(&self); +} + +impl Bar for u8 { + fn bar(&self) {} +} + +struct Foo<F> { + foo: F, +} + +impl<F> Foo<F> { + fn new(foo: F) -> Foo<F> { + Foo { foo } + } +} + +impl<F: core::ops::Deref<Target = impl Bar>> Foo<F> { + fn foobar(&self) { + self.foo.deref().bar() + } +} +"#, + expect![[r#" + fd foo &u8 + me foobar() fn(&self) + "#]], + ); + } + + #[test] + fn assoc_impl_2() { + check( + r#" +//- minicore: deref +fn main() { + let foo: Foo<&u8> = Foo::new(&42_u8); + foo.$0 +} + +trait Bar { + fn bar(&self); +} + +struct Foo<F> { + foo: F, +} + +impl<F> Foo<F> { + fn new(foo: F) -> Foo<F> { + Foo { foo } + } +} + +impl<B: Bar, F: core::ops::Deref<Target = B>> Foo<F> { + fn foobar(&self) { + self.foo.deref().bar() + } +} +"#, + expect![[r#" + fd foo &u8 + "#]], + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs index ed74ef7b667..99b895eed4d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs @@ -26,6 +26,10 @@ use crate::{ pub struct CompletionItem { /// Label in the completion pop up which identifies completion. pub label: SmolStr, + /// Additional label details in the completion pop up that are + /// displayed and aligned on the right side after the label. + pub label_detail: Option<SmolStr>, + /// Range of identifier that is being completed. /// /// It should be used primarily for UI, but we also use this to convert @@ -425,13 +429,14 @@ impl Builder { pub(crate) fn build(self, db: &RootDatabase) -> CompletionItem { let _p = profile::span("item::Builder::build"); - let mut label = self.label; + let label = self.label; + let mut label_detail = None; let mut lookup = self.lookup.unwrap_or_else(|| label.clone()); let insert_text = self.insert_text.unwrap_or_else(|| label.to_string()); if !self.doc_aliases.is_empty() { let doc_aliases = self.doc_aliases.iter().join(", "); - label = SmolStr::from(format!("{label} (alias {doc_aliases})")); + label_detail.replace(SmolStr::from(format!(" (alias {doc_aliases})"))); let lookup_doc_aliases = self .doc_aliases .iter() @@ -454,10 +459,17 @@ impl Builder { if let [import_edit] = &*self.imports_to_add { // snippets can have multiple imports, but normal completions only have up to one if let Some(original_path) = import_edit.original_path.as_ref() { - label = SmolStr::from(format!("{label} (use {})", original_path.display(db))); + label_detail.replace(SmolStr::from(format!( + "{} (use {})", + label_detail.as_deref().unwrap_or_default(), + original_path.display(db) + ))); } } else if let Some(trait_name) = self.trait_name { - label = SmolStr::from(format!("{label} (as {trait_name})")); + label_detail.replace(SmolStr::from(format!( + "{} (as {trait_name})", + label_detail.as_deref().unwrap_or_default(), + ))); } let text_edit = match self.text_edit { @@ -479,6 +491,7 @@ impl Builder { CompletionItem { source_range: self.source_range, label, + label_detail, text_edit, is_snippet: self.is_snippet, detail: self.detail, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index dfe8fe7e2f7..00a9081985b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -557,7 +557,11 @@ mod tests { let tag = it.kind.tag(); let relevance = display_relevance(it.relevance); - items.push(format!("{tag} {} {relevance}\n", it.label)); + items.push(format!( + "{tag} {}{} {relevance}\n", + it.label, + it.label_detail.clone().unwrap_or_default(), + )); if let Some((label, _indel, relevance)) = it.ref_match() { let relevance = display_relevance(relevance); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs index 9db8e972dd4..f28afacc586 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs @@ -150,16 +150,29 @@ fn render_completion_list(completions: Vec<CompletionItem>) -> String { fn monospace_width(s: &str) -> usize { s.chars().count() } - let label_width = - completions.iter().map(|it| monospace_width(&it.label)).max().unwrap_or_default().min(22); + let label_width = completions + .iter() + .map(|it| { + monospace_width(&it.label) + + monospace_width(it.label_detail.as_deref().unwrap_or_default()) + }) + .max() + .unwrap_or_default() + .min(22); completions .into_iter() .map(|it| { let tag = it.kind.tag(); let var_name = format!("{tag} {}", it.label); let mut buf = var_name; + if let Some(ref label_detail) = it.label_detail { + format_to!(buf, "{label_detail}"); + } if let Some(detail) = it.detail { - let width = label_width.saturating_sub(monospace_width(&it.label)); + let width = label_width.saturating_sub( + monospace_width(&it.label) + + monospace_width(&it.label_detail.unwrap_or_default()), + ); format_to!(buf, "{:width$} {}", "", detail, width = width); } if it.deprecated { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs index 40d0b6fdd4b..51923797ac9 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs @@ -36,6 +36,19 @@ mod tests { use crate::tests::check_diagnostics; #[test] + fn trait_with_default_value() { + check_diagnostics( + r#" +trait Marker { + const FLAG: bool = false; +} +struct Foo; +impl Marker for Foo {} + "#, + ) + } + + #[test] fn simple() { check_diagnostics( r#" diff --git a/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs b/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs index 3d89599c583..9b2ff070c74 100644 --- a/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs +++ b/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs @@ -108,7 +108,7 @@ fn try_extend_selection( let node = shallowest_node(&node); - if node.parent().map(|n| list_kinds.contains(&n.kind())) == Some(true) { + if node.parent().is_some_and(|n| list_kinds.contains(&n.kind())) { if let Some(range) = extend_list_item(&node) { return Some(range); } diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index 46a0464e9e6..a7f5ae92a4c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -43,7 +43,7 @@ pub struct HighlightRelatedConfig { // // . if on an identifier, highlights all references to that identifier in the current file // .. additionally, if the identifier is a trait in a where clause, type parameter trait bound or use item, highlights all references to that trait's assoc items in the corresponding scope -// . if on an `async` or `await token, highlights all yield points for that async context +// . if on an `async` or `await` token, highlights all yield points for that async context // . if on a `return` or `fn` keyword, `?` character or `->` return type arrow, highlights all exit points for that context // . if on a `break`, `loop`, `while` or `for` token, highlights all break points for that loop or block context // . if on a `move` or `|` token that belongs to a closure, highlights all captures of the closure. diff --git a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs index 80897f7478c..931eba11576 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs @@ -49,7 +49,7 @@ //! user explores them belongs to that extension (it's totally valid to change //! rust-project.json over time via configuration request!) -use base_db::{CrateDisplayName, CrateId, CrateName, Dependency, Edition}; +use base_db::{CrateDisplayName, CrateId, CrateName, Dependency, DependencyKind, Edition}; use la_arena::RawIdx; use paths::{AbsPath, AbsPathBuf}; use rustc_hash::FxHashMap; @@ -135,6 +135,7 @@ impl ProjectJson { Dependency::new( dep_data.name, CrateId::from_raw(RawIdx::from(dep_data.krate as u32)), + DependencyKind::Normal, ) }) .collect::<Vec<_>>(), diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs index 7815b9dda77..98f3063bb98 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs @@ -249,3 +249,55 @@ fn crate_graph_dedup() { crate_graph.extend(regex_crate_graph, &mut regex_proc_macros); assert_eq!(crate_graph.iter().count(), 118); } + +#[test] +fn test_deduplicate_origin_dev() { + let path_map = &mut Default::default(); + let (mut crate_graph, _proc_macros) = + load_cargo_with_sysroot(path_map, "deduplication_crate_graph_A.json"); + crate_graph.sort_deps(); + let (crate_graph_1, mut _proc_macros_2) = + load_cargo_with_sysroot(path_map, "deduplication_crate_graph_B.json"); + + crate_graph.extend(crate_graph_1, &mut _proc_macros_2); + + let mut crates_named_p2 = vec![]; + for id in crate_graph.iter() { + let krate = &crate_graph[id]; + if let Some(name) = krate.display_name.as_ref() { + if name.to_string() == "p2" { + crates_named_p2.push(krate); + } + } + } + + assert!(crates_named_p2.len() == 1); + let p2 = crates_named_p2[0]; + assert!(p2.origin.is_local()); +} + +#[test] +fn test_deduplicate_origin_dev_rev() { + let path_map = &mut Default::default(); + let (mut crate_graph, _proc_macros) = + load_cargo_with_sysroot(path_map, "deduplication_crate_graph_B.json"); + crate_graph.sort_deps(); + let (crate_graph_1, mut _proc_macros_2) = + load_cargo_with_sysroot(path_map, "deduplication_crate_graph_A.json"); + + crate_graph.extend(crate_graph_1, &mut _proc_macros_2); + + let mut crates_named_p2 = vec![]; + for id in crate_graph.iter() { + let krate = &crate_graph[id]; + if let Some(name) = krate.display_name.as_ref() { + if name.to_string() == "p2" { + crates_named_p2.push(krate); + } + } + } + + assert!(crates_named_p2.len() == 1); + let p2 = crates_named_p2[0]; + assert!(p2.origin.is_local()); +} diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index e0209ca15a5..9333570354a 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -6,8 +6,8 @@ use std::{collections::VecDeque, fmt, fs, iter, process::Command, str::FromStr, use anyhow::{format_err, Context}; use base_db::{ - CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env, - FileId, LangCrateOrigin, ProcMacroPaths, ReleaseChannel, TargetLayoutLoadResult, + CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, DependencyKind, + Edition, Env, FileId, LangCrateOrigin, ProcMacroPaths, ReleaseChannel, TargetLayoutLoadResult, }; use cfg::{CfgDiff, CfgOptions}; use paths::{AbsPath, AbsPathBuf}; @@ -834,7 +834,7 @@ fn project_json_to_crate_graph( for dep in &krate.deps { if let Some(&to) = crates.get(&dep.crate_id) { - add_dep(crate_graph, from, dep.name.clone(), to) + add_dep(crate_graph, from, dep.name.clone(), to, dep.kind().to_owned()) } } } @@ -979,7 +979,7 @@ fn cargo_to_crate_graph( // cargo metadata does not do any normalization, // so we do it ourselves currently let name = CrateName::normalize_dashes(&name); - add_dep(crate_graph, from, name, to); + add_dep(crate_graph, from, name, to, DependencyKind::Normal); } } } @@ -999,7 +999,17 @@ fn cargo_to_crate_graph( continue; } - add_dep(crate_graph, from, name.clone(), to) + add_dep( + crate_graph, + from, + name.clone(), + to, + match dep.kind { + DepKind::Normal => DependencyKind::Normal, + DepKind::Dev => DependencyKind::Dev, + DepKind::Build => DependencyKind::Build, + }, + ) } } } @@ -1187,7 +1197,17 @@ fn handle_rustc_crates( let name = CrateName::new(&dep.name).unwrap(); if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() { - add_dep(crate_graph, from, name.clone(), to); + add_dep( + crate_graph, + from, + name.clone(), + to, + match dep.kind { + DepKind::Normal => DependencyKind::Normal, + DepKind::Dev => DependencyKind::Dev, + DepKind::Build => DependencyKind::Build, + }, + ); } } } @@ -1209,7 +1229,7 @@ fn handle_rustc_crates( // `rust_analyzer` thinks that it should use the one from the `rustc_source` // instead of the one from `crates.io` if !crate_graph[*from].dependencies.iter().any(|d| d.name == name) { - add_dep(crate_graph, *from, name.clone(), to); + add_dep(crate_graph, *from, name.clone(), to, DependencyKind::Normal); } } } @@ -1308,7 +1328,14 @@ impl SysrootPublicDeps { /// Makes `from` depend on the public sysroot crates. fn add_to_crate_graph(&self, crate_graph: &mut CrateGraph, from: CrateId) { for (name, krate, prelude) in &self.deps { - add_dep_with_prelude(crate_graph, from, name.clone(), *krate, *prelude); + add_dep_with_prelude( + crate_graph, + from, + name.clone(), + *krate, + *prelude, + DependencyKind::Normal, + ); } } } @@ -1363,7 +1390,7 @@ fn sysroot_to_crate_graph( for &to in sysroot[from].deps.iter() { let name = CrateName::new(&sysroot[to].name).unwrap(); if let (Some(&from), Some(&to)) = (sysroot_crates.get(&from), sysroot_crates.get(&to)) { - add_dep(crate_graph, from, name, to); + add_dep(crate_graph, from, name, to, DependencyKind::Normal); } } } @@ -1442,8 +1469,14 @@ fn handle_hack_cargo_workspace( .collect() } -fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) { - add_dep_inner(graph, from, Dependency::new(name, to)) +fn add_dep( + graph: &mut CrateGraph, + from: CrateId, + name: CrateName, + to: CrateId, + kind: DependencyKind, +) { + add_dep_inner(graph, from, Dependency::new(name, to, kind)) } fn add_dep_with_prelude( @@ -1452,12 +1485,20 @@ fn add_dep_with_prelude( name: CrateName, to: CrateId, prelude: bool, + kind: DependencyKind, ) { - add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude)) + add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude, kind)) } fn add_proc_macro_dep(crate_graph: &mut CrateGraph, from: CrateId, to: CrateId, prelude: bool) { - add_dep_with_prelude(crate_graph, from, CrateName::new("proc_macro").unwrap(), to, prelude); + add_dep_with_prelude( + crate_graph, + from, + CrateName::new("proc_macro").unwrap(), + to, + prelude, + DependencyKind::Normal, + ); } fn add_dep_inner(graph: &mut CrateGraph, from: CrateId, dep: Dependency) { diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_A.json b/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_A.json new file mode 100644 index 00000000000..b0fb5845cef --- /dev/null +++ b/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_A.json @@ -0,0 +1,140 @@ +{ + "packages": [ + { + "name": "p1", + "version": "0.1.0", + "id": "p1 0.1.0 (path+file:///example_project/p1)", + "license": null, + "license_file": null, + "description": null, + "source": null, + "dependencies": [ + { + "name": "p2", + "source": null, + "req": "*", + "kind": null, + "rename": null, + "optional": false, + "uses_default_features": true, + "features": [], + "target": null, + "registry": null, + "path": "$ROOT$example_project/p2" + } + ], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "p1", + "src_path": "$ROOT$example_project/p1/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$example_project/p1/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [], + "categories": [], + "keywords": [], + "readme": null, + "repository": null, + "homepage": null, + "documentation": null, + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": null + }, + { + "name": "p2", + "version": "0.1.0", + "id": "p2 0.1.0 (path+file:///example_project/p2)", + "license": null, + "license_file": null, + "description": null, + "source": null, + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "p2", + "src_path": "$ROOT$example_project/p2/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$example_project/p2/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [], + "categories": [], + "keywords": [], + "readme": null, + "repository": null, + "homepage": null, + "documentation": null, + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": null + } + ], + "workspace_members": [ + "p1 0.1.0 (path+file:///example_project/p1)" + ], + "workspace_default_members": [ + "p1 0.1.0 (path+file:///example_project/p1)" + ], + "resolve": { + "nodes": [ + { + "id": "p1 0.1.0 (path+file:///example_project/p1)", + "dependencies": [ + "p2 0.1.0 (path+file:///example_project/p2)" + ], + "deps": [ + { + "name": "p2", + "pkg": "p2 0.1.0 (path+file:///example_project/p2)", + "dep_kinds": [ + { + "kind": null, + "target": null + } + ] + } + ], + "features": [] + }, + { + "id": "p2 0.1.0 (path+file:///example_project/p2)", + "dependencies": [], + "deps": [], + "features": [] + } + ], + "root": "p1 0.1.0 (path+file:///example_project/p1)" + }, + "target_directory": "$ROOT$example_project/p1/target", + "version": 1, + "workspace_root": "$ROOT$example_project/p1", + "metadata": null +} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_B.json b/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_B.json new file mode 100644 index 00000000000..b5d1e16e62e --- /dev/null +++ b/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_B.json @@ -0,0 +1,66 @@ +{ + "packages": [ + { + "name": "p2", + "version": "0.1.0", + "id": "p2 0.1.0 (path+file:///example_project/p2)", + "license": null, + "license_file": null, + "description": null, + "source": null, + "dependencies": [], + "targets": [ + { + "kind": [ + "lib" + ], + "crate_types": [ + "lib" + ], + "name": "p2", + "src_path": "$ROOT$example_project/p2/src/lib.rs", + "edition": "2021", + "doc": true, + "doctest": true, + "test": true + } + ], + "features": {}, + "manifest_path": "$ROOT$example_project/p2/Cargo.toml", + "metadata": null, + "publish": null, + "authors": [], + "categories": [], + "keywords": [], + "readme": null, + "repository": null, + "homepage": null, + "documentation": null, + "edition": "2021", + "links": null, + "default_run": null, + "rust_version": null + } + ], + "workspace_members": [ + "p2 0.1.0 (path+file:///example_project/p2)" + ], + "workspace_default_members": [ + "p2 0.1.0 (path+file:///example_project/p2)" + ], + "resolve": { + "nodes": [ + { + "id": "p2 0.1.0 (path+file:///example_project/p2)", + "dependencies": [], + "deps": [], + "features": [] + } + ], + "root": "p2 0.1.0 (path+file:///example_project/p2)" + }, + "target_directory": "$ROOT$example_project/p2/target", + "version": 1, + "workspace_root": "$ROOT$example_project/p2", + "metadata": null +} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt index 727d39a3077..e98f016ca7d 100644 --- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt +++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt @@ -48,6 +48,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -112,6 +113,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -119,6 +121,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -183,6 +186,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -190,6 +194,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -254,6 +259,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -261,6 +267,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt index 727d39a3077..e98f016ca7d 100644 --- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt +++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt @@ -48,6 +48,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -112,6 +113,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -119,6 +121,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -183,6 +186,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -190,6 +194,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -254,6 +259,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -261,6 +267,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt index 89728babd82..7ecd53572e2 100644 --- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt +++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt @@ -47,6 +47,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -110,6 +111,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -117,6 +119,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -180,6 +183,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -187,6 +191,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], @@ -250,6 +255,7 @@ name: CrateName( "hello_world", ), + kind: Normal, prelude: true, }, Dependency { @@ -257,6 +263,7 @@ name: CrateName( "libc", ), + kind: Normal, prelude: true, }, ], diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt index b7bf6cb2774..581a6afc148 100644 --- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt +++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt @@ -28,6 +28,7 @@ name: CrateName( "core", ), + kind: Normal, prelude: true, }, ], @@ -168,6 +169,7 @@ name: CrateName( "std", ), + kind: Normal, prelude: true, }, Dependency { @@ -175,6 +177,7 @@ name: CrateName( "core", ), + kind: Normal, prelude: true, }, ], @@ -249,6 +252,7 @@ name: CrateName( "alloc", ), + kind: Normal, prelude: true, }, Dependency { @@ -256,6 +260,7 @@ name: CrateName( "panic_unwind", ), + kind: Normal, prelude: true, }, Dependency { @@ -263,6 +268,7 @@ name: CrateName( "panic_abort", ), + kind: Normal, prelude: true, }, Dependency { @@ -270,6 +276,7 @@ name: CrateName( "core", ), + kind: Normal, prelude: true, }, Dependency { @@ -277,6 +284,7 @@ name: CrateName( "profiler_builtins", ), + kind: Normal, prelude: true, }, Dependency { @@ -284,6 +292,7 @@ name: CrateName( "unwind", ), + kind: Normal, prelude: true, }, Dependency { @@ -291,6 +300,7 @@ name: CrateName( "std_detect", ), + kind: Normal, prelude: true, }, Dependency { @@ -298,6 +308,7 @@ name: CrateName( "test", ), + kind: Normal, prelude: true, }, ], @@ -438,6 +449,7 @@ name: CrateName( "core", ), + kind: Normal, prelude: true, }, Dependency { @@ -445,6 +457,7 @@ name: CrateName( "alloc", ), + kind: Normal, prelude: true, }, Dependency { @@ -452,6 +465,7 @@ name: CrateName( "std", ), + kind: Normal, prelude: true, }, Dependency { @@ -459,6 +473,7 @@ name: CrateName( "test", ), + kind: Normal, prelude: false, }, Dependency { @@ -466,6 +481,7 @@ name: CrateName( "proc_macro", ), + kind: Normal, prelude: false, }, ], diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs index aca91570f7c..fb366fd5cc4 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs @@ -1,7 +1,7 @@ //! Conversion of rust-analyzer specific types to lsp_types equivalents. use std::{ iter::once, - path, + mem, path, sync::atomic::{AtomicU32, Ordering}, }; @@ -301,9 +301,11 @@ fn completion_item( if config.completion_label_details_support() { lsp_item.label_details = Some(lsp_types::CompletionItemLabelDetails { - detail: None, + detail: item.label_detail.as_ref().map(ToString::to_string), description: lsp_item.detail.clone(), }); + } else if let Some(label_detail) = item.label_detail { + lsp_item.label.push_str(label_detail.as_str()); } set_score(&mut lsp_item, max_relevance, item.relevance); @@ -1123,13 +1125,20 @@ pub(crate) fn snippet_text_document_ops( pub(crate) fn snippet_workspace_edit( snap: &GlobalStateSnapshot, - source_change: SourceChange, + mut source_change: SourceChange, ) -> Cancellable<lsp_ext::SnippetWorkspaceEdit> { let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new(); - for op in source_change.file_system_edits { - let ops = snippet_text_document_ops(snap, op)?; - document_changes.extend_from_slice(&ops); + for op in &mut source_change.file_system_edits { + if let FileSystemEdit::CreateFile { dst, initial_contents } = op { + // replace with a placeholder to avoid cloneing the edit + let op = FileSystemEdit::CreateFile { + dst: dst.clone(), + initial_contents: mem::take(initial_contents), + }; + let ops = snippet_text_document_ops(snap, op)?; + document_changes.extend_from_slice(&ops); + } } for (file_id, (edit, snippet_edit)) in source_change.source_file_edits { let edit = snippet_text_document_edit( @@ -1141,6 +1150,12 @@ pub(crate) fn snippet_workspace_edit( )?; document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit)); } + for op in source_change.file_system_edits { + if !matches!(op, FileSystemEdit::CreateFile { .. }) { + let ops = snippet_text_document_ops(snap, op)?; + document_changes.extend_from_slice(&ops); + } + } let mut workspace_edit = lsp_ext::SnippetWorkspaceEdit { changes: None, document_changes: Some(document_changes), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs index d5991429899..5cd02f78404 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs @@ -984,6 +984,11 @@ fn main() {} //- /src/old_file.rs //- /src/old_folder/mod.rs +mod nested; + +//- /src/old_folder/nested.rs +struct foo; +use crate::old_folder::nested::foo as bar; //- /src/from_mod/mod.rs @@ -1080,6 +1085,27 @@ fn main() {} "newText": "new_folder" } ] + }, + { + "textDocument": { + "uri": format!("file://{}", tmp_dir_path.join("src").join("old_folder").join("nested.rs").to_str().unwrap().to_string().replace("C:\\", "/c:/").replace('\\', "/")), + "version": null + }, + "edits": [ + { + "range": { + "start": { + "line": 1, + "character": 11 + }, + "end": { + "line": 1, + "character": 21 + } + }, + "newText": "new_folder" + } + ] } ] }), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs index 56b5fcef3c2..45adbf5c573 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs @@ -316,7 +316,7 @@ fn check_trailing_ws(path: &Path, text: &str) { return; } for (line_number, line) in text.lines().enumerate() { - if line.chars().last().map(char::is_whitespace) == Some(true) { + if line.chars().last().is_some_and(char::is_whitespace) { panic!("Trailing whitespace in {} at line {}", path.display(), line_number + 1) } } diff --git a/src/tools/rust-analyzer/crates/rustc-dependencies/Cargo.toml b/src/tools/rust-analyzer/crates/rustc-dependencies/Cargo.toml index ba36fb0b044..cd7ec305936 100644 --- a/src/tools/rust-analyzer/crates/rustc-dependencies/Cargo.toml +++ b/src/tools/rust-analyzer/crates/rustc-dependencies/Cargo.toml @@ -11,10 +11,10 @@ authors.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ra-ap-rustc_lexer = { version = "0.19.0" } -ra-ap-rustc_parse_format = { version = "0.14.0", default-features = false } -ra-ap-rustc_index = { version = "0.19.0", default-features = false } -ra-ap-rustc_abi = { version = "0.19.0", default-features = false } +ra-ap-rustc_lexer = { version = "0.20.0" } +ra-ap-rustc_parse_format = { version = "0.20.0", default-features = false } +ra-ap-rustc_index = { version = "0.20.0", default-features = false } +ra-ap-rustc_abi = { version = "0.20.0", default-features = false } [features] in-rust-tree = [] diff --git a/src/tools/rust-analyzer/docs/user/manual.adoc b/src/tools/rust-analyzer/docs/user/manual.adoc index 18d5ddd4d0a..9fc19a7d074 100644 --- a/src/tools/rust-analyzer/docs/user/manual.adoc +++ b/src/tools/rust-analyzer/docs/user/manual.adoc @@ -174,7 +174,7 @@ $ rustup component add rust-analyzer The `rust-analyzer` binary can be installed from the repos or AUR (Arch User Repository): -- https://www.archlinux.org/packages/community/x86_64/rust-analyzer/[`rust-analyzer`] (built from latest tagged source) +- https://www.archlinux.org/packages/extra/x86_64/rust-analyzer/[`rust-analyzer`] (built from latest tagged source) - https://aur.archlinux.org/packages/rust-analyzer-git[`rust-analyzer-git`] (latest Git version) Install it with pacman, for example: diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 265c63f3e2d..c43f2b964fd 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -498,6 +498,11 @@ "default": true, "type": "boolean" }, + "rust-analyzer.showRequestFailedErrorNotification": { + "markdownDescription": "Whether to show error notifications for failing requests.", + "default": true, + "type": "boolean" + }, "rust-analyzer.showDependenciesExplorer": { "markdownDescription": "Whether to show the dependencies view.", "default": true, diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts index 96e888402ba..c27a446b380 100644 --- a/src/tools/rust-analyzer/editors/code/src/client.ts +++ b/src/tools/rust-analyzer/editors/code/src/client.ts @@ -10,6 +10,7 @@ import { type Config, prepareVSCodeConfig } from "./config"; import { randomUUID } from "crypto"; import { sep as pathSeparator } from "path"; import { unwrapUndefinable } from "./undefinable"; +import { RaLanguageClient } from "./lang_client"; export interface Env { [name: string]: string; @@ -363,7 +364,7 @@ export async function createClient( }, }; - const client = new lc.LanguageClient( + const client = new RaLanguageClient( "rust-analyzer", "Rust Analyzer Language Server", serverOptions, diff --git a/src/tools/rust-analyzer/editors/code/src/lang_client.ts b/src/tools/rust-analyzer/editors/code/src/lang_client.ts new file mode 100644 index 00000000000..09d64efc048 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/src/lang_client.ts @@ -0,0 +1,26 @@ +import * as lc from "vscode-languageclient/node"; +import * as vscode from "vscode"; + +export class RaLanguageClient extends lc.LanguageClient { + override handleFailedRequest<T>( + type: lc.MessageSignature, + token: vscode.CancellationToken | undefined, + error: any, + defaultValue: T, + showNotification?: boolean | undefined, + ): T { + const showError = vscode.workspace + .getConfiguration("rust-analyzer") + .get("showRequestFailedErrorNotification"); + if ( + !showError && + error instanceof lc.ResponseError && + error.code === lc.ErrorCodes.InternalError + ) { + // Don't show notification for internal errors, these are emitted by r-a when a request fails. + showNotification = false; + } + + return super.handleFailedRequest(type, token, error, defaultValue, showNotification); + } +} diff --git a/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml b/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml index 8d00813b0d7..be1573913ff 100644 --- a/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml +++ b/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml @@ -14,3 +14,4 @@ crossbeam-channel = "0.5.6" [dev-dependencies] lsp-types = "=0.94" +ctrlc = "3.4.1" diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs b/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs index affab60a227..b190c0af73d 100644 --- a/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs +++ b/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs @@ -17,7 +17,7 @@ use std::{ net::{TcpListener, TcpStream, ToSocketAddrs}, }; -use crossbeam_channel::{Receiver, Sender}; +use crossbeam_channel::{Receiver, RecvTimeoutError, Sender}; pub use crate::{ error::{ExtractError, ProtocolError}, @@ -113,11 +113,62 @@ impl Connection { /// } /// ``` pub fn initialize_start(&self) -> Result<(RequestId, serde_json::Value), ProtocolError> { - loop { - break match self.receiver.recv() { - Ok(Message::Request(req)) if req.is_initialize() => Ok((req.id, req.params)), + self.initialize_start_while(|| true) + } + + /// Starts the initialization process by waiting for an initialize as described in + /// [`Self::initialize_start`] as long as `running` returns + /// `true` while the return value can be changed through a sig handler such as `CTRL + C`. + /// + /// # Example + /// + /// ```rust + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// use std::sync::Arc; + /// # use std::error::Error; + /// # use lsp_types::{ClientCapabilities, InitializeParams, ServerCapabilities}; + /// # use lsp_server::{Connection, Message, Request, RequestId, Response}; + /// # fn main() -> Result<(), Box<dyn Error + Sync + Send>> { + /// let running = Arc::new(AtomicBool::new(true)); + /// # running.store(true, Ordering::SeqCst); + /// let r = running.clone(); + /// + /// ctrlc::set_handler(move || { + /// r.store(false, Ordering::SeqCst); + /// }).expect("Error setting Ctrl-C handler"); + /// + /// let (connection, io_threads) = Connection::stdio(); + /// + /// let res = connection.initialize_start_while(|| running.load(Ordering::SeqCst)); + /// # assert!(res.is_err()); + /// + /// # Ok(()) + /// # } + /// ``` + pub fn initialize_start_while<C>( + &self, + running: C, + ) -> Result<(RequestId, serde_json::Value), ProtocolError> + where + C: Fn() -> bool, + { + while running() { + let msg = match self.receiver.recv_timeout(std::time::Duration::from_secs(1)) { + Ok(msg) => msg, + Err(RecvTimeoutError::Timeout) => { + continue; + } + Err(e) => { + return Err(ProtocolError(format!( + "expected initialize request, got error: {e}" + ))) + } + }; + + match msg { + Message::Request(req) if req.is_initialize() => return Ok((req.id, req.params)), // Respond to non-initialize requests with ServerNotInitialized - Ok(Message::Request(req)) => { + Message::Request(req) => { let resp = Response::new_err( req.id.clone(), ErrorCode::ServerNotInitialized as i32, @@ -126,15 +177,18 @@ impl Connection { self.sender.send(resp.into()).unwrap(); continue; } - Ok(Message::Notification(n)) if !n.is_exit() => { + Message::Notification(n) if !n.is_exit() => { continue; } - Ok(msg) => Err(ProtocolError(format!("expected initialize request, got {msg:?}"))), - Err(e) => { - Err(ProtocolError(format!("expected initialize request, got error: {e}"))) + msg => { + return Err(ProtocolError(format!("expected initialize request, got {msg:?}"))); } }; } + + return Err(ProtocolError(String::from( + "Initialization has been aborted during initialization", + ))); } /// Finishes the initialization process by sending an `InitializeResult` to the client @@ -156,6 +210,51 @@ impl Connection { } } + /// Finishes the initialization process as described in [`Self::initialize_finish`] as + /// long as `running` returns `true` while the return value can be changed through a sig + /// handler such as `CTRL + C`. + pub fn initialize_finish_while<C>( + &self, + initialize_id: RequestId, + initialize_result: serde_json::Value, + running: C, + ) -> Result<(), ProtocolError> + where + C: Fn() -> bool, + { + let resp = Response::new_ok(initialize_id, initialize_result); + self.sender.send(resp.into()).unwrap(); + + while running() { + let msg = match self.receiver.recv_timeout(std::time::Duration::from_secs(1)) { + Ok(msg) => msg, + Err(RecvTimeoutError::Timeout) => { + continue; + } + Err(e) => { + return Err(ProtocolError(format!( + "expected initialized notification, got error: {e}", + ))); + } + }; + + match msg { + Message::Notification(n) if n.is_initialized() => { + return Ok(()); + } + msg => { + return Err(ProtocolError(format!( + r#"expected initialized notification, got: {msg:?}"# + ))); + } + } + } + + return Err(ProtocolError(String::from( + "Initialization has been aborted during initialization", + ))); + } + /// Initialize the connection. Sends the server capabilities /// to the client and returns the serialized client capabilities /// on success. If more fine-grained initialization is required use @@ -198,6 +297,58 @@ impl Connection { Ok(params) } + /// Initialize the connection as described in [`Self::initialize`] as long as `running` returns + /// `true` while the return value can be changed through a sig handler such as `CTRL + C`. + /// + /// # Example + /// + /// ```rust + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// use std::sync::Arc; + /// # use std::error::Error; + /// # use lsp_types::ServerCapabilities; + /// # use lsp_server::{Connection, Message, Request, RequestId, Response}; + /// + /// # fn main() -> Result<(), Box<dyn Error + Sync + Send>> { + /// let running = Arc::new(AtomicBool::new(true)); + /// # running.store(true, Ordering::SeqCst); + /// let r = running.clone(); + /// + /// ctrlc::set_handler(move || { + /// r.store(false, Ordering::SeqCst); + /// }).expect("Error setting Ctrl-C handler"); + /// + /// let (connection, io_threads) = Connection::stdio(); + /// + /// let server_capabilities = serde_json::to_value(&ServerCapabilities::default()).unwrap(); + /// let initialization_params = connection.initialize_while( + /// server_capabilities, + /// || running.load(Ordering::SeqCst) + /// ); + /// + /// # assert!(initialization_params.is_err()); + /// # Ok(()) + /// # } + /// ``` + pub fn initialize_while<C>( + &self, + server_capabilities: serde_json::Value, + running: C, + ) -> Result<serde_json::Value, ProtocolError> + where + C: Fn() -> bool, + { + let (id, params) = self.initialize_start_while(&running)?; + + let initialize_data = serde_json::json!({ + "capabilities": server_capabilities, + }); + + self.initialize_finish_while(id, initialize_data, running)?; + + Ok(params) + } + /// If `req` is `Shutdown`, respond to it and return `true`, otherwise return `false` pub fn handle_shutdown(&self, req: &Request) -> Result<bool, ProtocolError> { if !req.is_shutdown() { diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index fa941e6146a..60e0e007b1d 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -1933,7 +1933,7 @@ fn rewrite_unary_op( shape: Shape, ) -> Option<String> { // For some reason, an UnOp is not spanned like BinOp! - rewrite_unary_prefix(context, ast::UnOp::to_string(op), expr, shape) + rewrite_unary_prefix(context, op.as_str(), expr, shape) } pub(crate) enum RhsAssignKind<'ast> { diff --git a/src/tools/rustfmt/src/pairs.rs b/src/tools/rustfmt/src/pairs.rs index 07c05193739..bfc2ffed383 100644 --- a/src/tools/rustfmt/src/pairs.rs +++ b/src/tools/rustfmt/src/pairs.rs @@ -339,7 +339,7 @@ impl FlattenPair for ast::Expr { if let Some(pop) = stack.pop() { match pop.kind { ast::ExprKind::Binary(op, _, ref rhs) => { - separators.push(op.node.to_string()); + separators.push(op.node.as_str()); node = rhs; } _ => unreachable!(), diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index 33f3b4b8a21..8504999b8ff 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -40,7 +40,9 @@ pub(crate) fn is_short_pattern(pat: &ast::Pat, pat_str: &str) -> bool { fn is_short_pattern_inner(pat: &ast::Pat) -> bool { match pat.kind { - ast::PatKind::Rest | ast::PatKind::Wild | ast::PatKind::Lit(_) => true, + ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Lit(_) => { + true + } ast::PatKind::Ident(_, _, ref pat) => pat.is_none(), ast::PatKind::Struct(..) | ast::PatKind::MacCall(..) @@ -193,6 +195,7 @@ impl Rewrite for Pat { None } } + PatKind::Never => None, PatKind::Range(ref lhs, ref rhs, ref end_kind) => { let infix = match end_kind.node { RangeEnd::Included(RangeSyntax::DotDotDot) => "...", diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index f36893bfb94..1f8edd7937b 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -129,7 +129,6 @@ const EXCEPTIONS_CARGO: ExceptionList = &[ const EXCEPTIONS_RUST_ANALYZER: ExceptionList = &[ // tidy-alphabetical-start ("dissimilar", "Apache-2.0"), - ("instant", "BSD-3-Clause"), ("notify", "CC0-1.0"), ("pulldown-cmark-to-cmark", "Apache-2.0"), ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0 diff --git a/tests/assembly/asm/loongarch-type.rs b/tests/assembly/asm/loongarch-type.rs index 4e296f3ade5..4aeecf92d86 100644 --- a/tests/assembly/asm/loongarch-type.rs +++ b/tests/assembly/asm/loongarch-type.rs @@ -1,4 +1,3 @@ -// min-llvm-version: 16.0 // assembly-output: emit-asm // compile-flags: --target loongarch64-unknown-linux-gnu // needs-llvm-components: loongarch @@ -42,7 +41,7 @@ extern "C" { // Hack to avoid function merging extern "Rust" { - fn dont_merge(s: &str); + fn dont_merge(s: &str); } // CHECK-LABEL: sym_fn: diff --git a/tests/assembly/x86-stack-probes.rs b/tests/assembly/x86-stack-probes.rs index c7141fb208a..64a4efc0e18 100644 --- a/tests/assembly/x86-stack-probes.rs +++ b/tests/assembly/x86-stack-probes.rs @@ -1,4 +1,3 @@ -// min-llvm-version: 16 // revisions: x86_64 i686 // assembly-output: emit-asm //[x86_64] compile-flags: --target x86_64-unknown-linux-gnu diff --git a/tests/assembly/x86_64-function-return.rs b/tests/assembly/x86_64-function-return.rs new file mode 100644 index 00000000000..0fcaca2d491 --- /dev/null +++ b/tests/assembly/x86_64-function-return.rs @@ -0,0 +1,30 @@ +// Test that the function return is (not) converted into a jump to the thunk +// when the `-Zfunction-return={keep,thunk-extern}` flag is (not) set. + +// revisions: unset keep thunk-extern keep-thunk-extern thunk-extern-keep +// assembly-output: emit-asm +// compile-flags: -O +// [keep] compile-flags: -Zfunction-return=keep +// [thunk-extern] compile-flags: -Zfunction-return=thunk-extern +// [keep-thunk-extern] compile-flags: -Zfunction-return=keep -Zfunction-return=thunk-extern +// [thunk-extern-keep] compile-flags: -Zfunction-return=thunk-extern -Zfunction-return=keep +// only-x86_64 +// ignore-x86_64-apple-darwin Symbol is called `___x86_return_thunk` (Darwin's extra underscore) +// ignore-sgx Tests incompatible with LVI mitigations + +#![crate_type = "lib"] + +// CHECK-LABEL: foo: +#[no_mangle] +pub unsafe fn foo() { + // unset: ret + // unset-NOT: jmp __x86_return_thunk + // keep: ret + // keep-NOT: jmp __x86_return_thunk + // thunk-extern: jmp __x86_return_thunk + // thunk-extern-NOT: ret + // keep-thunk-extern: jmp __x86_return_thunk + // keep-thunk-extern-NOT: ret + // thunk-extern-keep: ret + // thunk-extern-keep-NOT: jmp __x86_return_thunk +} diff --git a/tests/codegen/ascii-char.rs b/tests/codegen/ascii-char.rs index 4167becf5e9..711ffe7e1a5 100644 --- a/tests/codegen/ascii-char.rs +++ b/tests/codegen/ascii-char.rs @@ -14,7 +14,7 @@ pub fn unwrap_digit_from_remainder(v: u32) -> AsciiChar { // CHECK: %[[R:.+]] = urem i32 %v, 10 // CHECK-NEXT: %[[T:.+]] = trunc i32 %[[R]] to i8 - // CHECK-NEXT: %[[D:.+]] = or i8 %[[T]], 48 + // CHECK-NEXT: %[[D:.+]] = or{{( disjoint)?}} i8 %[[T]], 48 // CHECK-NEXT: ret i8 %[[D]] // CHECK-NOT: icmp diff --git a/tests/codegen/function-return.rs b/tests/codegen/function-return.rs new file mode 100644 index 00000000000..d832d19ac39 --- /dev/null +++ b/tests/codegen/function-return.rs @@ -0,0 +1,28 @@ +// Test that the `fn_ret_thunk_extern` function attribute is (not) emitted when +// the `-Zfunction-return={keep,thunk-extern}` flag is (not) set. + +// revisions: unset keep thunk-extern keep-thunk-extern thunk-extern-keep +// needs-llvm-components: x86 +// compile-flags: --target x86_64-unknown-linux-gnu +// [keep] compile-flags: -Zfunction-return=keep +// [thunk-extern] compile-flags: -Zfunction-return=thunk-extern +// [keep-thunk-extern] compile-flags: -Zfunction-return=keep -Zfunction-return=thunk-extern +// [thunk-extern-keep] compile-flags: -Zfunction-return=thunk-extern -Zfunction-return=keep + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +#[no_mangle] +pub fn foo() { + // CHECK: @foo() unnamed_addr #0 + + // unset-NOT: fn_ret_thunk_extern + // keep-NOT: fn_ret_thunk_extern + // thunk-extern: attributes #0 = { {{.*}}fn_ret_thunk_extern{{.*}} } + // keep-thunk-extern: attributes #0 = { {{.*}}fn_ret_thunk_extern{{.*}} } + // thunk-extern-keep-NOT: fn_ret_thunk_extern +} diff --git a/tests/codegen/issues/issue-101048.rs b/tests/codegen/issues/issue-101048.rs index efa4db93ec2..e4712cf9cb3 100644 --- a/tests/codegen/issues/issue-101048.rs +++ b/tests/codegen/issues/issue-101048.rs @@ -1,5 +1,4 @@ // compile-flags: -O -// min-llvm-version: 16 #![crate_type = "lib"] diff --git a/tests/codegen/issues/issue-101082.rs b/tests/codegen/issues/issue-101082.rs index 2cbe99942cb..58fcd75a8f2 100644 --- a/tests/codegen/issues/issue-101082.rs +++ b/tests/codegen/issues/issue-101082.rs @@ -1,5 +1,4 @@ // compile-flags: -O -// min-llvm-version: 16 // ignore-debug: the debug assertions get in the way #![crate_type = "lib"] diff --git a/tests/codegen/issues/issue-101814.rs b/tests/codegen/issues/issue-101814.rs index 13796352c02..63a8cebcb60 100644 --- a/tests/codegen/issues/issue-101814.rs +++ b/tests/codegen/issues/issue-101814.rs @@ -1,5 +1,4 @@ // compile-flags: -O -// min-llvm-version: 16 // ignore-debug: the debug assertions get in the way #![crate_type = "lib"] diff --git a/tests/codegen/issues/issue-103132.rs b/tests/codegen/issues/issue-103132.rs index cc87d7cd2b9..521d424c269 100644 --- a/tests/codegen/issues/issue-103132.rs +++ b/tests/codegen/issues/issue-103132.rs @@ -1,5 +1,4 @@ // compile-flags: -O -C overflow-checks -// min-llvm-version: 16 #![crate_type = "lib"] diff --git a/tests/codegen/issues/issue-103327.rs b/tests/codegen/issues/issue-103327.rs index cee00faccc8..021f1ca0c3a 100644 --- a/tests/codegen/issues/issue-103327.rs +++ b/tests/codegen/issues/issue-103327.rs @@ -1,5 +1,4 @@ // compile-flags: -O -// min-llvm-version: 16 #![crate_type = "lib"] diff --git a/tests/codegen/issues/issue-103840.rs b/tests/codegen/issues/issue-103840.rs index da64692d27d..f19d7031bb3 100644 --- a/tests/codegen/issues/issue-103840.rs +++ b/tests/codegen/issues/issue-103840.rs @@ -1,5 +1,4 @@ // compile-flags: -O -// min-llvm-version: 16.0 #![crate_type = "lib"] pub fn foo(t: &mut Vec<usize>) { diff --git a/tests/codegen/issues/issue-75978.rs b/tests/codegen/issues/issue-75978.rs index f335e92c3dc..abfafc35f0b 100644 --- a/tests/codegen/issues/issue-75978.rs +++ b/tests/codegen/issues/issue-75978.rs @@ -1,5 +1,4 @@ // compile-flags: -O -// min-llvm-version: 16 #![crate_type = "lib"] diff --git a/tests/codegen/issues/issue-99960.rs b/tests/codegen/issues/issue-99960.rs index e9c9367fa64..ad0315a8227 100644 --- a/tests/codegen/issues/issue-99960.rs +++ b/tests/codegen/issues/issue-99960.rs @@ -1,5 +1,4 @@ // compile-flags: -O -// min-llvm-version: 16 #![crate_type = "lib"] diff --git a/tests/codegen/sanitizer/kasan-emits-instrumentation.rs b/tests/codegen/sanitizer/kasan-emits-instrumentation.rs index 29d50d8df24..18d315c9598 100644 --- a/tests/codegen/sanitizer/kasan-emits-instrumentation.rs +++ b/tests/codegen/sanitizer/kasan-emits-instrumentation.rs @@ -6,10 +6,8 @@ //[aarch64] needs-llvm-components: aarch64 //[riscv64imac] compile-flags: --target riscv64imac-unknown-none-elf //[riscv64imac] needs-llvm-components: riscv -//[riscv64imac] min-llvm-version: 16 //[riscv64gc] compile-flags: --target riscv64gc-unknown-none-elf //[riscv64gc] needs-llvm-components: riscv -//[riscv64gc] min-llvm-version: 16 //[x86_64] compile-flags: --target x86_64-unknown-none //[x86_64] needs-llvm-components: x86 diff --git a/tests/codegen/slice-iter-fold.rs b/tests/codegen/slice-iter-fold.rs index 9391c176130..a55425cb6bb 100644 --- a/tests/codegen/slice-iter-fold.rs +++ b/tests/codegen/slice-iter-fold.rs @@ -1,6 +1,5 @@ // ignore-debug: the debug assertions get in the way // compile-flags: -O -// min-llvm-version: 16 #![crate_type = "lib"] // CHECK-LABEL: @slice_fold_to_last diff --git a/tests/codegen/stack-probes-call.rs b/tests/codegen/stack-probes-call.rs deleted file mode 100644 index a18fd41c28c..00000000000 --- a/tests/codegen/stack-probes-call.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Check the "probe-stack" attribute for targets with `StackProbeType::Call`, -// or `StackProbeType::InlineOrCall` when running on older LLVM. - -// compile-flags: -C no-prepopulate-passes -// revisions: i686 x86_64 -//[i686] compile-flags: --target i686-unknown-linux-gnu -//[i686] needs-llvm-components: x86 -//[i686] ignore-llvm-version: 16 - 99 -//[x86_64] compile-flags: --target x86_64-unknown-linux-gnu -//[x86_64] needs-llvm-components: x86 -//[x86_64] ignore-llvm-version: 16 - 99 - -#![crate_type = "rlib"] -#![feature(no_core, lang_items)] -#![no_core] - -#[lang = "sized"] -trait Sized {} - -#[no_mangle] -pub fn foo() { -// CHECK: @foo() unnamed_addr #0 -// CHECK: attributes #0 = { {{.*}}"probe-stack"="__rust_probestack"{{.*}} } -} diff --git a/tests/codegen/stack-probes-inline.rs b/tests/codegen/stack-probes-inline.rs index a6b781de531..058c363969f 100644 --- a/tests/codegen/stack-probes-inline.rs +++ b/tests/codegen/stack-probes-inline.rs @@ -13,10 +13,8 @@ //[s390x] needs-llvm-components: systemz //[i686] compile-flags: --target i686-unknown-linux-gnu //[i686] needs-llvm-components: x86 -//[i686] min-llvm-version: 16 //[x86_64] compile-flags: --target x86_64-unknown-linux-gnu //[x86_64] needs-llvm-components: x86 -//[x86_64] min-llvm-version: 16 #![crate_type = "rlib"] #![feature(no_core, lang_items)] diff --git a/tests/codegen/vec-in-place.rs b/tests/codegen/vec-in-place.rs index d68067ceb19..5cf7add836d 100644 --- a/tests/codegen/vec-in-place.rs +++ b/tests/codegen/vec-in-place.rs @@ -1,6 +1,5 @@ // ignore-debug: the debug assertions get in the way // compile-flags: -O -Z merge-functions=disabled -// min-llvm-version: 16 #![crate_type = "lib"] // Ensure that trivial casts of vec elements are O(1) diff --git a/tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.panic-abort.diff index b30deb2a4d4..11cdf9e09db 100644 --- a/tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.panic-abort.diff +++ b/tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.panic-abort.diff @@ -8,7 +8,7 @@ let mut _3: u8; scope 1 { } - scope 2 (inlined <u8 as Add>::add) { + scope 2 (inlined #[track_caller] <u8 as Add>::add) { debug self => _2; debug other => _3; let mut _4: (u8, bool); diff --git a/tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.panic-unwind.diff index 47c51196c02..181a2f287d6 100644 --- a/tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.panic-unwind.diff +++ b/tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.panic-unwind.diff @@ -8,7 +8,7 @@ let mut _3: u8; scope 1 { } - scope 2 (inlined <u8 as Add>::add) { + scope 2 (inlined #[track_caller] <u8 as Add>::add) { debug self => _2; debug other => _3; let mut _4: (u8, bool); diff --git a/tests/mir-opt/const_prop/overwrite_with_const_with_params.rs b/tests/mir-opt/const_prop/overwrite_with_const_with_params.rs new file mode 100644 index 00000000000..4cf6d7c1396 --- /dev/null +++ b/tests/mir-opt/const_prop/overwrite_with_const_with_params.rs @@ -0,0 +1,26 @@ +// unit-test: ConstProp +// compile-flags: -O + +// Regression test for https://github.com/rust-lang/rust/issues/118328 + +#![allow(unused_assignments)] + +struct SizeOfConst<T>(std::marker::PhantomData<T>); +impl<T> SizeOfConst<T> { + const SIZE: usize = std::mem::size_of::<T>(); +} + +// EMIT_MIR overwrite_with_const_with_params.size_of.ConstProp.diff +fn size_of<T>() -> usize { + // CHECK-LABEL: fn size_of( + // CHECK: _1 = const 0_usize; + // CHECK-NEXT: _1 = const _; + // CHECK-NEXT: _0 = _1; + let mut a = 0; + a = SizeOfConst::<T>::SIZE; + a +} + +fn main() { + assert_eq!(size_of::<u32>(), std::mem::size_of::<u32>()); +} diff --git a/tests/mir-opt/const_prop/overwrite_with_const_with_params.size_of.ConstProp.diff b/tests/mir-opt/const_prop/overwrite_with_const_with_params.size_of.ConstProp.diff new file mode 100644 index 00000000000..ad8318832d6 --- /dev/null +++ b/tests/mir-opt/const_prop/overwrite_with_const_with_params.size_of.ConstProp.diff @@ -0,0 +1,20 @@ +- // MIR for `size_of` before ConstProp ++ // MIR for `size_of` after ConstProp + + fn size_of() -> usize { + let mut _0: usize; + let mut _1: usize; + scope 1 { + debug a => _1; + } + + bb0: { + StorageLive(_1); + _1 = const 0_usize; + _1 = const _; + _0 = _1; + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff index 2d4591ea2d3..09fc48043b9 100644 --- a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff @@ -8,7 +8,7 @@ let mut _3: u8; scope 1 { } - scope 2 (inlined <u8 as Add>::add) { + scope 2 (inlined #[track_caller] <u8 as Add>::add) { debug self => _2; debug other => _3; let mut _4: (u8, bool); diff --git a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff index e99ac782a2f..c0b26080f56 100644 --- a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff @@ -8,7 +8,7 @@ let mut _3: u8; scope 1 { } - scope 2 (inlined <u8 as Add>::add) { + scope 2 (inlined #[track_caller] <u8 as Add>::add) { debug self => _2; debug other => _3; let mut _4: (u8, bool); diff --git a/tests/run-make/compressed-debuginfo/Makefile b/tests/run-make/compressed-debuginfo/Makefile index f9e4927d008..d2f24dde00d 100644 --- a/tests/run-make/compressed-debuginfo/Makefile +++ b/tests/run-make/compressed-debuginfo/Makefile @@ -2,7 +2,6 @@ include ../tools.mk # only-linux -# min-llvm-version: 16.0 # # This tests debuginfo-compression. diff --git a/tests/run-make/pass-linker-flags-flavor/Makefile b/tests/run-make/pass-linker-flags-flavor/Makefile new file mode 100644 index 00000000000..bd3d3ed882f --- /dev/null +++ b/tests/run-make/pass-linker-flags-flavor/Makefile @@ -0,0 +1,8 @@ +# only-linux + +include ../tools.mk + +all: + $(RUSTC) rs.rs -Z unstable-options -C linker-flavor=gnu-cc -l static=l1 -l link-arg=a1 -l static=l2 -l link-arg=a2 -l dylib=d1 -l link-arg=a3 --print link-args | $(CGREP) -e 'l1.*-Wl,a1.*l2.*-Wl,a2.*d1.*-Wl,a3' + $(RUSTC) rs.rs -Z unstable-options -C linker-flavor=gnu-cc -l static=l1 -l link-arg:+verbatim=a1 -l static=l2 -l link-arg=a2 -l dylib=d1 -l link-arg=a3 --print link-args | $(CGREP) -e 'l1.*"a1".*l2.*-Wl,a2.*d1.*-Wl,a3' + $(RUSTC) rs.rs -Z unstable-options -C linker-flavor=ld -l static=l1 -l link-arg=a1 -l static=l2 -l link-arg=a2 -l dylib=d1 -l link-arg=a3 --print link-args | $(CGREP) -e 'l1.*"a1".*l2.*"a2".*d1.*"a3"' diff --git a/tests/run-make/pass-linker-flags-flavor/rs.rs b/tests/run-make/pass-linker-flags-flavor/rs.rs new file mode 100644 index 00000000000..f328e4d9d04 --- /dev/null +++ b/tests/run-make/pass-linker-flags-flavor/rs.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/ui/associated-inherent-types/assoc-inherent-late-bound.rs b/tests/ui/associated-inherent-types/assoc-inherent-late-bound.rs new file mode 100644 index 00000000000..b6993f66fe7 --- /dev/null +++ b/tests/ui/associated-inherent-types/assoc-inherent-late-bound.rs @@ -0,0 +1,14 @@ +// check-pass + +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +struct Foo<T>(T); + +impl<'a> Foo<fn(&'a ())> { + type Assoc = &'a (); +} + +fn bar(_: for<'a> fn(Foo<fn(Foo<fn(&'static ())>::Assoc)>::Assoc)) {} + +fn main() {} diff --git a/tests/ui/associated-inherent-types/issue-111404-1.rs b/tests/ui/associated-inherent-types/issue-111404-1.rs index f4ad5d7ff6c..dd62e59f07d 100644 --- a/tests/ui/associated-inherent-types/issue-111404-1.rs +++ b/tests/ui/associated-inherent-types/issue-111404-1.rs @@ -9,5 +9,6 @@ impl<'a> Foo<fn(&'a ())> { fn bar(_: fn(Foo<for<'b> fn(Foo<fn(&'b ())>::Assoc)>::Assoc)) {} //~^ ERROR higher-ranked subtype error +//~| ERROR higher-ranked subtype error fn main() {} diff --git a/tests/ui/associated-inherent-types/issue-111404-1.stderr b/tests/ui/associated-inherent-types/issue-111404-1.stderr index 2c78e3a1fb7..cf4d4a5f19b 100644 --- a/tests/ui/associated-inherent-types/issue-111404-1.stderr +++ b/tests/ui/associated-inherent-types/issue-111404-1.stderr @@ -4,5 +4,13 @@ error: higher-ranked subtype error LL | fn bar(_: fn(Foo<for<'b> fn(Foo<fn(&'b ())>::Assoc)>::Assoc)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: higher-ranked subtype error + --> $DIR/issue-111404-1.rs:10:1 + | +LL | fn bar(_: fn(Foo<for<'b> fn(Foo<fn(&'b ())>::Assoc)>::Assoc)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors diff --git a/tests/ui/async-await/issue-70594.rs b/tests/ui/async-await/issue-70594.rs index 9e7c5847b3b..4c8209348b3 100644 --- a/tests/ui/async-await/issue-70594.rs +++ b/tests/ui/async-await/issue-70594.rs @@ -3,9 +3,6 @@ async fn fun() { [1; ().await]; //~^ error: `await` is only allowed inside `async` functions and blocks - //~| error: `.await` is not allowed in a `const` - //~| error: `.await` is not allowed in a `const` - //~| error: `()` is not a future } fn main() {} diff --git a/tests/ui/async-await/issue-70594.stderr b/tests/ui/async-await/issue-70594.stderr index 9866e00bb83..aed99ec3f1f 100644 --- a/tests/ui/async-await/issue-70594.stderr +++ b/tests/ui/async-await/issue-70594.stderr @@ -1,37 +1,12 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-70594.rs:4:12 | -LL | async fn fun() { - | --- this is not `async` LL | [1; ().await]; - | ^^^^^ only allowed inside `async` functions and blocks + | ---^^^^^ + | | | + | | only allowed inside `async` functions and blocks + | this is not `async` -error[E0744]: `.await` is not allowed in a `const` - --> $DIR/issue-70594.rs:4:9 - | -LL | [1; ().await]; - | ^^^^^^^^ - -error[E0744]: `.await` is not allowed in a `const` - --> $DIR/issue-70594.rs:4:12 - | -LL | [1; ().await]; - | ^^^^^ - -error[E0277]: `()` is not a future - --> $DIR/issue-70594.rs:4:12 - | -LL | [1; ().await]; - | -^^^^^ - | || - | |`()` is not a future - | help: remove the `.await` - | - = help: the trait `Future` is not implemented for `()` - = note: () must be a future or must implement `IntoFuture` to be awaited - = note: required for `()` to implement `IntoFuture` - -error: aborting due to 4 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0277, E0728, E0744. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0728`. diff --git a/tests/ui/async-await/issues/issue-62009-1.rs b/tests/ui/async-await/issues/issue-62009-1.rs index 40ccf25712e..51d216408d7 100644 --- a/tests/ui/async-await/issues/issue-62009-1.rs +++ b/tests/ui/async-await/issues/issue-62009-1.rs @@ -11,5 +11,4 @@ fn main() { //~^ ERROR `await` is only allowed inside `async` functions and blocks (|_| 2333).await; //~^ ERROR `await` is only allowed inside `async` functions and blocks - //~| ERROR is not a future } diff --git a/tests/ui/async-await/issues/issue-62009-1.stderr b/tests/ui/async-await/issues/issue-62009-1.stderr index bb617d09076..02933f4f2f2 100644 --- a/tests/ui/async-await/issues/issue-62009-1.stderr +++ b/tests/ui/async-await/issues/issue-62009-1.stderr @@ -24,20 +24,6 @@ LL | fn main() { LL | (|_| 2333).await; | ^^^^^ only allowed inside `async` functions and blocks -error[E0277]: `{closure@$DIR/issue-62009-1.rs:12:6: 12:9}` is not a future - --> $DIR/issue-62009-1.rs:12:16 - | -LL | (|_| 2333).await; - | -^^^^^ - | || - | |`{closure@$DIR/issue-62009-1.rs:12:6: 12:9}` is not a future - | help: remove the `.await` - | - = help: the trait `Future` is not implemented for closure `{closure@$DIR/issue-62009-1.rs:12:6: 12:9}` - = note: {closure@$DIR/issue-62009-1.rs:12:6: 12:9} must be a future or must implement `IntoFuture` to be awaited - = note: required for `{closure@$DIR/issue-62009-1.rs:12:6: 12:9}` to implement `IntoFuture` - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0277, E0728. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0728`. diff --git a/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr index 8221505b100..3ee89d9734a 100644 --- a/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr +++ b/tests/ui/borrowck/issue-114374-invalid-help-fmt-args.stderr @@ -9,7 +9,7 @@ LL | let x = format_args!("a {} {} {}.", 1, format_args!("b{}!", 2), 3); LL | bar(x); | - borrow later used here | - = note: the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used + = note: the result of `format_args!` can only be assigned directly if no placeholders in its arguments are used = note: to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html> = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -24,7 +24,7 @@ LL | LL | bar(foo); | --- borrow later used here | - = note: the result of `format_args!` can only be assigned directly if no placeholders in it's arguments are used + = note: the result of `format_args!` can only be assigned directly if no placeholders in its arguments are used = note: to learn more, visit <https://doc.rust-lang.org/std/macro.format_args.html> = note: this error originates in the macro `format_args` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr b/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr index 272d3e74b9c..6f0a6b04333 100644 --- a/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr +++ b/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr @@ -14,7 +14,6 @@ LL | fn test(&self) -> [u8; bar::<Self>()]; | | | ...because method `test` references the `Self` type in its `where` clause = help: consider moving `test` to another trait - = help: consider moving `test` to another trait = help: only type `()` implements the trait, consider using it directly instead error: aborting due to 1 previous error diff --git a/tests/ui/const_prop/apfloat-f64-roundtrip.rs b/tests/ui/const_prop/apfloat-f64-roundtrip.rs index 9fb2ac96beb..5f3ec931c82 100644 --- a/tests/ui/const_prop/apfloat-f64-roundtrip.rs +++ b/tests/ui/const_prop/apfloat-f64-roundtrip.rs @@ -1,6 +1,5 @@ // run-pass // compile-flags: -O -Zmir-opt-level=3 -Cno-prepopulate-passes -// min-llvm-version: 16.0 (requires APFloat fixes in LLVM) // Regression test for a broken MIR optimization (issue #113407). pub fn main() { diff --git a/tests/ui/const_prop/overwrite_with_const_with_params.rs b/tests/ui/const_prop/overwrite_with_const_with_params.rs new file mode 100644 index 00000000000..6f533919a47 --- /dev/null +++ b/tests/ui/const_prop/overwrite_with_const_with_params.rs @@ -0,0 +1,21 @@ +// compile-flags: -O +// run-pass + +// Regression test for https://github.com/rust-lang/rust/issues/118328 + +#![allow(unused_assignments)] + +struct SizeOfConst<T>(std::marker::PhantomData<T>); +impl<T> SizeOfConst<T> { + const SIZE: usize = std::mem::size_of::<T>(); +} + +fn size_of<T>() -> usize { + let mut a = 0; + a = SizeOfConst::<T>::SIZE; + a +} + +fn main() { + assert_eq!(size_of::<u32>(), std::mem::size_of::<u32>()); +} diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr index c8a99b2d078..43e664ce413 100644 --- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:21:1 + --> $DIR/raw-bytes.rs:22:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x00000001, but expected a valid enum tag @@ -10,7 +10,7 @@ LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:29:1 + --> $DIR/raw-bytes.rs:30:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x00000000, but expected a valid enum tag @@ -21,7 +21,7 @@ LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:43:1 + --> $DIR/raw-bytes.rs:44:1 | LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered an uninhabited enum variant @@ -32,7 +32,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:45:1 + --> $DIR/raw-bytes.rs:46:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered an uninhabited enum variant @@ -43,7 +43,7 @@ LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:51:1 + --> $DIR/raw-bytes.rs:52:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) @@ -54,7 +54,7 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:55:1 + --> $DIR/raw-bytes.rs:57:1 | LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -65,7 +65,7 @@ LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:58:1 + --> $DIR/raw-bytes.rs:60:1 | LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -76,7 +76,7 @@ LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:60:1 + --> $DIR/raw-bytes.rs:62:1 | LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -87,7 +87,7 @@ LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:66:1 + --> $DIR/raw-bytes.rs:68:1 | LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30 @@ -98,7 +98,7 @@ LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:72:1 + --> $DIR/raw-bytes.rs:74:1 | LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30 @@ -109,7 +109,7 @@ LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:75:1 + --> $DIR/raw-bytes.rs:77:1 | LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -120,7 +120,7 @@ LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:83:1 + --> $DIR/raw-bytes.rs:85:1 | LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) @@ -131,7 +131,7 @@ LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:87:1 + --> $DIR/raw-bytes.rs:89:1 | LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) @@ -142,7 +142,7 @@ LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:91:1 + --> $DIR/raw-bytes.rs:93:1 | LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference @@ -153,7 +153,7 @@ LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:94:1 + --> $DIR/raw-bytes.rs:96:1 | LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box @@ -164,7 +164,7 @@ LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:97:1 + --> $DIR/raw-bytes.rs:99:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (0x539[noalloc] has no provenance) @@ -175,7 +175,7 @@ LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:100:1 + --> $DIR/raw-bytes.rs:102:1 | LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (0x539[noalloc] has no provenance) @@ -186,7 +186,7 @@ LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:103:1 + --> $DIR/raw-bytes.rs:105:1 | LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer @@ -197,7 +197,7 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:105:1 + --> $DIR/raw-bytes.rs:107:1 | LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer @@ -208,7 +208,7 @@ LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:107:1 + --> $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 @@ -219,7 +219,7 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:113:1 + --> $DIR/raw-bytes.rs:115:1 | LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar @@ -230,7 +230,7 @@ LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:138:1 + --> $DIR/raw-bytes.rs:140:1 | LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) @@ -241,7 +241,7 @@ LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:140:1 + --> $DIR/raw-bytes.rs:142:1 | LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object @@ -252,7 +252,7 @@ LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, us } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:142:1 + --> $DIR/raw-bytes.rs:144:1 | LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object @@ -263,7 +263,7 @@ LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize: } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:145:1 + --> $DIR/raw-bytes.rs:147:1 | LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized memory, but expected a string @@ -274,7 +274,7 @@ LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit: } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:147:1 + --> $DIR/raw-bytes.rs:149:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized memory, but expected a string @@ -285,7 +285,7 @@ LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUni } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:149:1 + --> $DIR/raw-bytes.rs:151:1 | LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered a pointer, but expected a string @@ -298,7 +298,7 @@ LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _> = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:153:1 + --> $DIR/raw-bytes.rs:155:1 | LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) @@ -309,7 +309,7 @@ LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:155:1 + --> $DIR/raw-bytes.rs:157:1 | LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object @@ -320,7 +320,7 @@ LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, is } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:158:1 + --> $DIR/raw-bytes.rs:160:1 | LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) @@ -331,7 +331,7 @@ LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999us } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:161:1 + --> $DIR/raw-bytes.rs:163:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean @@ -342,13 +342,13 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:161:40 + --> $DIR/raw-bytes.rs:163:40 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:167:1 + --> $DIR/raw-bytes.rs:169:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean @@ -359,13 +359,13 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3 } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:167:42 + --> $DIR/raw-bytes.rs:169:42 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:171:1 + --> $DIR/raw-bytes.rs:173:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean @@ -376,13 +376,13 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:171:42 + --> $DIR/raw-bytes.rs:173:42 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:176:1 + --> $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 @@ -393,7 +393,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:180:1 + --> $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 @@ -404,7 +404,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:184:1 + --> $DIR/raw-bytes.rs:186:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer @@ -415,7 +415,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:187:1 + --> $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 @@ -426,7 +426,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:191:1 + --> $DIR/raw-bytes.rs:193:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean @@ -437,7 +437,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:195:1 + --> $DIR/raw-bytes.rs:197:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer @@ -448,7 +448,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:197:1 + --> $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 @@ -459,29 +459,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:202:1 - | -LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x00000000, but expected a valid enum tag - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 8, align: 4) { - 00 00 00 00 00 10 00 00 │ ........ - } - -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:206:1 - | -LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x00000003, but expected a valid enum tag - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 8, align: 4) { - 03 00 00 00 09 00 00 00 │ ........ - } - -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:210:1 + --> $DIR/raw-bytes.rs:203:1 | LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] @@ -492,7 +470,7 @@ LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:211:1 + --> $DIR/raw-bytes.rs:204:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!` @@ -503,7 +481,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:212:1 + --> $DIR/raw-bytes.rs:205:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!` @@ -514,7 +492,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:216:1 + --> $DIR/raw-bytes.rs:209:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized memory, but expected an integer @@ -525,7 +503,7 @@ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) } } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:219:1 + --> $DIR/raw-bytes.rs:212:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a pointer, but expected an integer @@ -538,7 +516,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem: = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:222:1 + --> $DIR/raw-bytes.rs:215:1 | LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean @@ -549,7 +527,7 @@ LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:226:1 + --> $DIR/raw-bytes.rs:219:1 | LL | pub static S7: &[u16] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized memory, but expected an integer @@ -560,7 +538,7 @@ LL | pub static S7: &[u16] = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:233:1 + --> $DIR/raw-bytes.rs:226:1 | LL | pub static R4: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized memory, but expected an integer @@ -571,7 +549,7 @@ LL | pub static R4: &[u8] = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:238:1 + --> $DIR/raw-bytes.rs:231:1 | LL | pub static R5: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a pointer, but expected an integer @@ -584,7 +562,7 @@ LL | pub static R5: &[u8] = unsafe { = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:243:1 + --> $DIR/raw-bytes.rs:236:1 | LL | pub static R6: &[bool] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean @@ -594,6 +572,6 @@ LL | pub static R6: &[bool] = unsafe { ╾ALLOC_ID╼ 04 00 00 00 │ ╾──╼.... } -error: aborting due to 52 previous errors +error: aborting due to 50 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr index 118ab6019d6..1427cef7d03 100644 --- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:21:1 + --> $DIR/raw-bytes.rs:22:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x0000000000000001, but expected a valid enum tag @@ -10,7 +10,7 @@ LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:29:1 + --> $DIR/raw-bytes.rs:30:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag @@ -21,7 +21,7 @@ LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:43:1 + --> $DIR/raw-bytes.rs:44:1 | LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered an uninhabited enum variant @@ -32,7 +32,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:45:1 + --> $DIR/raw-bytes.rs:46:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-tag>: encountered an uninhabited enum variant @@ -43,7 +43,7 @@ LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:51:1 + --> $DIR/raw-bytes.rs:52:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) @@ -54,7 +54,7 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:55:1 + --> $DIR/raw-bytes.rs:57:1 | LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -65,7 +65,7 @@ LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:58:1 + --> $DIR/raw-bytes.rs:60:1 | LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -76,7 +76,7 @@ LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:60:1 + --> $DIR/raw-bytes.rs:62:1 | LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -87,7 +87,7 @@ LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:66:1 + --> $DIR/raw-bytes.rs:68:1 | LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30 @@ -98,7 +98,7 @@ LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:72:1 + --> $DIR/raw-bytes.rs:74:1 | LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30 @@ -109,7 +109,7 @@ LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:75:1 + --> $DIR/raw-bytes.rs:77:1 | LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -120,7 +120,7 @@ LL | const NULL_FAT_PTR: NonNull<dyn Send> = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:83:1 + --> $DIR/raw-bytes.rs:85:1 | LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) @@ -131,7 +131,7 @@ LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:87:1 + --> $DIR/raw-bytes.rs:89:1 | LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) @@ -142,7 +142,7 @@ LL | const UNALIGNED_BOX: Box<u16> = unsafe { mem::transmute(&[0u8; 4]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:91:1 + --> $DIR/raw-bytes.rs:93:1 | LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference @@ -153,7 +153,7 @@ LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:94:1 + --> $DIR/raw-bytes.rs:96:1 | LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box @@ -164,7 +164,7 @@ LL | const NULL_BOX: Box<u16> = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:97:1 + --> $DIR/raw-bytes.rs:99:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (0x539[noalloc] has no provenance) @@ -175,7 +175,7 @@ LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:100:1 + --> $DIR/raw-bytes.rs:102:1 | LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (0x539[noalloc] has no provenance) @@ -186,7 +186,7 @@ LL | const USIZE_AS_BOX: Box<u8> = unsafe { mem::transmute(1337usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:103:1 + --> $DIR/raw-bytes.rs:105:1 | LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer @@ -197,7 +197,7 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:105:1 + --> $DIR/raw-bytes.rs:107:1 | LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer @@ -208,7 +208,7 @@ LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:107:1 + --> $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 @@ -219,7 +219,7 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:113:1 + --> $DIR/raw-bytes.rs:115:1 | LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar @@ -230,7 +230,7 @@ LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:138:1 + --> $DIR/raw-bytes.rs:140:1 | LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) @@ -241,7 +241,7 @@ LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:140:1 + --> $DIR/raw-bytes.rs:142:1 | LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object @@ -252,7 +252,7 @@ LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, us } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:142:1 + --> $DIR/raw-bytes.rs:144:1 | LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object @@ -263,7 +263,7 @@ LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize: } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:145:1 + --> $DIR/raw-bytes.rs:147:1 | LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered uninitialized memory, but expected a string @@ -274,7 +274,7 @@ LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit: } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:147:1 + --> $DIR/raw-bytes.rs:149:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit::<u8> { uninit: () }]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered uninitialized memory, but expected a string @@ -285,7 +285,7 @@ LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUni } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:149:1 + --> $DIR/raw-bytes.rs:151:1 | LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered a pointer, but expected a string @@ -298,7 +298,7 @@ LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _> = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:153:1 + --> $DIR/raw-bytes.rs:155:1 | LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) @@ -309,7 +309,7 @@ LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:155:1 + --> $DIR/raw-bytes.rs:157:1 | LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object @@ -320,7 +320,7 @@ LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, is } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:158:1 + --> $DIR/raw-bytes.rs:160:1 | LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) @@ -331,7 +331,7 @@ LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999us } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:161:1 + --> $DIR/raw-bytes.rs:163:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x03, but expected a boolean @@ -342,13 +342,13 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:161:40 + --> $DIR/raw-bytes.rs:163:40 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:167:1 + --> $DIR/raw-bytes.rs:169:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.0: encountered 0x03, but expected a boolean @@ -359,13 +359,13 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3 } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:167:42 + --> $DIR/raw-bytes.rs:169:42 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:171:1 + --> $DIR/raw-bytes.rs:173:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.1[0]: encountered 0x03, but expected a boolean @@ -376,13 +376,13 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:171:42 + --> $DIR/raw-bytes.rs:173:42 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:176:1 + --> $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 @@ -393,7 +393,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:180:1 + --> $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 @@ -404,7 +404,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:184:1 + --> $DIR/raw-bytes.rs:186:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer @@ -415,7 +415,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:187:1 + --> $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 @@ -426,7 +426,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:191:1 + --> $DIR/raw-bytes.rs:193:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean @@ -437,7 +437,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:195:1 + --> $DIR/raw-bytes.rs:197:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer @@ -448,7 +448,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:197:1 + --> $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 @@ -459,29 +459,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:202:1 - | -LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 16, align: 8) { - 00 00 00 00 00 00 00 00 00 10 00 00 00 00 00 00 │ ................ - } - -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:206:1 - | -LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x0000000000000003, but expected a valid enum tag - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: 16, align: 8) { - 03 00 00 00 00 00 00 00 09 00 00 00 00 00 00 00 │ ................ - } - -error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:210:1 + --> $DIR/raw-bytes.rs:203:1 | LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] @@ -492,7 +470,7 @@ LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:211:1 + --> $DIR/raw-bytes.rs:204:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!` @@ -503,7 +481,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:212:1 + --> $DIR/raw-bytes.rs:205:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; | ^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a value of the never type `!` @@ -514,7 +492,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:216:1 + --> $DIR/raw-bytes.rs:209:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized memory, but expected an integer @@ -525,7 +503,7 @@ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) } } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:219:1 + --> $DIR/raw-bytes.rs:212:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a pointer, but expected an integer @@ -538,7 +516,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem: = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:222:1 + --> $DIR/raw-bytes.rs:215:1 | LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean @@ -549,7 +527,7 @@ LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:226:1 + --> $DIR/raw-bytes.rs:219:1 | LL | pub static S7: &[u16] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized memory, but expected an integer @@ -560,7 +538,7 @@ LL | pub static S7: &[u16] = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:233:1 + --> $DIR/raw-bytes.rs:226:1 | LL | pub static R4: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized memory, but expected an integer @@ -571,7 +549,7 @@ LL | pub static R4: &[u8] = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:238:1 + --> $DIR/raw-bytes.rs:231:1 | LL | pub static R5: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a pointer, but expected an integer @@ -584,7 +562,7 @@ LL | pub static R5: &[u8] = unsafe { = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:243:1 + --> $DIR/raw-bytes.rs:236:1 | LL | pub static R6: &[bool] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean @@ -594,6 +572,6 @@ LL | pub static R6: &[bool] = unsafe { ╾ALLOC_ID╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ } -error: aborting due to 52 previous errors +error: aborting due to 50 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/raw-bytes.rs b/tests/ui/consts/const-eval/raw-bytes.rs index aa4a41a7caa..ff2a32d5757 100644 --- a/tests/ui/consts/const-eval/raw-bytes.rs +++ b/tests/ui/consts/const-eval/raw-bytes.rs @@ -1,7 +1,6 @@ // stderr-per-bitwidth // ignore-endian-big // ignore-tidy-linelength -// ignore-debug debug assertions catch some UB too early // normalize-stderr-test "╾─*ALLOC[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$1╼" #![feature(never_type, rustc_attrs, ptr_metadata, slice_from_ptr_range, const_slice_from_ptr_range)] @@ -13,6 +12,8 @@ use std::ptr::NonNull; use std::num::{NonZeroU8, NonZeroUsize}; use std::slice::{from_ptr_range, from_raw_parts}; +// # Bad enums and chars + #[repr(usize)] #[derive(Copy, Clone)] enum Enum { @@ -51,6 +52,7 @@ const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); //~^ ERROR is undefined behavior +// # Bad pointers and references const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) }; //~^ ERROR it is undefined behavior to use this value @@ -197,16 +199,7 @@ const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92 const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; //~^ ERROR it is undefined behavior to use this value - -// not ok, since alignment needs to be non-zero. -const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; -//~^ ERROR it is undefined behavior to use this value - -// not ok, since alignment needs to be a power of two. -const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) }; -//~^ ERROR it is undefined behavior to use this value - - +// Uninhabited types const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; //~ ERROR undefined behavior const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; //~ ERROR undefined behavior diff --git a/tests/ui/consts/std/alloc.32bit.stderr b/tests/ui/consts/std/alloc.32bit.stderr deleted file mode 100644 index 8c83df53dad..00000000000 --- a/tests/ui/consts/std/alloc.32bit.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/alloc.rs:12:1 - | -LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x00000000, but expected a valid enum tag - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -error[E0080]: it is undefined behavior to use this value - --> $DIR/alloc.rs:16:1 - | -LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x00000003, but expected a valid enum tag - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/std/alloc.64bit.stderr b/tests/ui/consts/std/alloc.64bit.stderr deleted file mode 100644 index addedad1704..00000000000 --- a/tests/ui/consts/std/alloc.64bit.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/alloc.rs:12:1 - | -LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -error[E0080]: it is undefined behavior to use this value - --> $DIR/alloc.rs:16:1 - | -LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.<enum-tag>: encountered 0x0000000000000003, but expected a valid enum tag - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { - HEX_DUMP - } - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/std/alloc.rs b/tests/ui/consts/std/alloc.rs deleted file mode 100644 index a456a672293..00000000000 --- a/tests/ui/consts/std/alloc.rs +++ /dev/null @@ -1,19 +0,0 @@ -// stderr-per-bitwidth -// Strip out raw byte dumps to make comparison platform-independent: -// normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" -// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" -// ignore-debug debug assertions catch some UB too early -use std::alloc::Layout; - -// ok -const LAYOUT_VALID: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x08) }; - -// not ok, since alignment needs to be non-zero. -const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; -//~^ ERROR it is undefined behavior to use this value - -// not ok, since alignment needs to be a power of two. -const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) }; -//~^ ERROR it is undefined behavior to use this value - -fn main() {} diff --git a/tests/ui/coroutine/auxiliary/unwind-aux.rs b/tests/ui/coroutine/auxiliary/unwind-aux.rs new file mode 100644 index 00000000000..215d6769116 --- /dev/null +++ b/tests/ui/coroutine/auxiliary/unwind-aux.rs @@ -0,0 +1,11 @@ +// compile-flags: -Cpanic=unwind --crate-type=lib +// no-prefer-dynamic +// edition:2021 + +#![feature(coroutines)] +pub fn run<T>(a: T) { + let _ = move || { + drop(a); + yield; + }; +} diff --git a/tests/ui/coroutine/unwind-abort-mix.rs b/tests/ui/coroutine/unwind-abort-mix.rs new file mode 100644 index 00000000000..869b3e4f433 --- /dev/null +++ b/tests/ui/coroutine/unwind-abort-mix.rs @@ -0,0 +1,13 @@ +// Ensure that coroutine drop glue is valid when mixing different panic +// strategies. Regression test for #116953. +// +// no-prefer-dynamic +// build-pass +// aux-build:unwind-aux.rs +// compile-flags: -Cpanic=abort +// needs-unwind +extern crate unwind_aux; + +pub fn main() { + unwind_aux::run(String::new()); +} diff --git a/tests/ui/dep-graph/dep-graph-trait-impl-two-traits.rs b/tests/ui/dep-graph/dep-graph-trait-impl-two-traits.rs index 590475fa03a..0331e75b2fe 100644 --- a/tests/ui/dep-graph/dep-graph-trait-impl-two-traits.rs +++ b/tests/ui/dep-graph/dep-graph-trait-impl-two-traits.rs @@ -29,7 +29,7 @@ mod x { mod y { use {Foo, Bar}; - #[rustc_then_this_would_need(typeck)] //~ ERROR OK + #[rustc_then_this_would_need(typeck)] //~ ERROR no path pub fn call_bar() { char::bar('a'); } diff --git a/tests/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr b/tests/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr index 4e10437362c..08f382cc024 100644 --- a/tests/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr +++ b/tests/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr @@ -1,4 +1,4 @@ -error: OK +error: no path from `x::<impl Foo for char>` to `typeck` --> $DIR/dep-graph-trait-impl-two-traits.rs:32:5 | LL | #[rustc_then_this_would_need(typeck)] diff --git a/tests/ui/expr/if/bad-if-let-suggestion.rs b/tests/ui/expr/if/bad-if-let-suggestion.rs index 99d584ac7a5..b0d0676e1ea 100644 --- a/tests/ui/expr/if/bad-if-let-suggestion.rs +++ b/tests/ui/expr/if/bad-if-let-suggestion.rs @@ -1,6 +1,3 @@ -// FIXME(compiler-errors): This really should suggest `let` on the RHS of the -// `&&` operator, but that's kinda hard to do because of precedence. -// Instead, for now we just make sure not to suggest `if let let`. fn a() { if let x = 1 && i = 2 {} //~^ ERROR cannot find value `i` in this scope diff --git a/tests/ui/expr/if/bad-if-let-suggestion.stderr b/tests/ui/expr/if/bad-if-let-suggestion.stderr index 20ac9ca76ba..0d1f895bd82 100644 --- a/tests/ui/expr/if/bad-if-let-suggestion.stderr +++ b/tests/ui/expr/if/bad-if-let-suggestion.stderr @@ -1,19 +1,27 @@ error: expected expression, found `let` statement - --> $DIR/bad-if-let-suggestion.rs:5:8 + --> $DIR/bad-if-let-suggestion.rs:2:8 | LL | if let x = 1 && i = 2 {} | ^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions +help: you might have meant to continue the let-chain + | +LL | if let x = 1 && let i = 2 {} + | +++ +help: you might have meant to compare for equality + | +LL | if let x = 1 && i == 2 {} + | + error[E0425]: cannot find value `i` in this scope - --> $DIR/bad-if-let-suggestion.rs:5:21 + --> $DIR/bad-if-let-suggestion.rs:2:21 | LL | if let x = 1 && i = 2 {} | ^ not found in this scope error[E0425]: cannot find value `i` in this scope - --> $DIR/bad-if-let-suggestion.rs:12:9 + --> $DIR/bad-if-let-suggestion.rs:9:9 | LL | fn a() { | ------ similarly named function `a` defined here @@ -22,7 +30,7 @@ LL | if (i + j) = i {} | ^ help: a function with a similar name exists: `a` error[E0425]: cannot find value `j` in this scope - --> $DIR/bad-if-let-suggestion.rs:12:13 + --> $DIR/bad-if-let-suggestion.rs:9:13 | LL | fn a() { | ------ similarly named function `a` defined here @@ -31,7 +39,7 @@ LL | if (i + j) = i {} | ^ help: a function with a similar name exists: `a` error[E0425]: cannot find value `i` in this scope - --> $DIR/bad-if-let-suggestion.rs:12:18 + --> $DIR/bad-if-let-suggestion.rs:9:18 | LL | fn a() { | ------ similarly named function `a` defined here @@ -40,7 +48,7 @@ LL | if (i + j) = i {} | ^ help: a function with a similar name exists: `a` error[E0425]: cannot find value `x` in this scope - --> $DIR/bad-if-let-suggestion.rs:19:8 + --> $DIR/bad-if-let-suggestion.rs:16:8 | LL | fn a() { | ------ similarly named function `a` defined here @@ -49,7 +57,7 @@ LL | if x[0] = 1 {} | ^ help: a function with a similar name exists: `a` error[E0308]: mismatched types - --> $DIR/bad-if-let-suggestion.rs:5:8 + --> $DIR/bad-if-let-suggestion.rs:2:8 | LL | if let x = 1 && i = 2 {} | ^^^^^^^^^^^^^^^^^^ expected `bool`, found `()` diff --git a/tests/ui/feature-gates/feature-gate-never_patterns.rs b/tests/ui/feature-gates/feature-gate-never_patterns.rs new file mode 100644 index 00000000000..69e9f62abf0 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-never_patterns.rs @@ -0,0 +1,27 @@ +// Check that never patterns require the feature gate. +use std::ptr::NonNull; + +enum Void {} + +fn main() { + let res: Result<u32, Void> = Ok(0); + let (Ok(_x) | Err(&!)) = res.as_ref(); + //~^ ERROR `!` patterns are experimental + //~| ERROR: is not bound in all patterns + + unsafe { + let ptr: *const Void = NonNull::dangling().as_ptr(); + match *ptr { + ! => {} //~ ERROR `!` patterns are experimental + } + } + + // Check that the gate operates even behind `cfg`. + #[cfg(FALSE)] + unsafe { + let ptr: *const Void = NonNull::dangling().as_ptr(); + match *ptr { + ! => {} //~ ERROR `!` patterns are experimental + } + } +} diff --git a/tests/ui/feature-gates/feature-gate-never_patterns.stderr b/tests/ui/feature-gates/feature-gate-never_patterns.stderr new file mode 100644 index 00000000000..b7290eeb36d --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-never_patterns.stderr @@ -0,0 +1,39 @@ +error[E0408]: variable `_x` is not bound in all patterns + --> $DIR/feature-gate-never_patterns.rs:8:19 + | +LL | let (Ok(_x) | Err(&!)) = res.as_ref(); + | -- ^^^^^^^ pattern doesn't bind `_x` + | | + | variable not in all patterns + +error[E0658]: `!` patterns are experimental + --> $DIR/feature-gate-never_patterns.rs:8:24 + | +LL | let (Ok(_x) | Err(&!)) = res.as_ref(); + | ^ + | + = note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information + = help: add `#![feature(never_patterns)]` to the crate attributes to enable + +error[E0658]: `!` patterns are experimental + --> $DIR/feature-gate-never_patterns.rs:15:13 + | +LL | ! => {} + | ^ + | + = note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information + = help: add `#![feature(never_patterns)]` to the crate attributes to enable + +error[E0658]: `!` patterns are experimental + --> $DIR/feature-gate-never_patterns.rs:24:13 + | +LL | ! => {} + | ^ + | + = note: see issue #118155 <https://github.com/rust-lang/rust/issues/118155> for more information + = help: add `#![feature(never_patterns)]` to the crate attributes to enable + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0408, E0658. +For more information about an error, try `rustc --explain E0408`. diff --git a/tests/ui/invalid-compile-flags/function-return/requires-x86-or-x86_64.aarch64.stderr b/tests/ui/invalid-compile-flags/function-return/requires-x86-or-x86_64.aarch64.stderr new file mode 100644 index 00000000000..a4fe77f5cbb --- /dev/null +++ b/tests/ui/invalid-compile-flags/function-return/requires-x86-or-x86_64.aarch64.stderr @@ -0,0 +1,4 @@ +error: `-Zfunction-return` (except `keep`) is only supported on x86 and x86_64 + +error: aborting due to 1 previous error + diff --git a/tests/ui/invalid-compile-flags/function-return/requires-x86-or-x86_64.rs b/tests/ui/invalid-compile-flags/function-return/requires-x86-or-x86_64.rs new file mode 100644 index 00000000000..15a88ebdb11 --- /dev/null +++ b/tests/ui/invalid-compile-flags/function-return/requires-x86-or-x86_64.rs @@ -0,0 +1,20 @@ +// revisions: x86 x86_64 aarch64 + +// compile-flags: -Zfunction-return=thunk-extern + +//[x86] check-pass +//[x86] needs-llvm-components: x86 +//[x86] compile-flags: --target i686-unknown-linux-gnu + +//[x86_64] check-pass +//[x86_64] needs-llvm-components: x86 +//[x86_64] compile-flags: --target x86_64-unknown-linux-gnu + +//[aarch64] check-fail +//[aarch64] needs-llvm-components: aarch64 +//[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//[aarch64] error-pattern: `-Zfunction-return` (except `keep`) is only supported on x86 and x86_64 + +#![feature(no_core)] +#![no_core] +#![no_main] diff --git a/tests/ui/invalid-compile-flags/function-return/thunk-extern-requires-non-large-code-model.large.stderr b/tests/ui/invalid-compile-flags/function-return/thunk-extern-requires-non-large-code-model.large.stderr new file mode 100644 index 00000000000..683b3213d07 --- /dev/null +++ b/tests/ui/invalid-compile-flags/function-return/thunk-extern-requires-non-large-code-model.large.stderr @@ -0,0 +1,4 @@ +error: `-Zfunction-return=thunk-extern` is only supported on non-large code models + +error: aborting due to 1 previous error + diff --git a/tests/ui/invalid-compile-flags/function-return/thunk-extern-requires-non-large-code-model.rs b/tests/ui/invalid-compile-flags/function-return/thunk-extern-requires-non-large-code-model.rs new file mode 100644 index 00000000000..f925905de36 --- /dev/null +++ b/tests/ui/invalid-compile-flags/function-return/thunk-extern-requires-non-large-code-model.rs @@ -0,0 +1,21 @@ +// revisions: small kernel medium large + +// needs-llvm-components: x86 +// compile-flags: --target x86_64-unknown-linux-gnu -Zfunction-return=thunk-extern + +//[small] check-pass +//[small] compile-flags: -Ccode-model=small + +//[kernel] check-pass +//[kernel] compile-flags: -Ccode-model=kernel + +//[medium] check-pass +//[medium] compile-flags: -Ccode-model=medium + +//[large] check-fail +//[large] compile-flags: -Ccode-model=large +//[large] error-pattern: `-Zfunction-return=thunk-extern` is only supported on non-large code models + +#![feature(no_core)] +#![no_core] +#![no_main] diff --git a/tests/ui/issues/issue-66706.stderr b/tests/ui/issues/issue-66706.stderr index 8a30c0cad39..ffdd61e7723 100644 --- a/tests/ui/issues/issue-66706.stderr +++ b/tests/ui/issues/issue-66706.stderr @@ -24,7 +24,9 @@ error: expected identifier, found reserved identifier `_` --> $DIR/issue-66706.rs:18:26 | LL | [0; match [|f @ &ref _| () ] {} ] - | ^ expected identifier, found reserved identifier + | ----- ^ expected identifier, found reserved identifier + | | + | while parsing this `match` expression error[E0282]: type annotations needed --> $DIR/issue-66706.rs:2:11 diff --git a/tests/ui/lint/issue-103435-extra-parentheses.fixed b/tests/ui/lint/issue-103435-extra-parentheses.fixed index 2b01b414baa..74b5aa06e35 100644 --- a/tests/ui/lint/issue-103435-extra-parentheses.fixed +++ b/tests/ui/lint/issue-103435-extra-parentheses.fixed @@ -13,6 +13,5 @@ fn main() { // reported by parser for _x in 1..10 {} - //~^ ERROR expected one of - //~| ERROR unexpected parentheses surrounding + //~^ ERROR unexpected parentheses surrounding } diff --git a/tests/ui/lint/issue-103435-extra-parentheses.rs b/tests/ui/lint/issue-103435-extra-parentheses.rs index 8261610cf56..cc81a64f217 100644 --- a/tests/ui/lint/issue-103435-extra-parentheses.rs +++ b/tests/ui/lint/issue-103435-extra-parentheses.rs @@ -8,11 +8,10 @@ fn main() { for(_x)in 1..10 {} //~^ ERROR unnecessary parentheses around pattern - if(2 == 1){} + if(2 == 1) {} //~^ ERROR unnecessary parentheses around `if` condition // reported by parser - for(_x in 1..10){} - //~^ ERROR expected one of - //~| ERROR unexpected parentheses surrounding + for(_x in 1..10) {} + //~^ ERROR unexpected parentheses surrounding } diff --git a/tests/ui/lint/issue-103435-extra-parentheses.stderr b/tests/ui/lint/issue-103435-extra-parentheses.stderr index 29c41c91050..5a166eb5008 100644 --- a/tests/ui/lint/issue-103435-extra-parentheses.stderr +++ b/tests/ui/lint/issue-103435-extra-parentheses.stderr @@ -1,18 +1,12 @@ -error: expected one of `)`, `,`, `@`, or `|`, found keyword `in` - --> $DIR/issue-103435-extra-parentheses.rs:15:12 - | -LL | for(_x in 1..10){} - | ^^ expected one of `)`, `,`, `@`, or `|` - error: unexpected parentheses surrounding `for` loop head --> $DIR/issue-103435-extra-parentheses.rs:15:8 | -LL | for(_x in 1..10){} +LL | for(_x in 1..10) {} | ^ ^ | help: remove parentheses in `for` loop | -LL - for(_x in 1..10){} +LL - for(_x in 1..10) {} LL + for _x in 1..10 {} | @@ -48,14 +42,14 @@ LL + for _x in 1..10 {} error: unnecessary parentheses around `if` condition --> $DIR/issue-103435-extra-parentheses.rs:11:7 | -LL | if(2 == 1){} +LL | if(2 == 1) {} | ^ ^ | help: remove these parentheses | -LL - if(2 == 1){} +LL - if(2 == 1) {} LL + if 2 == 1 {} | -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index 70ca00285c4..c0eb7f01fdb 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -11,6 +11,7 @@ #![feature(decl_macro)] #![feature(explicit_tail_calls)] #![feature(more_qualified_paths)] +#![feature(never_patterns)] #![feature(raw_ref_op)] #![feature(trait_alias)] #![feature(try_blocks)] @@ -635,6 +636,10 @@ fn test_pat() { // PatKind::Rest c1!(pat, [ .. ], ".."); + // PatKind::Never + c1!(pat, [ Some(!) ], "Some(!)"); + c1!(pat, [ None | Some(!) ], "None | Some(!)"); + // PatKind::Paren c1!(pat, [ (pat) ], "(pat)"); diff --git a/tests/ui/match/match-tail-expr-never-type-error.rs b/tests/ui/match/match-tail-expr-never-type-error.rs new file mode 100644 index 00000000000..786ed3fa904 --- /dev/null +++ b/tests/ui/match/match-tail-expr-never-type-error.rs @@ -0,0 +1,16 @@ +fn never() -> ! { + loop {} +} + +fn bar(a: bool) { + match a { + true => 1, + false => { + never() //~ ERROR `match` arms have incompatible types + } + } +} +fn main() { + bar(true); + bar(false); +} diff --git a/tests/ui/match/match-tail-expr-never-type-error.stderr b/tests/ui/match/match-tail-expr-never-type-error.stderr new file mode 100644 index 00000000000..226d33daeb2 --- /dev/null +++ b/tests/ui/match/match-tail-expr-never-type-error.stderr @@ -0,0 +1,21 @@ +error[E0308]: `match` arms have incompatible types + --> $DIR/match-tail-expr-never-type-error.rs:9:13 + | +LL | fn bar(a: bool) { + | - help: try adding a return type: `-> i32` +LL | / match a { +LL | | true => 1, + | | - this is found to be of type `{integer}` +LL | | false => { +LL | | never() + | | ^^^^^^^ + | | | + | | expected integer, found `()` + | | this expression is of type `!`, but it is coerced to `()` due to its surrounding expression +LL | | } +LL | | } + | |_____- `match` arms have incompatible types + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/mismatched_types/issue-118145-unwrap-for-shorthand.fixed b/tests/ui/mismatched_types/issue-118145-unwrap-for-shorthand.fixed new file mode 100644 index 00000000000..15d4e393874 --- /dev/null +++ b/tests/ui/mismatched_types/issue-118145-unwrap-for-shorthand.fixed @@ -0,0 +1,20 @@ +// run-rustfix +#![allow(unused, dead_code)] + +#[derive(Clone, Copy)] +struct Stuff { + count: i32, +} +struct Error; + +fn demo() -> Result<Stuff, Error> { + let count = Ok(1); + Ok(Stuff { count: count? }) //~ ERROR mismatched types +} + +fn demo_unwrap() -> Stuff { + let count = Some(1); + Stuff { count: count.expect("REASON") } //~ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/mismatched_types/issue-118145-unwrap-for-shorthand.rs b/tests/ui/mismatched_types/issue-118145-unwrap-for-shorthand.rs new file mode 100644 index 00000000000..8e811caa3bd --- /dev/null +++ b/tests/ui/mismatched_types/issue-118145-unwrap-for-shorthand.rs @@ -0,0 +1,20 @@ +// run-rustfix +#![allow(unused, dead_code)] + +#[derive(Clone, Copy)] +struct Stuff { + count: i32, +} +struct Error; + +fn demo() -> Result<Stuff, Error> { + let count = Ok(1); + Ok(Stuff { count }) //~ ERROR mismatched types +} + +fn demo_unwrap() -> Stuff { + let count = Some(1); + Stuff { count } //~ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/mismatched_types/issue-118145-unwrap-for-shorthand.stderr b/tests/ui/mismatched_types/issue-118145-unwrap-for-shorthand.stderr new file mode 100644 index 00000000000..0bcbd6f27c4 --- /dev/null +++ b/tests/ui/mismatched_types/issue-118145-unwrap-for-shorthand.stderr @@ -0,0 +1,29 @@ +error[E0308]: mismatched types + --> $DIR/issue-118145-unwrap-for-shorthand.rs:12:16 + | +LL | Ok(Stuff { count }) + | ^^^^^ expected `i32`, found `Result<{integer}, _>` + | + = note: expected type `i32` + found enum `Result<{integer}, _>` +help: use the `?` operator to extract the `Result<{integer}, _>` value, propagating a `Result::Err` value to the caller + | +LL | Ok(Stuff { count: count? }) + | ++++++++ + +error[E0308]: mismatched types + --> $DIR/issue-118145-unwrap-for-shorthand.rs:17:13 + | +LL | Stuff { count } + | ^^^^^ expected `i32`, found `Option<{integer}>` + | + = note: expected type `i32` + found enum `Option<{integer}>` +help: consider using `Option::expect` to unwrap the `Option<{integer}>` value, panicking if the value is an `Option::None` + | +LL | Stuff { count: count.expect("REASON") } + | ++++++++++++++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.fixed b/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.fixed new file mode 100644 index 00000000000..e1f929e6170 --- /dev/null +++ b/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.fixed @@ -0,0 +1,77 @@ +// run-rustfix +// edition:2021 +#![allow(dead_code)] +#![allow(unused_variables)] +use std::future::Future; +use std::pin::Pin; + +fn test1() { + let string = String::from("Hello, world"); + + struct Demo<'a> { + option: Option<&'a str>, + } + + let option: Option<String> = Some(string.clone()); + let s = Demo { option: option.as_deref() }; //~ ERROR mismatched types +} + +fn test2() { + let string = String::from("Hello, world"); + + struct Demo<'a> { + option_ref: Option<&'a str>, + } + + let option_ref = Some(&string); + let s = Demo { option_ref: option_ref.map(|x| x.as_str()) }; //~ ERROR mismatched types +} + +fn test3() { + let string = String::from("Hello, world"); + + struct Demo<'a> { + option_ref_ref: Option<&'a str>, + } + + let option_ref = Some(&string); + let option_ref_ref = option_ref.as_ref(); + + let s = Demo { option_ref_ref: option_ref_ref.map(|x| x.as_str()) }; //~ ERROR mismatched types +} + +fn test4() { + let a = 1; + struct Demo { + a: String, + } + let s = Demo { a: a.to_string() }; //~ ERROR mismatched types +} + +type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>; +fn test5() { + let a = async { 42 }; + struct Demo { + a: BoxFuture<'static, i32>, + } + let s = Demo { a: Box::pin(a) }; //~ ERROR mismatched types +} + +fn test6() { + struct A; + struct B; + + impl From<B> for A { + fn from(_: B) -> Self { + A + } + } + + struct Demo { + a: A, + } + let a = B; + let s = Demo { a: a.into() }; //~ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.rs b/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.rs new file mode 100644 index 00000000000..956936c925b --- /dev/null +++ b/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.rs @@ -0,0 +1,77 @@ +// run-rustfix +// edition:2021 +#![allow(dead_code)] +#![allow(unused_variables)] +use std::future::Future; +use std::pin::Pin; + +fn test1() { + let string = String::from("Hello, world"); + + struct Demo<'a> { + option: Option<&'a str>, + } + + let option: Option<String> = Some(string.clone()); + let s = Demo { option }; //~ ERROR mismatched types +} + +fn test2() { + let string = String::from("Hello, world"); + + struct Demo<'a> { + option_ref: Option<&'a str>, + } + + let option_ref = Some(&string); + let s = Demo { option_ref }; //~ ERROR mismatched types +} + +fn test3() { + let string = String::from("Hello, world"); + + struct Demo<'a> { + option_ref_ref: Option<&'a str>, + } + + let option_ref = Some(&string); + let option_ref_ref = option_ref.as_ref(); + + let s = Demo { option_ref_ref }; //~ ERROR mismatched types +} + +fn test4() { + let a = 1; + struct Demo { + a: String, + } + let s = Demo { a }; //~ ERROR mismatched types +} + +type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>; +fn test5() { + let a = async { 42 }; + struct Demo { + a: BoxFuture<'static, i32>, + } + let s = Demo { a }; //~ ERROR mismatched types +} + +fn test6() { + struct A; + struct B; + + impl From<B> for A { + fn from(_: B) -> Self { + A + } + } + + struct Demo { + a: A, + } + let a = B; + let s = Demo { a }; //~ ERROR mismatched types +} + +fn main() {} diff --git a/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.stderr b/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.stderr new file mode 100644 index 00000000000..1baf95d2bf7 --- /dev/null +++ b/tests/ui/mismatched_types/mismatch-sugg-for-shorthand-field.stderr @@ -0,0 +1,80 @@ +error[E0308]: mismatched types + --> $DIR/mismatch-sugg-for-shorthand-field.rs:16:20 + | +LL | let s = Demo { option }; + | ^^^^^^ expected `Option<&str>`, found `Option<String>` + | + = note: expected enum `Option<&str>` + found enum `Option<String>` +help: try using `: option.as_deref()` to convert `Option<String>` to `Option<&str>` + | +LL | let s = Demo { option: option.as_deref() }; + | +++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/mismatch-sugg-for-shorthand-field.rs:27:20 + | +LL | let s = Demo { option_ref }; + | ^^^^^^^^^^ expected `Option<&str>`, found `Option<&String>` + | + = note: expected enum `Option<&str>` + found enum `Option<&String>` +help: try converting the passed type into a `&str` + | +LL | let s = Demo { option_ref: option_ref.map(|x| x.as_str()) }; + | ++++++++++++++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/mismatch-sugg-for-shorthand-field.rs:40:20 + | +LL | let s = Demo { option_ref_ref }; + | ^^^^^^^^^^^^^^ expected `Option<&str>`, found `Option<&&String>` + | + = note: expected enum `Option<&str>` + found enum `Option<&&String>` +help: try converting the passed type into a `&str` + | +LL | let s = Demo { option_ref_ref: option_ref_ref.map(|x| x.as_str()) }; + | ++++++++++++++++++++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/mismatch-sugg-for-shorthand-field.rs:48:20 + | +LL | let s = Demo { a }; + | ^ expected `String`, found integer + | +help: try using a conversion method + | +LL | let s = Demo { a: a.to_string() }; + | ++ ++++++++++++ + +error[E0308]: mismatched types + --> $DIR/mismatch-sugg-for-shorthand-field.rs:57:20 + | +LL | let a = async { 42 }; + | ------------ the found `async` block +... +LL | let s = Demo { a }; + | ^ expected `Pin<Box<...>>`, found `async` block + | + = note: expected struct `Pin<Box<(dyn Future<Output = i32> + Send + 'static)>>` + found `async` block `{async block@$DIR/mismatch-sugg-for-shorthand-field.rs:53:13: 53:25}` +help: you need to pin and box this expression + | +LL | let s = Demo { a: Box::pin(a) }; + | ++++++++++++ + + +error[E0308]: mismatched types + --> $DIR/mismatch-sugg-for-shorthand-field.rs:74:20 + | +LL | let s = Demo { a }; + | ^ expected `A`, found `B` + | +help: call `Into::into` on this expression to convert `B` into `A` + | +LL | let s = Demo { a: a.into() }; + | ++ +++++++ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/numbers-arithmetic/issue-105626.rs b/tests/ui/numbers-arithmetic/issue-105626.rs index f97edd510c9..5466f8e18d4 100644 --- a/tests/ui/numbers-arithmetic/issue-105626.rs +++ b/tests/ui/numbers-arithmetic/issue-105626.rs @@ -1,6 +1,5 @@ // run-pass // only-x86 -// min-system-llvm-version: 16 // compile-flags: -Ctarget-feature=+sse2 use std::hint::black_box; diff --git a/tests/ui/numbers-arithmetic/location-add-assign-overflow.rs b/tests/ui/numbers-arithmetic/location-add-assign-overflow.rs new file mode 100644 index 00000000000..2c4bdad3e91 --- /dev/null +++ b/tests/ui/numbers-arithmetic/location-add-assign-overflow.rs @@ -0,0 +1,8 @@ +// run-fail +// ignore-wasm32 +// error-pattern:location-add-assign-overflow.rs + +fn main() { + let mut a: u8 = 255; + a += &1; +} diff --git a/tests/ui/numbers-arithmetic/location-add-overflow.rs b/tests/ui/numbers-arithmetic/location-add-overflow.rs new file mode 100644 index 00000000000..085623c9bf7 --- /dev/null +++ b/tests/ui/numbers-arithmetic/location-add-overflow.rs @@ -0,0 +1,7 @@ +// run-fail +// ignore-wasm32 +// error-pattern:location-add-overflow.rs + +fn main() { + let _: u8 = 255 + &1; +} diff --git a/tests/ui/numbers-arithmetic/location-divide-assign-by-zero.rs b/tests/ui/numbers-arithmetic/location-divide-assign-by-zero.rs new file mode 100644 index 00000000000..21b5e7a8110 --- /dev/null +++ b/tests/ui/numbers-arithmetic/location-divide-assign-by-zero.rs @@ -0,0 +1,8 @@ +// run-fail +// ignore-wasm32 +// error-pattern:location-divide-assign-by-zero.rs + +fn main() { + let mut a = 1; + a /= &0; +} diff --git a/tests/ui/numbers-arithmetic/location-divide-by-zero.rs b/tests/ui/numbers-arithmetic/location-divide-by-zero.rs new file mode 100644 index 00000000000..7d045fc5602 --- /dev/null +++ b/tests/ui/numbers-arithmetic/location-divide-by-zero.rs @@ -0,0 +1,9 @@ +// run-fail +// ignore-wasm32 +// error-pattern:location-divide-by-zero.rs + +// https://github.com/rust-lang/rust/issues/114814 + +fn main() { + let _ = 1 / &0; +} diff --git a/tests/ui/numbers-arithmetic/location-mod-assign-by-zero.rs b/tests/ui/numbers-arithmetic/location-mod-assign-by-zero.rs new file mode 100644 index 00000000000..88d602e4b6d --- /dev/null +++ b/tests/ui/numbers-arithmetic/location-mod-assign-by-zero.rs @@ -0,0 +1,8 @@ +// run-fail +// ignore-wasm32 +// error-pattern:location-mod-assign-by-zero.rs + +fn main() { + let mut a = 1; + a %= &0; +} diff --git a/tests/ui/numbers-arithmetic/location-mod-by-zero.rs b/tests/ui/numbers-arithmetic/location-mod-by-zero.rs new file mode 100644 index 00000000000..4397adb75d1 --- /dev/null +++ b/tests/ui/numbers-arithmetic/location-mod-by-zero.rs @@ -0,0 +1,7 @@ +// run-fail +// ignore-wasm32 +// error-pattern:location-mod-by-zero.rs + +fn main() { + let _ = 1 % &0; +} diff --git a/tests/ui/numbers-arithmetic/location-mul-assign-overflow.rs b/tests/ui/numbers-arithmetic/location-mul-assign-overflow.rs new file mode 100644 index 00000000000..b042751ded9 --- /dev/null +++ b/tests/ui/numbers-arithmetic/location-mul-assign-overflow.rs @@ -0,0 +1,8 @@ +// run-fail +// ignore-wasm32 +// error-pattern:location-mul-assign-overflow.rs + +fn main() { + let mut a: u8 = 255; + a *= &2; +} diff --git a/tests/ui/numbers-arithmetic/location-mul-overflow.rs b/tests/ui/numbers-arithmetic/location-mul-overflow.rs new file mode 100644 index 00000000000..6dd58874874 --- /dev/null +++ b/tests/ui/numbers-arithmetic/location-mul-overflow.rs @@ -0,0 +1,7 @@ +// run-fail +// ignore-wasm32 +// error-pattern:location-mul-overflow.rs + +fn main() { + let _: u8 = 255 * &2; +} diff --git a/tests/ui/numbers-arithmetic/location-sub-assign-overflow.rs b/tests/ui/numbers-arithmetic/location-sub-assign-overflow.rs new file mode 100644 index 00000000000..5b92ada2e0b --- /dev/null +++ b/tests/ui/numbers-arithmetic/location-sub-assign-overflow.rs @@ -0,0 +1,8 @@ +// run-fail +// ignore-wasm32 +// error-pattern:location-sub-assign-overflow.rs + +fn main() { + let mut a: u8 = 0; + a -= &1; +} diff --git a/tests/ui/numbers-arithmetic/location-sub-overflow.rs b/tests/ui/numbers-arithmetic/location-sub-overflow.rs new file mode 100644 index 00000000000..2d77cb8f55e --- /dev/null +++ b/tests/ui/numbers-arithmetic/location-sub-overflow.rs @@ -0,0 +1,7 @@ +// run-fail +// ignore-wasm32 +// error-pattern:location-sub-overflow.rs + +fn main() { + let _: u8 = 0 - &1; +} diff --git a/tests/ui/parser/issues/issue-68890.stderr b/tests/ui/parser/issues/issue-68890.stderr index 0d7b53a67c5..43ed69dcf24 100644 --- a/tests/ui/parser/issues/issue-68890.stderr +++ b/tests/ui/parser/issues/issue-68890.stderr @@ -8,7 +8,11 @@ error: expected one of `)`, `+`, or `,`, found `a` --> $DIR/issue-68890.rs:1:15 | LL | enum e{A((?'a a+?+l))} - | ^ expected one of `)`, `+`, or `,` + | - ^ expected one of `)`, `+`, or `,` + | | + | while parsing this enum + | + = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` error: expected item, found `)` --> $DIR/issue-68890.rs:1:21 diff --git a/tests/ui/parser/mut-patterns.rs b/tests/ui/parser/mut-patterns.rs index 8b83d6ab2f8..f2d2df0af29 100644 --- a/tests/ui/parser/mut-patterns.rs +++ b/tests/ui/parser/mut-patterns.rs @@ -27,7 +27,7 @@ pub fn main() { struct r#yield(u8, u8); let mut mut yield(become, await) = r#yield(0, 0); //~^ ERROR `mut` on a binding may not be repeated - //~| ERROR `mut` must be attached to each individual binding + //~| ERROR `mut` must be followed by a named binding //~| ERROR expected identifier, found reserved keyword `yield` //~| ERROR expected identifier, found reserved keyword `become` //~| ERROR expected identifier, found keyword `await` diff --git a/tests/ui/parser/mut-patterns.stderr b/tests/ui/parser/mut-patterns.stderr index 66985c9f5e4..6559cf09cdf 100644 --- a/tests/ui/parser/mut-patterns.stderr +++ b/tests/ui/parser/mut-patterns.stderr @@ -83,11 +83,11 @@ help: escape `await` to use it as an identifier LL | let mut mut yield(become, r#await) = r#yield(0, 0); | ++ -error: `mut` must be attached to each individual binding +error: `mut` must be followed by a named binding --> $DIR/mut-patterns.rs:28:9 | LL | let mut mut yield(become, await) = r#yield(0, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `mut` to each binding: `r#yield(mut r#become, mut r#await)` + | ^^^^^^^^ help: remove the `mut` prefix | = note: `mut` may be followed by `variable` and `variable @ pattern` diff --git a/tests/ui/parser/issues/issue-104088.rs b/tests/ui/parser/recover/binding-name-starting-with-number.rs index 3dc636b6a33..6b279c5539e 100644 --- a/tests/ui/parser/issues/issue-104088.rs +++ b/tests/ui/parser/recover/binding-name-starting-with-number.rs @@ -8,10 +8,12 @@ fn 1234test() { let 23name = 123; //~^ ERROR expected identifier, found `23name` - +} +fn foo() { let 2x: i32 = 123; //~^ ERROR expected identifier, found `2x` - +} +fn bar() { let 1x = 123; //~^ ERROR expected identifier, found `1x` } diff --git a/tests/ui/parser/issues/issue-104088.stderr b/tests/ui/parser/recover/binding-name-starting-with-number.stderr index 8b751759d69..de59a7de043 100644 --- a/tests/ui/parser/issues/issue-104088.stderr +++ b/tests/ui/parser/recover/binding-name-starting-with-number.stderr @@ -1,53 +1,53 @@ error: expected identifier, found `1234test` - --> $DIR/issue-104088.rs:1:4 + --> $DIR/binding-name-starting-with-number.rs:1:4 | LL | fn 1234test() { | ^^^^^^^^ expected identifier | help: identifiers cannot start with a number - --> $DIR/issue-104088.rs:1:4 + --> $DIR/binding-name-starting-with-number.rs:1:4 | LL | fn 1234test() { | ^^^^ error: expected identifier, found `23name` - --> $DIR/issue-104088.rs:9:9 + --> $DIR/binding-name-starting-with-number.rs:9:9 | LL | let 23name = 123; | ^^^^^^ expected identifier | help: identifiers cannot start with a number - --> $DIR/issue-104088.rs:9:9 + --> $DIR/binding-name-starting-with-number.rs:9:9 | LL | let 23name = 123; | ^^ error: expected identifier, found `2x` - --> $DIR/issue-104088.rs:12:9 + --> $DIR/binding-name-starting-with-number.rs:13:9 | LL | let 2x: i32 = 123; | ^^ expected identifier | help: identifiers cannot start with a number - --> $DIR/issue-104088.rs:12:9 + --> $DIR/binding-name-starting-with-number.rs:13:9 | LL | let 2x: i32 = 123; | ^ error: expected identifier, found `1x` - --> $DIR/issue-104088.rs:15:9 + --> $DIR/binding-name-starting-with-number.rs:17:9 | LL | let 1x = 123; | ^^ expected identifier | help: identifiers cannot start with a number - --> $DIR/issue-104088.rs:15:9 + --> $DIR/binding-name-starting-with-number.rs:17:9 | LL | let 1x = 123; | ^ error[E0308]: mismatched types - --> $DIR/issue-104088.rs:5:12 + --> $DIR/binding-name-starting-with-number.rs:5:12 | LL | if let 2e1 = 123 { | ^^^ --- this expression has type `{integer}` diff --git a/tests/ui/parser/recover/recover-enum2.rs b/tests/ui/parser/recover/recover-enum2.rs index 0c942088955..56b57f625ba 100644 --- a/tests/ui/parser/recover/recover-enum2.rs +++ b/tests/ui/parser/recover/recover-enum2.rs @@ -8,7 +8,7 @@ fn main() { } // recover... - let a = 1; + let () = 1; //~ ERROR mismatched types enum Test2 { Fine, } @@ -24,5 +24,6 @@ fn main() { enum Test4 { Nope(i32 {}) //~ ERROR: found `{` } + let () = 1; //~ ERROR mismatched types } } diff --git a/tests/ui/parser/recover/recover-enum2.stderr b/tests/ui/parser/recover/recover-enum2.stderr index 7634bca921c..132f84cc76b 100644 --- a/tests/ui/parser/recover/recover-enum2.stderr +++ b/tests/ui/parser/recover/recover-enum2.stderr @@ -9,8 +9,29 @@ LL | abc: {}, error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `{` --> $DIR/recover-enum2.rs:25:22 | +LL | enum Test4 { + | ----- while parsing this enum LL | Nope(i32 {}) | ^ expected one of 7 possible tokens + | + = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` + +error[E0308]: mismatched types + --> $DIR/recover-enum2.rs:11:9 + | +LL | let () = 1; + | ^^ - this expression has type `{integer}` + | | + | expected integer, found `()` + +error[E0308]: mismatched types + --> $DIR/recover-enum2.rs:27:13 + | +LL | let () = 1; + | ^^ - this expression has type `{integer}` + | | + | expected integer, found `()` -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/parser/recover/recover-for-loop-parens-around-head.fixed b/tests/ui/parser/recover/recover-for-loop-parens-around-head.fixed new file mode 100644 index 00000000000..6afc2d99355 --- /dev/null +++ b/tests/ui/parser/recover/recover-for-loop-parens-around-head.fixed @@ -0,0 +1,15 @@ +// run-rustfix +// Here we test that the parser is able to recover in a situation like +// `for ( $pat in $expr )` since that is familiar syntax in other languages. +// Instead we suggest that the user writes `for $pat in $expr`. + +#![deny(unused)] // Make sure we don't trigger `unused_parens`. + +fn main() { + let vec = vec![1, 2, 3]; + + for _elem in vec { + //~^ ERROR unexpected parentheses surrounding `for` loop head + const _RECOVERY_WITNESS: u32 = 0u32; //~ ERROR mismatched types + } +} diff --git a/tests/ui/parser/recover/recover-for-loop-parens-around-head.rs b/tests/ui/parser/recover/recover-for-loop-parens-around-head.rs index 053b428bd12..b1716900c49 100644 --- a/tests/ui/parser/recover/recover-for-loop-parens-around-head.rs +++ b/tests/ui/parser/recover/recover-for-loop-parens-around-head.rs @@ -1,3 +1,4 @@ +// run-rustfix // Here we test that the parser is able to recover in a situation like // `for ( $pat in $expr )` since that is familiar syntax in other languages. // Instead we suggest that the user writes `for $pat in $expr`. @@ -7,9 +8,8 @@ fn main() { let vec = vec![1, 2, 3]; - for ( elem in vec ) { - //~^ ERROR expected one of `)`, `,`, `@`, or `|`, found keyword `in` - //~| ERROR unexpected parentheses surrounding `for` loop head - const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types + for ( _elem in vec ) { + //~^ ERROR unexpected parentheses surrounding `for` loop head + const _RECOVERY_WITNESS: u32 = 0u8; //~ ERROR mismatched types } } diff --git a/tests/ui/parser/recover/recover-for-loop-parens-around-head.stderr b/tests/ui/parser/recover/recover-for-loop-parens-around-head.stderr index 3bad29f20af..beaa346e76c 100644 --- a/tests/ui/parser/recover/recover-for-loop-parens-around-head.stderr +++ b/tests/ui/parser/recover/recover-for-loop-parens-around-head.stderr @@ -1,27 +1,26 @@ -error: expected one of `)`, `,`, `@`, or `|`, found keyword `in` - --> $DIR/recover-for-loop-parens-around-head.rs:10:16 - | -LL | for ( elem in vec ) { - | ^^ expected one of `)`, `,`, `@`, or `|` - error: unexpected parentheses surrounding `for` loop head - --> $DIR/recover-for-loop-parens-around-head.rs:10:9 + --> $DIR/recover-for-loop-parens-around-head.rs:11:9 | -LL | for ( elem in vec ) { - | ^ ^ +LL | for ( _elem in vec ) { + | ^ ^ | help: remove parentheses in `for` loop | -LL - for ( elem in vec ) { -LL + for elem in vec { +LL - for ( _elem in vec ) { +LL + for _elem in vec { | error[E0308]: mismatched types - --> $DIR/recover-for-loop-parens-around-head.rs:13:38 + --> $DIR/recover-for-loop-parens-around-head.rs:13:40 + | +LL | const _RECOVERY_WITNESS: u32 = 0u8; + | ^^^ expected `u32`, found `u8` + | +help: change the type of the numeric literal from `u8` to `u32` | -LL | const RECOVERY_WITNESS: () = 0; - | ^ expected `()`, found integer +LL | const _RECOVERY_WITNESS: u32 = 0u32; + | ~~~ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/parser/recover/recover-parens-around-match-arm-head.fixed b/tests/ui/parser/recover/recover-parens-around-match-arm-head.fixed new file mode 100644 index 00000000000..6b9b7fa882a --- /dev/null +++ b/tests/ui/parser/recover/recover-parens-around-match-arm-head.fixed @@ -0,0 +1,12 @@ +// run-rustfix +fn main() { + let val = 42; + let x = match val { + 0 if true => { + //~^ ERROR unexpected parentheses surrounding `match` arm pattern + 42u8 + } + _ => 0u8, + }; + let _y: u32 = x.into(); //~ ERROR mismatched types +} diff --git a/tests/ui/parser/recover/recover-parens-around-match-arm-head.rs b/tests/ui/parser/recover/recover-parens-around-match-arm-head.rs index 9ed733bf079..f523581e2da 100644 --- a/tests/ui/parser/recover/recover-parens-around-match-arm-head.rs +++ b/tests/ui/parser/recover/recover-parens-around-match-arm-head.rs @@ -1,11 +1,9 @@ +// run-rustfix fn main() { let val = 42; let x = match val { (0 if true) => { - //~^ ERROR expected identifier, found keyword `if` - //~| ERROR expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found keyword `if` - //~| ERROR expected one of `)`, `,`, `@`, or `|`, found keyword `true` - //~| ERROR mismatched types + //~^ ERROR unexpected parentheses surrounding `match` arm pattern 42u8 } _ => 0u8, diff --git a/tests/ui/parser/recover/recover-parens-around-match-arm-head.stderr b/tests/ui/parser/recover/recover-parens-around-match-arm-head.stderr index 6542f440e4b..bad4d7d2f19 100644 --- a/tests/ui/parser/recover/recover-parens-around-match-arm-head.stderr +++ b/tests/ui/parser/recover/recover-parens-around-match-arm-head.stderr @@ -1,38 +1,17 @@ -error: expected identifier, found keyword `if` - --> $DIR/recover-parens-around-match-arm-head.rs:4:12 +error: unexpected parentheses surrounding `match` arm pattern + --> $DIR/recover-parens-around-match-arm-head.rs:5:9 | LL | (0 if true) => { - | ^^ expected identifier, found keyword - -error: expected one of `)`, `,`, `...`, `..=`, `..`, or `|`, found keyword `if` - --> $DIR/recover-parens-around-match-arm-head.rs:4:12 - | -LL | (0 if true) => { - | -^^ expected one of `)`, `,`, `...`, `..=`, `..`, or `|` - | | - | help: missing `,` - -error: expected one of `)`, `,`, `@`, or `|`, found keyword `true` - --> $DIR/recover-parens-around-match-arm-head.rs:4:15 + | ^ ^ | -LL | (0 if true) => { - | -^^^^ expected one of `)`, `,`, `@`, or `|` - | | - | help: missing `,` - -error[E0308]: mismatched types - --> $DIR/recover-parens-around-match-arm-head.rs:4:9 +help: remove parentheses surrounding the pattern | -LL | let x = match val { - | --- this expression has type `{integer}` -LL | (0 if true) => { - | ^^^^^^^^^^^ expected integer, found `(_, _, _)` +LL - (0 if true) => { +LL + 0 if true => { | - = note: expected type `{integer}` - found tuple `(_, _, _)` error[E0308]: mismatched types - --> $DIR/recover-parens-around-match-arm-head.rs:13:19 + --> $DIR/recover-parens-around-match-arm-head.rs:11:19 | LL | let _y: u32 = x; | --- ^ expected `u32`, found `u8` @@ -44,6 +23,6 @@ help: you can convert a `u8` to a `u32` LL | let _y: u32 = x.into(); | +++++++ -error: aborting due to 5 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/never_patterns.rs b/tests/ui/pattern/never_patterns.rs new file mode 100644 index 00000000000..e2e17e0e9a7 --- /dev/null +++ b/tests/ui/pattern/never_patterns.rs @@ -0,0 +1,99 @@ +#![feature(never_patterns)] +#![allow(incomplete_features)] + +enum Void {} + +fn main() {} + +// The classic use for empty types. +fn safe_unwrap_result<T>(res: Result<T, Void>) { + let Ok(_x) = res; + // FIXME(never_patterns): These should be allowed + let (Ok(_x) | Err(!)) = &res; + //~^ ERROR: is not bound in all patterns + let (Ok(_x) | Err(&!)) = res.as_ref(); + //~^ ERROR: is not bound in all patterns +} + +// Check we only accept `!` where we want to. +fn never_pattern_location(void: Void) { + // FIXME(never_patterns): Don't accept on a non-empty type. + match Some(0) { + None => {} + Some(!) => {} + } + // FIXME(never_patterns): Don't accept on an arbitrary type, even if there are no more branches. + match () { + () => {} + ! => {} + } + // FIXME(never_patterns): Don't accept even on an empty branch. + match None::<Void> { + None => {} + ! => {} + } + // FIXME(never_patterns): Let alone if the emptiness is behind a reference. + match None::<&Void> { + None => {} + ! => {} + } + // Participate in match ergonomics. + match &void { + ! => {} + } + match &&void { + ! => {} + } + match &&void { + &! => {} + } + match &None::<Void> { + None => {} + Some(!) => {} + } + match None::<&Void> { + None => {} + Some(!) => {} + } + // Accept on a composite empty type. + match None::<&(u32, Void)> { + None => {} + Some(&!) => {} + } + // Accept on an simple empty type. + match None::<Void> { + None => {} + Some(!) => {} + } + match None::<&Void> { + None => {} + Some(&!) => {} + } + match None::<&(u32, Void)> { + None => {} + Some(&(_, !)) => {} + } +} + +fn never_and_bindings() { + let x: Result<bool, &(u32, Void)> = Ok(false); + + // FIXME(never_patterns): Never patterns in or-patterns don't need to share the same bindings. + match x { + Ok(_x) | Err(&!) => {} + //~^ ERROR: is not bound in all patterns + } + let (Ok(_x) | Err(&!)) = x; + //~^ ERROR: is not bound in all patterns + + // FIXME(never_patterns): A never pattern mustn't have bindings. + match x { + Ok(_) => {} + Err(&(_b, !)) => {} + } + match x { + Ok(_a) | Err(&(_b, !)) => {} + //~^ ERROR: is not bound in all patterns + //~| ERROR: is not bound in all patterns + } +} diff --git a/tests/ui/pattern/never_patterns.stderr b/tests/ui/pattern/never_patterns.stderr new file mode 100644 index 00000000000..11e50debfd3 --- /dev/null +++ b/tests/ui/pattern/never_patterns.stderr @@ -0,0 +1,51 @@ +error[E0408]: variable `_x` is not bound in all patterns + --> $DIR/never_patterns.rs:12:19 + | +LL | let (Ok(_x) | Err(!)) = &res; + | -- ^^^^^^ pattern doesn't bind `_x` + | | + | variable not in all patterns + +error[E0408]: variable `_x` is not bound in all patterns + --> $DIR/never_patterns.rs:14:19 + | +LL | let (Ok(_x) | Err(&!)) = res.as_ref(); + | -- ^^^^^^^ pattern doesn't bind `_x` + | | + | variable not in all patterns + +error[E0408]: variable `_x` is not bound in all patterns + --> $DIR/never_patterns.rs:83:18 + | +LL | Ok(_x) | Err(&!) => {} + | -- ^^^^^^^ pattern doesn't bind `_x` + | | + | variable not in all patterns + +error[E0408]: variable `_x` is not bound in all patterns + --> $DIR/never_patterns.rs:86:19 + | +LL | let (Ok(_x) | Err(&!)) = x; + | -- ^^^^^^^ pattern doesn't bind `_x` + | | + | variable not in all patterns + +error[E0408]: variable `_b` is not bound in all patterns + --> $DIR/never_patterns.rs:95:9 + | +LL | Ok(_a) | Err(&(_b, !)) => {} + | ^^^^^^ -- variable not in all patterns + | | + | pattern doesn't bind `_b` + +error[E0408]: variable `_a` is not bound in all patterns + --> $DIR/never_patterns.rs:95:18 + | +LL | Ok(_a) | Err(&(_b, !)) => {} + | -- ^^^^^^^^^^^^^ pattern doesn't bind `_a` + | | + | variable not in all patterns + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0408`. diff --git a/tests/ui/pattern/pattern-bad-ref-box-order.fixed b/tests/ui/pattern/pattern-bad-ref-box-order.fixed new file mode 100644 index 00000000000..8825744a08b --- /dev/null +++ b/tests/ui/pattern/pattern-bad-ref-box-order.fixed @@ -0,0 +1,14 @@ +// run-rustfix + +#![feature(box_patterns)] +#![allow(dead_code)] + +fn foo(f: Option<Box<i32>>) { + match f { + Some(box ref _i) => {}, + //~^ ERROR switch the order of `ref` and `box` + None => {} + } +} + +fn main() { } diff --git a/tests/ui/pattern/pattern-bad-ref-box-order.rs b/tests/ui/pattern/pattern-bad-ref-box-order.rs new file mode 100644 index 00000000000..f3fcf0ceacf --- /dev/null +++ b/tests/ui/pattern/pattern-bad-ref-box-order.rs @@ -0,0 +1,14 @@ +// run-rustfix + +#![feature(box_patterns)] +#![allow(dead_code)] + +fn foo(f: Option<Box<i32>>) { + match f { + Some(ref box _i) => {}, + //~^ ERROR switch the order of `ref` and `box` + None => {} + } +} + +fn main() { } diff --git a/tests/ui/pattern/pattern-bad-ref-box-order.stderr b/tests/ui/pattern/pattern-bad-ref-box-order.stderr new file mode 100644 index 00000000000..a49f05c1028 --- /dev/null +++ b/tests/ui/pattern/pattern-bad-ref-box-order.stderr @@ -0,0 +1,8 @@ +error: switch the order of `ref` and `box` + --> $DIR/pattern-bad-ref-box-order.rs:8:14 + | +LL | Some(ref box _i) => {}, + | ^^^^^^^ help: swap them: `box ref` + +error: aborting due to 1 previous error + diff --git a/tests/ui/repr/issue-83921-ice.rs b/tests/ui/repr/malformed-repr-hints.rs index 70583eb9bd3..27840b5f835 100644 --- a/tests/ui/repr/issue-83921-ice.rs +++ b/tests/ui/repr/malformed-repr-hints.rs @@ -19,6 +19,15 @@ struct S3; //~^ ERROR: incorrect `repr(align)` attribute format struct S4; +// Regression test for issue #118334: +#[repr(Rust(u8))] +//~^ ERROR: invalid representation hint +#[repr(Rust(0))] +//~^ ERROR: invalid representation hint +#[repr(Rust = 0)] +//~^ ERROR: invalid representation hint +struct S5; + #[repr(i8())] //~^ ERROR: invalid representation hint enum E1 { A, B } diff --git a/tests/ui/repr/issue-83921-ice.stderr b/tests/ui/repr/malformed-repr-hints.stderr index 32c450410ea..6fb92755761 100644 --- a/tests/ui/repr/issue-83921-ice.stderr +++ b/tests/ui/repr/malformed-repr-hints.stderr @@ -1,46 +1,64 @@ error[E0552]: incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all - --> $DIR/issue-83921-ice.rs:6:8 + --> $DIR/malformed-repr-hints.rs:6:8 | LL | #[repr(packed())] | ^^^^^^^^ error[E0589]: invalid `repr(align)` attribute: `align` needs an argument - --> $DIR/issue-83921-ice.rs:10:8 + --> $DIR/malformed-repr-hints.rs:10:8 | LL | #[repr(align)] | ^^^^^ help: supply an argument here: `align(...)` error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses - --> $DIR/issue-83921-ice.rs:14:8 + --> $DIR/malformed-repr-hints.rs:14:8 | LL | #[repr(align(2, 4))] | ^^^^^^^^^^^ error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses - --> $DIR/issue-83921-ice.rs:18:8 + --> $DIR/malformed-repr-hints.rs:18:8 | LL | #[repr(align())] | ^^^^^^^ +error[E0552]: invalid representation hint: `Rust` does not take a parenthesized argument list + --> $DIR/malformed-repr-hints.rs:23:8 + | +LL | #[repr(Rust(u8))] + | ^^^^^^^^ + +error[E0552]: invalid representation hint: `Rust` does not take a parenthesized argument list + --> $DIR/malformed-repr-hints.rs:25:8 + | +LL | #[repr(Rust(0))] + | ^^^^^^^ + +error[E0552]: invalid representation hint: `Rust` does not take a value + --> $DIR/malformed-repr-hints.rs:27:8 + | +LL | #[repr(Rust = 0)] + | ^^^^^^^^ + error[E0552]: invalid representation hint: `i8` does not take a parenthesized argument list - --> $DIR/issue-83921-ice.rs:22:8 + --> $DIR/malformed-repr-hints.rs:31:8 | LL | #[repr(i8())] | ^^^^ error[E0552]: invalid representation hint: `u32` does not take a parenthesized argument list - --> $DIR/issue-83921-ice.rs:26:8 + --> $DIR/malformed-repr-hints.rs:35:8 | LL | #[repr(u32(42))] | ^^^^^^^ error[E0552]: invalid representation hint: `i64` does not take a value - --> $DIR/issue-83921-ice.rs:30:8 + --> $DIR/malformed-repr-hints.rs:39:8 | LL | #[repr(i64 = 2)] | ^^^^^^^ -error: aborting due to 7 previous errors +error: aborting due to 10 previous errors Some errors have detailed explanations: E0552, E0589, E0693. For more information about an error, try `rustc --explain E0552`. diff --git a/tests/ui/resolve/resolve-dont-hint-macro.rs b/tests/ui/resolve/resolve-dont-hint-macro.rs new file mode 100644 index 00000000000..da1752b337e --- /dev/null +++ b/tests/ui/resolve/resolve-dont-hint-macro.rs @@ -0,0 +1,4 @@ +fn main() { + let zero = assert_eq::<()>(); + //~^ ERROR expected function, found macro `assert_eq` +} diff --git a/tests/ui/resolve/resolve-dont-hint-macro.stderr b/tests/ui/resolve/resolve-dont-hint-macro.stderr new file mode 100644 index 00000000000..597e014d255 --- /dev/null +++ b/tests/ui/resolve/resolve-dont-hint-macro.stderr @@ -0,0 +1,9 @@ +error[E0423]: expected function, found macro `assert_eq` + --> $DIR/resolve-dont-hint-macro.rs:2:16 + | +LL | let zero = assert_eq::<()>(); + | ^^^^^^^^^^^^^^^ not a function + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0423`. diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr index 0ef7b8b09f1..cabc475fa61 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr @@ -1,83 +1,115 @@ error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:23:5 + --> $DIR/safe-calls.rs:28:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: sse2 + = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:26:5 + --> $DIR/safe-calls.rs:31:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:29:5 + --> $DIR/safe-calls.rs:34:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:36:5 + --> $DIR/safe-calls.rs:41:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:39:5 + --> $DIR/safe-calls.rs:44:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:46:5 + --> $DIR/safe-calls.rs:51:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: sse2 + = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:49:5 + --> $DIR/safe-calls.rs:54:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: bmi2 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:52:5 + --> $DIR/safe-calls.rs:57:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: bmi2 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:60:5 + --> $DIR/safe-calls.rs:65:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: sse2 + = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:65:18 + --> $DIR/safe-calls.rs:70:15 | -LL | const name: () = sse2(); - | ^^^^^^ call to function with `#[target_feature]` +LL | const _: () = sse2(); + | ^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: sse2 + = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` -error: aborting due to 10 previous errors +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:74:15 + | +LL | const _: () = sse2_and_fxsr(); + | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` + | + = help: in order for the call to be safe, the context requires the following additional target features: sse2 and fxsr + = note: the fxsr and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]` + +error: call to function with `#[target_feature]` is unsafe and requires unsafe block (error E0133) + --> $DIR/safe-calls.rs:82:5 + | +LL | sse2(); + | ^^^^^^ call to function with `#[target_feature]` + | + = help: in order for the call to be safe, the context requires the following additional target feature: sse2 + = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` +note: an unsafe function restricts its caller, but its body is safe by default + --> $DIR/safe-calls.rs:81:1 + | +LL | unsafe fn needs_unsafe_block() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/safe-calls.rs:78:8 + | +LL | #[deny(unsafe_op_in_unsafe_fn)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs index cebc6f94784..f17dab269bc 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs @@ -7,6 +7,11 @@ #[target_feature(enable = "sse2")] const fn sse2() {} +#[target_feature(enable = "sse2")] +#[target_feature(enable = "fxsr")] +const fn sse2_and_fxsr() {} + + #[target_feature(enable = "avx")] #[target_feature(enable = "bmi2")] fn avx_bmi2() {} @@ -62,8 +67,21 @@ fn qux() { //[thir]~^^ ERROR call to function `sse2` with `#[target_feature]` is unsafe } -const name: () = sse2(); +const _: () = sse2(); //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe //[thir]~^^ ERROR call to function `sse2` with `#[target_feature]` is unsafe +const _: () = sse2_and_fxsr(); +//[mir]~^ ERROR call to function with `#[target_feature]` is unsafe +//[thir]~^^ ERROR call to function `sse2_and_fxsr` with `#[target_feature]` is unsafe + +#[deny(unsafe_op_in_unsafe_fn)] +#[target_feature(enable = "avx")] +#[target_feature(enable = "bmi2")] +unsafe fn needs_unsafe_block() { + sse2(); + //[mir]~^ ERROR call to function with `#[target_feature]` is unsafe + //[thir]~^^ ERROR call to function `sse2` with `#[target_feature]` is unsafe +} + fn main() {} diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr index c75ac6e8b9a..13b58fde862 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr @@ -1,83 +1,115 @@ error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:23:5 + --> $DIR/safe-calls.rs:28:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: sse2 + = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:26:5 + --> $DIR/safe-calls.rs:31:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:29:5 + --> $DIR/safe-calls.rs:34:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:36:5 + --> $DIR/safe-calls.rs:41:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:39:5 + --> $DIR/safe-calls.rs:44:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2 error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:46:5 + --> $DIR/safe-calls.rs:51:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: sse2 + = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:49:5 + --> $DIR/safe-calls.rs:54:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: bmi2 error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:52:5 + --> $DIR/safe-calls.rs:57:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: bmi2 error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:60:5 + --> $DIR/safe-calls.rs:65:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: sse2 + = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:65:18 + --> $DIR/safe-calls.rs:70:15 | -LL | const name: () = sse2(); - | ^^^^^^ call to function with `#[target_feature]` +LL | const _: () = sse2(); + | ^^^^^^ call to function with `#[target_feature]` | - = note: can only be called if the required target features are available + = help: in order for the call to be safe, the context requires the following additional target feature: sse2 + = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` -error: aborting due to 10 previous errors +error[E0133]: call to function `sse2_and_fxsr` with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:74:15 + | +LL | const _: () = sse2_and_fxsr(); + | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` + | + = help: in order for the call to be safe, the context requires the following additional target features: sse2 and fxsr + = note: the fxsr and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]` + +error: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe block (error E0133) + --> $DIR/safe-calls.rs:82:5 + | +LL | sse2(); + | ^^^^^^ call to function with `#[target_feature]` + | + = help: in order for the call to be safe, the context requires the following additional target feature: sse2 + = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]` +note: an unsafe function restricts its caller, but its body is safe by default + --> $DIR/safe-calls.rs:81:1 + | +LL | unsafe fn needs_unsafe_block() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/safe-calls.rs:78:8 + | +LL | #[deny(unsafe_op_in_unsafe_fn)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.stderr index 247fad2e992..f3726166eba 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.stderr @@ -29,6 +29,10 @@ LL | if let Some(elem) = _opt && [1, 2, 3][let _ = &&let Some(x) = Some( | ^^^^^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions +help: you might have meant to compare for equality + | +LL | if let Some(elem) = _opt && [1, 2, 3][let _ = &&let Some(x) = Some(42)] == 1 { + | + error: expected expression, found `let` statement --> $DIR/invalid-let-in-a-valid-let-context.rs:24:23 @@ -53,6 +57,10 @@ LL | if let Some(elem) = _opt && [1, 2, 3][let _ = ()] = 1 { | ^^^^^^^^^^^^^^^^^^^^^ | = note: only supported directly in conditions of `if` and `while` expressions +help: you might have meant to compare for equality + | +LL | if let Some(elem) = _opt && [1, 2, 3][let _ = ()] == 1 { + | + error: expected expression, found `let` statement --> $DIR/invalid-let-in-a-valid-let-context.rs:42:21 diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs index eada4ceafe9..b9331caaf8e 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs @@ -1,7 +1,4 @@ -// check-pass -// known-bug: #110395 - -#![feature(const_trait_impl)] +#![feature(const_trait_impl, effects)] struct S; @@ -24,6 +21,7 @@ const fn equals_self<T: ~const Foo>(t: &T) -> bool { // it not using the impl. pub const EQ: bool = equals_self(&S); -// FIXME(effects) ~^ ERROR +//~^ ERROR +// FIXME(effects) the diagnostics here isn't ideal, we shouldn't get `<false>` fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr new file mode 100644 index 00000000000..4fe296d4d3f --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `S: ~const Foo<false>` is not satisfied + --> $DIR/call-generic-method-nonconst.rs:23:34 + | +LL | pub const EQ: bool = equals_self(&S); + | ----------- ^^ the trait `Foo<false>` is not implemented for `S` + | | + | required by a bound introduced by this call + | + = help: the trait `Foo` is implemented for `S` +note: required by a bound in `equals_self` + --> $DIR/call-generic-method-nonconst.rs:16:25 + | +LL | const fn equals_self<T: ~const Foo>(t: &T) -> bool { + | ^^^^^^^^^^ required by this bound in `equals_self` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs index c38b4b3f1a2..ecf45c97dcd 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,7 +21,7 @@ trait Add<Rhs = Self> { fn add(self, rhs: Rhs) -> Self::Output; } -// FIXME we shouldn't need to have to specify `Rhs`. +// FIXME(effects) we shouldn't need to have to specify `Rhs`. impl const Add<i32> for i32 { type Output = i32; fn add(self, rhs: i32) -> i32 { @@ -344,6 +344,15 @@ trait PartialEq<Rhs: ?Sized = Self> { } } +impl<A: ?Sized, B: ?Sized> const PartialEq<&B> for &A +where + A: ~const PartialEq<B>, +{ + fn eq(&self, other: &&B) -> bool { + PartialEq::eq(*self, *other) + } +} + // FIXME(effects): again, this should not error without Rhs specified impl PartialEq<str> for str { fn eq(&self, other: &str) -> bool { 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 02429374218..461133e6c3e 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,32 +1,20 @@ -error[E0369]: cannot add `i32` to `i32` - --> $DIR/minicore.rs:33:20 +error[E0493]: destructor of `Self` cannot be evaluated at compile-time + --> $DIR/minicore.rs:503:9 | -LL | let x = 42_i32 + 43_i32; - | ------ ^ ------ i32 - | | - | i32 +LL | *self = source.clone() + | ^^^^^ + | | + | the destructor for this type cannot be evaluated in constant functions + | value is dropped here -error[E0369]: cannot add `i32` to `i32` - --> $DIR/minicore.rs:37:20 +error[E0493]: destructor of `T` cannot be evaluated at compile-time + --> $DIR/minicore.rs:513:35 | -LL | let x = 42_i32 + 43_i32; - | ------ ^ ------ i32 - | | - | i32 +LL | const fn drop<T: ~const Destruct>(_: T) {} + | ^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions -error[E0600]: cannot apply unary operator `!` to type `bool` - --> $DIR/minicore.rs:343:9 - | -LL | !self.eq(other) - | ^^^^^^^^^^^^^^^ cannot apply unary operator `!` - -error[E0600]: cannot apply unary operator `!` to type `bool` - --> $DIR/minicore.rs:365:9 - | -LL | !self - | ^^^^^ cannot apply unary operator `!` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0369, E0600. -For more information about an error, try `rustc --explain E0369`. +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/sanitize/cfg-kasan.rs b/tests/ui/sanitize/cfg-kasan.rs index d721011f3ee..fb9a6f549ce 100644 --- a/tests/ui/sanitize/cfg-kasan.rs +++ b/tests/ui/sanitize/cfg-kasan.rs @@ -8,10 +8,8 @@ //[aarch64] needs-llvm-components: aarch64 //[riscv64imac] compile-flags: --target riscv64imac-unknown-none-elf //[riscv64imac] needs-llvm-components: riscv -//[riscv64imac] min-llvm-version: 16 //[riscv64gc] compile-flags: --target riscv64gc-unknown-none-elf //[riscv64gc] needs-llvm-components: riscv -//[riscv64gc] min-llvm-version: 16 //[x86_64] compile-flags: --target x86_64-unknown-none //[x86_64] needs-llvm-components: x86 diff --git a/tests/ui/suggestions/non_ascii_ident.rs b/tests/ui/suggestions/non_ascii_ident.rs new file mode 100644 index 00000000000..679ac4bcb6e --- /dev/null +++ b/tests/ui/suggestions/non_ascii_ident.rs @@ -0,0 +1,4 @@ +fn main() { + // There shall be no suggestions here. In particular not `Ok`. + let _ = 读文; //~ ERROR cannot find value `读文` in this scope +} diff --git a/tests/ui/suggestions/non_ascii_ident.stderr b/tests/ui/suggestions/non_ascii_ident.stderr new file mode 100644 index 00000000000..79fca3e1f61 --- /dev/null +++ b/tests/ui/suggestions/non_ascii_ident.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `读文` in this scope + --> $DIR/non_ascii_ident.rs:3:13 + | +LL | let _ = 读文; + | ^^^^ not found in this scope + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/suggestions/range-index-instead-of-colon.rs b/tests/ui/suggestions/range-index-instead-of-colon.rs new file mode 100644 index 00000000000..3267527ecf2 --- /dev/null +++ b/tests/ui/suggestions/range-index-instead-of-colon.rs @@ -0,0 +1,7 @@ +// edition:2021 + +fn main() { + &[1, 2, 3][1:2]; + //~^ ERROR: expected one of + //~| HELP: you might have meant a range expression +} diff --git a/tests/ui/suggestions/range-index-instead-of-colon.stderr b/tests/ui/suggestions/range-index-instead-of-colon.stderr new file mode 100644 index 00000000000..df29356cc16 --- /dev/null +++ b/tests/ui/suggestions/range-index-instead-of-colon.stderr @@ -0,0 +1,13 @@ +error: expected one of `.`, `?`, `]`, or an operator, found `:` + --> $DIR/range-index-instead-of-colon.rs:4:17 + | +LL | &[1, 2, 3][1:2]; + | ^ expected one of `.`, `?`, `]`, or an operator + | +help: you might have meant a range expression + | +LL | &[1, 2, 3][1..2]; + | ~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/symbol-names/foreign-types.stderr b/tests/ui/symbol-names/foreign-types.stderr index 9c8633742b2..63044991485 100644 --- a/tests/ui/symbol-names/foreign-types.stderr +++ b/tests/ui/symbol-names/foreign-types.stderr @@ -1,4 +1,4 @@ -error: symbol-name(_RMCsCRATE_HASH_13foreign_typesINtB<REF>_5CheckNvB<REF>_11ForeignTypeE) +error: symbol-name(_RMCsCRATE_HASH_13foreign_typesINtB<REF>_5CheckNtB<REF>_11ForeignTypeE) --> $DIR/foreign-types.rs:13:1 | LL | #[rustc_symbol_name] diff --git a/triagebot.toml b/triagebot.toml index 593386288b4..ed9d59b1bb9 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -18,6 +18,7 @@ allow-unauthenticated = [ "relnotes", "requires-*", "regression-*", + "rla-*", "perf-*", "AsyncAwait-OnDeck", "needs-triage", |
