diff options
1513 files changed, 24112 insertions, 13005 deletions
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 8040cb22855..d23682596fd 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -18,3 +18,5 @@ b39a1d6f1a30ba29f25d7141038b9a5bf0126e36 f97fddab91fbf290ea5b691fe355d6f915220b6e # format let-else cc907f80b95c6ec530c5ee1b05b044a468f07eca +# format let-chains +b2d2184edea578109a48ec3d8decbee5948e8f35 diff --git a/.mailmap b/.mailmap index 26d6be9f0c6..c109074021d 100644 --- a/.mailmap +++ b/.mailmap @@ -346,7 +346,9 @@ Lindsey Kuper <lindsey@composition.al> <lindsey@rockstargirl.org> Lindsey Kuper <lindsey@composition.al> <lkuper@mozilla.com> Liu Dingming <liudingming@bytedance.com> Loo Maclin <loo.maclin@protonmail.com> -Loïc BRANSTETT <lolo.branstett@numericable.fr> +Urgau <urgau@numericable.fr> +Urgau <urgau@numericable.fr> <lolo.branstett@numericable.fr> +Urgau <urgau@numericable.fr> <3616612+Urgau@users.noreply.github.com> Lucy <luxx4x@protonmail.com> Lukas H. <lukaramu@users.noreply.github.com> Lukas Lueg <lukas.lueg@gmail.com> @@ -445,6 +447,8 @@ Oliver Scherer <oli-obk@users.noreply.github.com> <public.oliver.schneider@kit.e Oliver Scherer <oli-obk@users.noreply.github.com> <oliver.schneider@kit.edu> Oliver Scherer <oli-obk@users.noreply.github.com> <obk8176014uqher834@olio-obk.de> Oliver Scherer <oli-obk@users.noreply.github.com> +Onur Özkan <onurozkan.dev@outlook.com> <work@onurozkan.dev> +Onur Özkan <onurozkan.dev@outlook.com> Ömer Sinan Ağacan <omeragacan@gmail.com> Ophir LOJKINE <pere.jobs@gmail.com> Ožbolt Menegatti <ozbolt.menegatti@gmail.com> gareins <ozbolt.menegatti@gmail.com> diff --git a/Cargo.lock b/Cargo.lock index 082bb4be93c..c8e7665337f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -697,6 +697,7 @@ dependencies = [ "getopts", "glob", "home", + "indexmap 2.0.0", "lazycell", "libc", "miow", @@ -2150,9 +2151,9 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" [[package]] name = "libc" -version = "0.2.148" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" dependencies = [ "rustc-std-workspace-core", ] @@ -2245,9 +2246,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.7" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" [[package]] name = "litemap" @@ -2418,9 +2419,9 @@ dependencies = [ [[package]] name = "minifier" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb022374af2f446981254e6bf9efb6e2c9e1a53176d395fca02792fd4435729" +checksum = "5394aa376422b4b2b6c02fd9cfcb657e4ec544ae98e43d7d5d785fd0d042fd6d" [[package]] name = "minimal-lexical" @@ -2971,30 +2972,6 @@ dependencies = [ ] [[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] name = "proc-macro-hack" version = "0.5.20+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3650,6 +3627,7 @@ dependencies = [ "serde_json", "smallvec", "tempfile", + "thin-vec", "thorin-dwp", "tracing", "windows", @@ -4479,7 +4457,6 @@ dependencies = [ name = "rustc_session" version = "0.0.0" dependencies = [ - "bitflags 1.3.2", "getopts", "libc", "rustc_ast", @@ -4504,6 +4481,7 @@ dependencies = [ name = "rustc_smir" version = "0.0.0" dependencies = [ + "rustc_data_structures", "rustc_driver", "rustc_hir", "rustc_interface", @@ -4778,9 +4756,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.14" +version = "0.38.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" +checksum = "745ecfa778e66b2b63c88a61cb36e0eea109e803b0b86bf9879fbc77c70e86ed" dependencies = [ "bitflags 2.4.0", "errno", @@ -5081,7 +5059,6 @@ version = "0.0.0" dependencies = [ "addr2line", "alloc", - "cc", "cfg-if", "compiler_builtins", "core", @@ -5252,24 +5229,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d38d39c754ae037a9bc3ca1580a985db7371cd14f1229172d1db9093feb6739" dependencies = [ "papergrid", - "tabled_derive", "unicode-width", ] [[package]] -name = "tabled_derive" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99f688a08b54f4f02f0a3c382aefdb7884d3d69609f785bd253dc033243e3fe4" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] name = "tar" version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/RELEASES.md b/RELEASES.md index e261294a032..1cc110e6607 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -229,6 +229,7 @@ Compatibility Notes this should only impact users of other registries, or people who don't publish to a registry. [#12291](https://github.com/rust-lang/cargo/pull/12291) +- [Demoted `mips*-unknown-linux-gnu*` targets from host tier 2 to target tier 3 support.](https://github.com/rust-lang/rust/pull/113274) Version 1.71.1 (2023-08-03) =========================== diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 45b3e76cca6..3722a0774ba 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1,5 +1,7 @@ #![cfg_attr(feature = "nightly", feature(step_trait))] #![cfg_attr(feature = "nightly", allow(internal_features))] +#![cfg_attr(all(not(bootstrap), feature = "nightly"), doc(rust_logo))] +#![cfg_attr(all(not(bootstrap), feature = "nightly"), feature(rustdoc_internals))] use std::fmt; use std::num::{NonZeroUsize, ParseIntError}; @@ -681,6 +683,7 @@ impl fmt::Display for AlignFromBytesError { impl Align { pub const ONE: Align = Align { pow2: 0 }; + // LLVM has a maximal supported alignment of 2^29, we inherit that. pub const MAX: Align = Align { pow2: 29 }; #[inline] diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index bf8a7eb293e..54274f15356 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -11,6 +11,8 @@ html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(no_crate_inject, attr(deny(warnings))) )] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(new_uninit)] diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index db008ea139d..be7d1b207bc 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -197,10 +197,10 @@ impl Attribute { .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}")) .to_attr_token_stream() .to_tokenstream(), - &AttrKind::DocComment(comment_kind, data) => TokenStream::new(vec![TokenTree::Token( - Token::new(token::DocComment(comment_kind, self.style, data), self.span), - Spacing::Alone, - )]), + &AttrKind::DocComment(comment_kind, data) => TokenStream::token_alone( + token::DocComment(comment_kind, self.style, data), + self.span, + ), } } } @@ -520,9 +520,7 @@ impl NestedMetaItem { I: Iterator<Item = &'a TokenTree>, { match tokens.peek() { - Some(TokenTree::Token(token, _)) - if let Some(lit) = MetaItemLit::from_token(token) => - { + Some(TokenTree::Token(token, _)) if let Some(lit) = MetaItemLit::from_token(token) => { tokens.next(); return Some(NestedMetaItem::Lit(lit)); } diff --git a/compiler/rustc_ast/src/entry.rs b/compiler/rustc_ast/src/entry.rs index 2dd5e96e513..cd8a5a66920 100644 --- a/compiler/rustc_ast/src/entry.rs +++ b/compiler/rustc_ast/src/entry.rs @@ -21,7 +21,9 @@ pub fn entry_point_type( } else if attr::contains_name(attrs, sym::rustc_main) { EntryPointType::RustcMainAttr } else { - if let Some(name) = name && name == sym::main { + if let Some(name) = name + && name == sym::main + { if at_root { // This is a top-level function so it can be `main`. EntryPointType::MainNamed diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index b07ed1d1c74..ddc7c8ee825 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -8,6 +8,9 @@ html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(deny(warnings))) )] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), allow(internal_features))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![feature(associated_type_bounds)] #![feature(box_patterns)] #![feature(const_trait_impl)] diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 09bfbd02198..dd879a14567 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -107,13 +107,11 @@ impl Lit { /// Keep this in sync with `Token::can_begin_literal_or_bool` excluding unary negation. pub fn from_token(token: &Token) -> Option<Lit> { match token.uninterpolate().kind { - Ident(name, false) if name.is_bool_lit() => { - Some(Lit::new(Bool, name, None)) - } + Ident(name, false) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)), Literal(token_lit) => Some(token_lit), Interpolated(ref nt) if let NtExpr(expr) | NtLiteral(expr) = &**nt - && let ast::ExprKind::Lit(token_lit) = expr.kind => + && let ast::ExprKind::Lit(token_lit) = expr.kind => { Some(token_lit) } @@ -229,35 +227,61 @@ fn ident_can_begin_type(name: Symbol, span: Span, is_raw: bool) -> bool { #[derive(PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum TokenKind { /* Expression-operator symbols. */ + /// `=` Eq, + /// `<` Lt, + /// `<=` Le, + /// `==` EqEq, + /// `!=` Ne, + /// `>` Ge, + /// `>=` Gt, + /// `&&` AndAnd, + /// `||` OrOr, + /// `!` Not, + /// `~` Tilde, BinOp(BinOpToken), BinOpEq(BinOpToken), /* Structural symbols */ + /// `@` At, + /// `.` Dot, + /// `..` DotDot, + /// `...` DotDotDot, + /// `..=` DotDotEq, + /// `,` Comma, + /// `;` Semi, + /// `:` Colon, + /// `::` ModSep, + /// `->` RArrow, + /// `<-` LArrow, + /// `=>` FatArrow, + /// `#` Pound, + /// `$` Dollar, + /// `?` Question, /// Used by proc macros for representing lifetimes, not generated by lexer right now. SingleQuote, @@ -296,6 +320,7 @@ pub enum TokenKind { /// similarly to symbols in string literal tokens. DocComment(CommentKind, ast::AttrStyle, Symbol), + /// End Of File Eof, } @@ -404,7 +429,7 @@ impl Token { [DotDot, DotDotDot, DotDotEq].contains(&self.kind) } - pub fn is_op(&self) -> bool { + pub fn is_punct(&self) -> bool { match self.kind { Eq | Lt | Le | EqEq | Ne | Ge | Gt | AndAnd | OrOr | Not | Tilde | BinOp(_) | BinOpEq(_) | At | Dot | DotDot | DotDotDot | DotDotEq | Comma | Semi | Colon @@ -628,7 +653,9 @@ impl Token { /// Returns `true` if the token is an interpolated path. fn is_path(&self) -> bool { - if let Interpolated(nt) = &self.kind && let NtPath(..) = **nt { + if let Interpolated(nt) = &self.kind + && let NtPath(..) = **nt + { return true; } @@ -650,7 +677,9 @@ impl Token { /// Is the token an interpolated block (`$b:block`)? pub fn is_whole_block(&self) -> bool { - if let Interpolated(nt) = &self.kind && let NtBlock(..) = **nt { + if let Interpolated(nt) = &self.kind + && let NtBlock(..) = **nt + { return true; } diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 1e18b1232de..23b8f9c12d8 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -550,7 +550,9 @@ impl TokenStream { let stream_iter = stream.0.iter().cloned(); - if let Some(first) = stream.0.first() && Self::try_glue_to_last(vec_mut, first) { + if let Some(first) = stream.0.first() + && Self::try_glue_to_last(vec_mut, first) + { // Now skip the first token tree from `stream`. vec_mut.extend(stream_iter.skip(1)); } else { diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index aaeef1ff77d..b9fe99ac72f 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -136,12 +136,6 @@ ast_lowering_template_modifier = template modifier ast_lowering_this_not_async = this is not `async` -ast_lowering_trait_fn_async = - functions in traits cannot be declared `async` - .label = `async` because of this - .note = `async` trait functions are not currently supported - .note2 = consider using the `async-trait` crate: https://crates.io/crates/async-trait - ast_lowering_underscore_expr_lhs_assign = in expressions, `_` can only be used on the left-hand side of an assignment .label = `_` not allowed here diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index a63bd4f8a02..fe0c7d101c1 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -354,17 +354,6 @@ pub struct InclusiveRangeWithNoEnd { pub span: Span, } -#[derive(Diagnostic, Clone, Copy)] -#[diag(ast_lowering_trait_fn_async, code = "E0706")] -#[note] -#[note(ast_lowering_note2)] -pub struct TraitFnAsync { - #[primary_span] - pub fn_span: Span, - #[label] - pub span: Span, -} - #[derive(Diagnostic)] pub enum BadReturnTypeNotation { #[diag(ast_lowering_bad_return_type_notation_inputs)] diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 57c54f8540c..dda23028222 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -673,12 +673,18 @@ impl<'hir> LoweringContext<'_, 'hir> { && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id) && attrs.into_iter().any(|attr| attr.has_name(sym::track_caller)) { - 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, + self.allow_gen_future.clone(), + ); self.lower_attrs( inner_hir_id, &[Attribute { - kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new(sym::track_caller, span)))), + kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new( + sym::track_caller, + span, + )))), id: self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id(), style: AttrStyle::Outer, span: unstable_span, @@ -1102,7 +1108,9 @@ impl<'hir> LoweringContext<'_, 'hir> { if let ExprKind::Path(qself, path) = &expr.kind { // Does the path resolve to something disallowed in a tuple struct/variant pattern? if let Some(partial_res) = self.resolver.get_partial_res(expr.id) { - if let Some(res) = partial_res.full_res() && !res.expected_in_tuple_struct_pat() { + if let Some(res) = partial_res.full_res() + && !res.expected_in_tuple_struct_pat() + { return None; } } @@ -1122,7 +1130,9 @@ impl<'hir> LoweringContext<'_, 'hir> { if let ExprKind::Path(qself, path) = &expr.kind { // Does the path resolve to something disallowed in a unit struct/variant pattern? if let Some(partial_res) = self.resolver.get_partial_res(expr.id) { - if let Some(res) = partial_res.full_res() && !res.expected_in_unit_struct_pat() { + if let Some(res) = partial_res.full_res() + && !res.expected_in_unit_struct_pat() + { return None; } } diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 45a9bebfcf6..c7d0719e71a 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -61,9 +61,12 @@ fn flatten_format_args(mut fmt: Cow<'_, FormatArgs>) -> Cow<'_, FormatArgs> { let remaining_args = args.split_off(arg_index + 1); let old_arg_offset = args.len(); let mut fmt2 = &mut args.pop().unwrap().expr; // The inner FormatArgs. - let fmt2 = loop { // Unwrap the Expr to get to the FormatArgs. + let fmt2 = loop { + // Unwrap the Expr to get to the FormatArgs. match &mut fmt2.kind { - ExprKind::Paren(inner) | ExprKind::AddrOf(BorrowKind::Ref, _, inner) => fmt2 = inner, + ExprKind::Paren(inner) | ExprKind::AddrOf(BorrowKind::Ref, _, inner) => { + fmt2 = inner + } ExprKind::FormatArgs(fmt2) => break fmt2, _ => unreachable!(), } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index edc1e2f0b84..b73f21433e1 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1387,10 +1387,12 @@ impl<'hir> LoweringContext<'_, 'hir> { // Desugar `~const` bound in generics into an additional `const host: bool` param // if the effects feature is enabled. This needs to be done before we lower where // clauses since where clauses need to bind to the DefId of the host param - let host_param_parts = if let Const::Yes(span) = constness && self.tcx.features().effects { - if let Some(param) = generics.params.iter().find(|x| { - x.attrs.iter().any(|x| x.has_name(sym::rustc_host)) - }) { + let host_param_parts = if let Const::Yes(span) = constness + && self.tcx.features().effects + { + if let Some(param) = + generics.params.iter().find(|x| x.attrs.iter().any(|x| x.has_name(sym::rustc_host))) + { // user has manually specified a `rustc_host` param, in this case, we set // the param id so that lowering logic can use that. But we don't create // another host param, so this gives `None`. @@ -1399,7 +1401,12 @@ impl<'hir> LoweringContext<'_, 'hir> { } else { let param_node_id = self.next_node_id(); let hir_id = self.next_id(); - let def_id = self.create_def(self.local_def_id(parent_node_id), param_node_id, DefPathData::TypeNs(sym::host), span); + let def_id = self.create_def( + self.local_def_id(parent_node_id), + param_node_id, + DefPathData::TypeNs(sym::host), + span, + ); self.host_param_id = Some(def_id); Some((span, hir_id, def_id)) } @@ -1623,12 +1630,10 @@ impl<'hir> LoweringContext<'_, 'hir> { .lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder), bounded_ty: self .lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), - bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| { - self.lower_param_bound( - bound, - &ImplTraitContext::Disallowed(ImplTraitPosition::Bound), - ) - })), + bounds: self.lower_param_bounds( + bounds, + &ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ), span: self.lower_span(*span), origin: PredicateOrigin::WhereClause, }), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 7e3ada9c123..68567f97eab 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -30,6 +30,9 @@ //! get confused if the spans from leaf AST nodes occur in multiple places //! in the HIR, especially for multiple identifiers. +#![cfg_attr(not(bootstrap), allow(internal_features))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), doc(rust_logo))] #![feature(box_patterns)] #![feature(let_chains)] #![feature(never_type)] @@ -40,7 +43,7 @@ #[macro_use] extern crate tracing; -use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait, TraitFnAsync}; +use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait}; use rustc_ast::ptr::P; use rustc_ast::visit; @@ -271,8 +274,6 @@ enum ImplTraitPosition { ClosureReturn, PointerReturn, FnTraitReturn, - TraitReturn, - ImplReturn, GenericDefault, ConstTy, StaticTy, @@ -302,8 +303,6 @@ impl std::fmt::Display for ImplTraitPosition { ImplTraitPosition::ClosureReturn => "closure return types", ImplTraitPosition::PointerReturn => "`fn` pointer return types", ImplTraitPosition::FnTraitReturn => "`Fn` trait return types", - ImplTraitPosition::TraitReturn => "trait method return types", - ImplTraitPosition::ImplReturn => "`impl` method return types", ImplTraitPosition::GenericDefault => "generic parameter defaults", ImplTraitPosition::ConstTy => "const types", ImplTraitPosition::StaticTy => "static types", @@ -334,20 +333,9 @@ impl FnDeclKind { matches!(self, FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait) } - fn return_impl_trait_allowed(&self, tcx: TyCtxt<'_>) -> bool { + fn return_impl_trait_allowed(&self) -> bool { match self { - FnDeclKind::Fn | FnDeclKind::Inherent => true, - FnDeclKind::Impl if tcx.features().return_position_impl_trait_in_trait => true, - FnDeclKind::Trait if tcx.features().return_position_impl_trait_in_trait => true, - _ => false, - } - } - - fn async_fn_allowed(&self, tcx: TyCtxt<'_>) -> bool { - match self { - FnDeclKind::Fn | FnDeclKind::Inherent => true, - FnDeclKind::Impl if tcx.features().async_fn_in_trait => true, - FnDeclKind::Trait if tcx.features().async_fn_in_trait => true, + FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait => true, _ => false, } } @@ -1271,7 +1259,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &PolyTraitRef { bound_generic_params: ThinVec::new(), trait_ref: TraitRef { path: path.clone(), ref_id: t.id }, - span: t.span + span: t.span, }, itctx, ast::Const::No, @@ -1805,53 +1793,30 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_ty_direct(¶m.ty, &itctx) })); - let output = if let Some((ret_id, span)) = make_ret_async { - if !kind.async_fn_allowed(self.tcx) { - match kind { - FnDeclKind::Trait | FnDeclKind::Impl => { - self.tcx - .sess - .create_feature_err( - TraitFnAsync { fn_span, span }, - sym::async_fn_in_trait, - ) - .emit(); - } - _ => { - self.tcx.sess.emit_err(TraitFnAsync { fn_span, span }); - } - } - } - + let output = if let Some((ret_id, _span)) = make_ret_async { let fn_def_id = self.local_def_id(fn_node_id); self.lower_async_fn_ret_ty(&decl.output, fn_def_id, ret_id, kind, fn_span) } else { match &decl.output { FnRetTy::Ty(ty) => { - let context = if kind.return_impl_trait_allowed(self.tcx) { + let context = if kind.return_impl_trait_allowed() { let fn_def_id = self.local_def_id(fn_node_id); ImplTraitContext::ReturnPositionOpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), fn_kind: kind, } } else { - let position = match kind { - FnDeclKind::Fn | FnDeclKind::Inherent => { - unreachable!("fn should allow in-band lifetimes") + ImplTraitContext::Disallowed(match kind { + FnDeclKind::Fn + | FnDeclKind::Inherent + | FnDeclKind::Trait + | FnDeclKind::Impl => { + unreachable!("fn should allow return-position impl trait in traits") } FnDeclKind::ExternFn => ImplTraitPosition::ExternFnReturn, FnDeclKind::Closure => ImplTraitPosition::ClosureReturn, FnDeclKind::Pointer => ImplTraitPosition::PointerReturn, - FnDeclKind::Trait => ImplTraitPosition::TraitReturn, - FnDeclKind::Impl => ImplTraitPosition::ImplReturn, - }; - match kind { - FnDeclKind::Trait | FnDeclKind::Impl => ImplTraitContext::FeatureGated( - position, - sym::return_position_impl_trait_in_trait, - ), - _ => ImplTraitContext::Disallowed(position), - } + }) }; hir::FnRetTy::Return(self.lower_ty(ty, &context)) } @@ -1924,18 +1889,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let future_bound = this.lower_async_fn_output_type_to_future_bound( output, span, - if let FnDeclKind::Trait = fn_kind - && !this.tcx.features().return_position_impl_trait_in_trait - { - ImplTraitContext::FeatureGated( - ImplTraitPosition::TraitReturn, - sym::return_position_impl_trait_in_trait, - ) - } else { - ImplTraitContext::ReturnPositionOpaqueTy { - origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), - fn_kind, - } + ImplTraitContext::ReturnPositionOpaqueTy { + origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), + fn_kind, }, ); arena_vec![this; future_bound] diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs index 6f75419c387..d66bba517e0 100644 --- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs +++ b/compiler/rustc_ast_lowering/src/lifetime_collector.rs @@ -82,7 +82,8 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> { // We can sometimes encounter bare trait objects // which are represented in AST as paths. if let Some(partial_res) = self.resolver.get_partial_res(t.id) - && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res() + && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = + partial_res.full_res() { self.current_binders.push(t.id); visit::walk_ty(self, t); diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 743fad8e865..0477c7b2ba9 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -215,14 +215,15 @@ impl<'a> AstValidator<'a> { } fn visit_struct_field_def(&mut self, field: &'a FieldDef) { - if let Some(ident) = field.ident && - ident.name == kw::Underscore { - self.check_unnamed_field_ty(&field.ty, ident.span); - self.visit_vis(&field.vis); - self.visit_ident(ident); - self.visit_ty_common(&field.ty); - self.walk_ty(&field.ty); - walk_list!(self, visit_attribute, &field.attrs); + if let Some(ident) = field.ident + && ident.name == kw::Underscore + { + self.check_unnamed_field_ty(&field.ty, ident.span); + self.visit_vis(&field.vis); + self.visit_ident(ident); + self.visit_ty_common(&field.ty); + self.walk_ty(&field.ty); + walk_list!(self, visit_attribute, &field.attrs); } else { self.visit_field_def(field); } @@ -291,13 +292,11 @@ impl<'a> AstValidator<'a> { } fn deny_unnamed_field(&self, field: &FieldDef) { - if let Some(ident) = field.ident && - ident.name == kw::Underscore { - self.err_handler() - .emit_err(errors::InvalidUnnamedField { - span: field.span, - ident_span: ident.span - }); + if let Some(ident) = field.ident + && ident.name == kw::Underscore + { + self.err_handler() + .emit_err(errors::InvalidUnnamedField { span: field.span, ident_span: ident.span }); } } @@ -1180,28 +1179,40 @@ impl<'a> Visitor<'a> for AstValidator<'a> { (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => { self.err_handler().emit_err(errors::OptionalTraitSupertrait { span: poly.span, - path_str: pprust::path_to_string(&poly.trait_ref.path) + path_str: pprust::path_to_string(&poly.trait_ref.path), }); } (BoundKind::TraitObject, TraitBoundModifier::Maybe) => { - self.err_handler().emit_err(errors::OptionalTraitObject {span: poly.span}); + self.err_handler().emit_err(errors::OptionalTraitObject { span: poly.span }); } - (_, TraitBoundModifier::MaybeConst) if let Some(reason) = &self.disallow_tilde_const => { + (_, TraitBoundModifier::MaybeConst) + if let Some(reason) = &self.disallow_tilde_const => + { let reason = match reason { - DisallowTildeConstContext::TraitObject => errors::TildeConstReason::TraitObject, - DisallowTildeConstContext::Fn(FnKind::Closure(..)) => errors::TildeConstReason::Closure, - DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => errors::TildeConstReason::Function { ident: ident.span }, + DisallowTildeConstContext::TraitObject => { + errors::TildeConstReason::TraitObject + } + DisallowTildeConstContext::Fn(FnKind::Closure(..)) => { + errors::TildeConstReason::Closure + } + DisallowTildeConstContext::Fn(FnKind::Fn(_, ident, ..)) => { + errors::TildeConstReason::Function { ident: ident.span } + } }; - self.err_handler().emit_err(errors::TildeConstDisallowed { - span: bound.span(), - reason - }); + self.err_handler() + .emit_err(errors::TildeConstDisallowed { span: bound.span(), reason }); } (_, TraitBoundModifier::MaybeConstMaybe) => { - self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span(), modifier: "?" }); + self.err_handler().emit_err(errors::OptionalConstExclusive { + span: bound.span(), + modifier: "?", + }); } (_, TraitBoundModifier::MaybeConstNegative) => { - self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span(), modifier: "!" }); + self.err_handler().emit_err(errors::OptionalConstExclusive { + span: bound.span(), + modifier: "!", + }); } _ => {} } @@ -1214,7 +1225,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { { for arg in &args.args { if let ast::AngleBracketedArg::Constraint(constraint) = arg { - self.err_handler().emit_err(errors::ConstraintOnNegativeBound { span: constraint.span }); + self.err_handler() + .emit_err(errors::ConstraintOnNegativeBound { span: constraint.span }); } } } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 5d279943f1e..9328b83e8f3 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -658,7 +658,7 @@ fn check_incompatible_features(sess: &Session, features: &Features) { for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES .iter() - .filter(|&&(f1, f2)| features.enabled(f1) && features.enabled(f2)) + .filter(|&&(f1, f2)| features.active(f1) && features.active(f2)) { if let Some((f1_name, f1_span)) = declared_features.clone().find(|(name, _)| name == f1) { if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2) diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index 7db413c5bbd..5147e672f5f 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -4,6 +4,9 @@ //! //! The crate also contains other misc AST visitors, e.g. `node_count` and `show_span`. +#![cfg_attr(not(bootstrap), allow(internal_features))] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(iter_is_partitioned)] diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs index bf094af5f7b..475bdb02378 100644 --- a/compiler/rustc_ast_pretty/src/lib.rs +++ b/compiler/rustc_ast_pretty/src/lib.rs @@ -1,3 +1,6 @@ +#![cfg_attr(not(bootstrap), allow(internal_features))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), doc(rust_logo))] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] #![feature(associated_type_bounds)] diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 8b7e91882fc..e71f421659e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -148,7 +148,7 @@ pub fn print_crate<'a>( /// This makes printed token streams look slightly nicer, /// and also addresses some specific regressions described in #63896 and #73345. -fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool { +fn space_between(prev: &TokenTree, curr: &TokenTree) -> bool { if let TokenTree::Token(token, _) = prev { // No space after these tokens, e.g. `x.y`, `$e` // (The carets point to `prev`.) ^ ^ @@ -159,9 +159,9 @@ fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool { return comment_kind != CommentKind::Line; } } - match tt { + match curr { // No space before these tokens, e.g. `foo,`, `println!`, `x.y` - // (The carets point to `token`.) ^ ^ ^ + // (The carets point to `curr`.) ^ ^ ^ // // FIXME: having `Not` here works well for macro invocations like // `println!()`, but is bad when `!` means "logical not" or "the never @@ -575,7 +575,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere while let Some(tt) = iter.next() { self.print_tt(tt, convert_dollar_crate); if let Some(next) = iter.peek() { - if tt_prepend_space(next, tt) { + if space_between(tt, next) { self.space(); } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 1142d492160..269cb8f2380 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -684,8 +684,8 @@ pub fn reconstruct_format_args_template_string(pieces: &[FormatArgsPiece]) -> St for piece in pieces { match piece { FormatArgsPiece::Literal(s) => { - for c in s.as_str().escape_debug() { - template.push(c); + for c in s.as_str().chars() { + template.extend(c.escape_debug()); if let '{' | '}' = c { template.push(c); } diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index f013ff45a4f..46683d2d258 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -405,7 +405,9 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit } } - if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER { + if let Some(s) = since + && s.as_str() == VERSION_PLACEHOLDER + { since = Some(rust_version_symbol()); } @@ -548,7 +550,11 @@ pub fn cfg_matches( UNEXPECTED_CFGS, cfg.span, lint_node_id, - "unexpected `cfg` condition value", + if let Some(value) = cfg.value { + format!("unexpected `cfg` condition value: `{value}`") + } else { + format!("unexpected `cfg` condition value: (none)") + }, BuiltinLintDiagnostics::UnexpectedCfgValue( (cfg.name, cfg.name_span), cfg.value.map(|v| (v, cfg.value_span.unwrap())), @@ -560,7 +566,7 @@ pub fn cfg_matches( UNEXPECTED_CFGS, cfg.span, lint_node_id, - "unexpected `cfg` condition name", + format!("unexpected `cfg` condition name: `{}`", cfg.name), BuiltinLintDiagnostics::UnexpectedCfgName( (cfg.name, cfg.name_span), cfg.value.map(|v| (v, cfg.value_span.unwrap())), @@ -690,13 +696,16 @@ pub fn eval_condition( !eval_condition(mis[0].meta_item().unwrap(), sess, features, eval) } sym::target => { - if let Some(features) = features && !features.cfg_target_compact { + if let Some(features) = features + && !features.cfg_target_compact + { feature_err( sess, sym::cfg_target_compact, cfg.span, - "compact `cfg(target(..))` is experimental and subject to change" - ).emit(); + "compact `cfg(target(..))` is experimental and subject to change", + ) + .emit(); } mis.iter().fold(true, |res, mi| { diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs index cfed2acfb3a..53e3eaaab37 100644 --- a/compiler/rustc_attr/src/lib.rs +++ b/compiler/rustc_attr/src/lib.rs @@ -4,6 +4,9 @@ //! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax` //! to this crate. +#![cfg_attr(not(bootstrap), allow(internal_features))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), doc(rust_logo))] #![feature(let_chains)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_baked_icu_data/src/lib.rs b/compiler/rustc_baked_icu_data/src/lib.rs index 4651e03f771..ae8c062d25d 100644 --- a/compiler/rustc_baked_icu_data/src/lib.rs +++ b/compiler/rustc_baked_icu_data/src/lib.rs @@ -19,6 +19,10 @@ //! -k list/and@1 fallback/likelysubtags@1 fallback/parents@1 fallback/supplement/co@1 \ //! --cldr-tag latest --icuexport-tag latest -o src/data //! ``` + +#![cfg_attr(not(bootstrap), allow(internal_features))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), doc(rust_logo))] #![allow(elided_lifetimes_in_paths)] mod data { diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 4ac633c263f..6ea84620bbe 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -1,6 +1,7 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::graph::WithSuccessors; use rustc_index::bit_set::BitSet; use rustc_middle::mir::{ self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges, @@ -222,6 +223,7 @@ impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> { } } +// This is `pub` because it's used by unstable external borrowck data users, see `consumers.rs`. pub fn calculate_borrows_out_of_scope_at_location<'tcx>( body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, @@ -238,15 +240,196 @@ pub fn calculate_borrows_out_of_scope_at_location<'tcx>( prec.borrows_out_of_scope_at_location } +struct PoloniusOutOfScopePrecomputer<'a, 'tcx> { + visited: BitSet<mir::BasicBlock>, + visit_stack: Vec<mir::BasicBlock>, + body: &'a Body<'tcx>, + regioncx: &'a RegionInferenceContext<'tcx>, + + loans_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>, +} + +impl<'a, 'tcx> PoloniusOutOfScopePrecomputer<'a, 'tcx> { + fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self { + Self { + visited: BitSet::new_empty(body.basic_blocks.len()), + visit_stack: vec![], + body, + regioncx, + loans_out_of_scope_at_location: FxIndexMap::default(), + } + } +} + +impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> { + /// Loans are in scope while they are live: whether they are contained within any live region. + /// In the location-insensitive analysis, a loan will be contained in a region if the issuing + /// region can reach it in the subset graph. So this is a reachability problem. + fn precompute_loans_out_of_scope( + &mut self, + loan_idx: BorrowIndex, + issuing_region: RegionVid, + loan_issued_at: Location, + ) { + let sccs = self.regioncx.constraint_sccs(); + let issuing_region_scc = sccs.scc(issuing_region); + + // We first handle the cases where the loan doesn't go out of scope, depending on the issuing + // region's successors. + for scc in sccs.depth_first_search(issuing_region_scc) { + // 1. Via member constraints + // + // The issuing region can flow into the choice regions, and they are either: + // - placeholders or free regions themselves, + // - or also transitively outlive a free region. + // + // That is to say, if there are member constraints here, the loan escapes the function + // and cannot go out of scope. We can early return. + if self.regioncx.scc_has_member_constraints(scc) { + return; + } + + // 2. Via regions that are live at all points: placeholders and free regions. + // + // If the issuing region outlives such a region, its loan escapes the function and + // cannot go out of scope. We can early return. + if self.regioncx.scc_is_live_at_all_points(scc) { + return; + } + } + + let first_block = loan_issued_at.block; + let first_bb_data = &self.body.basic_blocks[first_block]; + + // The first block we visit is the one where the loan is issued, starting from the statement + // where the loan is issued: at `loan_issued_at`. + let first_lo = loan_issued_at.statement_index; + let first_hi = first_bb_data.statements.len(); + + if let Some(kill_location) = + self.loan_kill_location(loan_idx, loan_issued_at, first_block, first_lo, first_hi) + { + debug!("loan {:?} gets killed at {:?}", loan_idx, kill_location); + self.loans_out_of_scope_at_location.entry(kill_location).or_default().push(loan_idx); + + // The loan dies within the first block, we're done and can early return. + return; + } + + // The loan is not dead. Add successor BBs to the work list, if necessary. + for succ_bb in first_bb_data.terminator().successors() { + if self.visited.insert(succ_bb) { + self.visit_stack.push(succ_bb); + } + } + + // We may end up visiting `first_block` again. This is not an issue: we know at this point + // that the loan is not killed in the `first_lo..=first_hi` range, so checking the + // `0..first_lo` range and the `0..first_hi` range gives the same result. + while let Some(block) = self.visit_stack.pop() { + let bb_data = &self.body[block]; + let num_stmts = bb_data.statements.len(); + if let Some(kill_location) = + self.loan_kill_location(loan_idx, loan_issued_at, block, 0, num_stmts) + { + debug!("loan {:?} gets killed at {:?}", loan_idx, kill_location); + self.loans_out_of_scope_at_location + .entry(kill_location) + .or_default() + .push(loan_idx); + + // The loan dies within this block, so we don't need to visit its successors. + continue; + } + + // Add successor BBs to the work list, if necessary. + for succ_bb in bb_data.terminator().successors() { + if self.visited.insert(succ_bb) { + self.visit_stack.push(succ_bb); + } + } + } + + self.visited.clear(); + assert!(self.visit_stack.is_empty(), "visit stack should be empty"); + } + + /// Returns the lowest statement in `start..=end`, where the loan goes out of scope, if any. + /// This is the statement where the issuing region can't reach any of the regions that are live + /// at this point. + fn loan_kill_location( + &self, + loan_idx: BorrowIndex, + loan_issued_at: Location, + block: BasicBlock, + start: usize, + end: usize, + ) -> Option<Location> { + for statement_index in start..=end { + let location = Location { block, statement_index }; + + // Check whether the issuing region can reach local regions that are live at this point: + // - a loan is always live at its issuing location because it can reach the issuing + // region, which is always live at this location. + if location == loan_issued_at { + continue; + } + + // - the loan goes out of scope at `location` if it's not contained within any regions + // live at this point. + // + // FIXME: if the issuing region `i` can reach a live region `r` at point `p`, and `r` is + // live at point `q`, then it's guaranteed that `i` would reach `r` at point `q`. + // Reachability is location-insensitive, and we could take advantage of that, by jumping + // to a further point than just the next statement: we can jump to the furthest point + // within the block where `r` is live. + if self.regioncx.is_loan_live_at(loan_idx, location) { + continue; + } + + // No live region is reachable from the issuing region: the loan is killed at this + // point. + return Some(location); + } + + None + } +} + impl<'a, 'tcx> Borrows<'a, 'tcx> { pub fn new( tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, - nonlexical_regioncx: &'a RegionInferenceContext<'tcx>, + regioncx: &'a RegionInferenceContext<'tcx>, borrow_set: &'a BorrowSet<'tcx>, ) -> Self { - let borrows_out_of_scope_at_location = - calculate_borrows_out_of_scope_at_location(body, nonlexical_regioncx, borrow_set); + let mut borrows_out_of_scope_at_location = + calculate_borrows_out_of_scope_at_location(body, regioncx, borrow_set); + + // The in-tree polonius analysis computes loans going out of scope using the set-of-loans + // model, and makes sure they're identical to the existing computation of the set-of-points + // model. + if tcx.sess.opts.unstable_opts.polonius.is_next_enabled() { + let mut polonius_prec = PoloniusOutOfScopePrecomputer::new(body, regioncx); + for (loan_idx, loan_data) in borrow_set.iter_enumerated() { + let issuing_region = loan_data.region; + let issued_location = loan_data.reserve_location; + + polonius_prec.precompute_loans_out_of_scope( + loan_idx, + issuing_region, + issued_location, + ); + } + + assert_eq!( + borrows_out_of_scope_at_location, polonius_prec.loans_out_of_scope_at_location, + "the loans out of scope must be the same as the borrows out of scope" + ); + + borrows_out_of_scope_at_location = polonius_prec.loans_out_of_scope_at_location; + } + Borrows { tcx, body, borrow_set, borrows_out_of_scope_at_location } } @@ -333,6 +516,13 @@ impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> { } } +/// Forward dataflow computation of the set of borrows that are in scope at a particular location. +/// - we gen the introduced loans +/// - we kill loans on locals going out of (regular) scope +/// - we kill the loans going out of their region's NLL scope: in NLL terms, the frontier where a +/// region stops containing the CFG points reachable from the issuing location. +/// - we also kill loans of conflicting places when overwriting a shared path: e.g. borrows of +/// `a.b.c` when `a` is overwritten. impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { type Idx = BorrowIndex; diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 4488276e0e7..20a4402f6f6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -351,7 +351,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } // Check if we are in a situation of `ident @ ident` where we want to suggest // `ref ident @ ref ident` or `ref ident @ Struct { ref ident }`. - if let Some(subpat) = sub && self.pat.is_none() { + if let Some(subpat) = sub + && self.pat.is_none() + { self.visit_pat(subpat); if self.pat.is_some() { self.parent_pat = Some(p); @@ -370,7 +372,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut finder = ExpressionFinder { expr_span: move_span, expr: None, pat: None, parent_pat: None }; finder.visit_expr(expr); - if let Some(span) = span && let Some(expr) = finder.expr { + if let Some(span) = span + && let Some(expr) = finder.expr + { for (_, expr) in hir.parent_iter(expr.hir_id) { if let hir::Node::Expr(expr) = expr { if expr.span.contains(span) { @@ -425,10 +429,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some(hir::intravisit::FnKind::Method(..)) => "method", Some(hir::intravisit::FnKind::Closure) => "closure", }; - span.push_span_label( - ident.span, - format!("in this {descr}"), - ); + span.push_span_label(ident.span, format!("in this {descr}")); err.span_note( span, format!( @@ -441,15 +442,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let ty = place.ty(self.body, self.infcx.tcx).ty; if let hir::Node::Expr(parent_expr) = parent && let hir::ExprKind::Call(call_expr, _) = parent_expr.kind - && let hir::ExprKind::Path( - hir::QPath::LangItem(LangItem::IntoIterIntoIter, _, _) - ) = call_expr.kind + && let hir::ExprKind::Path(hir::QPath::LangItem( + LangItem::IntoIterIntoIter, + _, + _, + )) = call_expr.kind { // Do not suggest `.clone()` in a `for` loop, we already suggest borrowing. - } else if let UseSpans::FnSelfUse { - kind: CallKind::Normal { .. }, - .. - } = move_spans { + } else if let UseSpans::FnSelfUse { kind: CallKind::Normal { .. }, .. } = + move_spans + { // We already suggest cloning for these cases in `explain_captures`. } else { self.suggest_cloning(err, ty, expr, move_span); @@ -602,10 +604,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if self.sugg_span.is_some() { return; } - if let hir::StmtKind::Local(hir::Local { - span, ty, init: None, .. - }) = &ex.kind && span.contains(self.decl_span) { - self.sugg_span = ty.map_or(Some(self.decl_span), |ty| Some(ty.span)); + if let hir::StmtKind::Local(hir::Local { span, ty, init: None, .. }) = &ex.kind + && span.contains(self.decl_span) + { + self.sugg_span = ty.map_or(Some(self.decl_span), |ty| Some(ty.span)); } hir::intravisit::walk_stmt(self, ex); } @@ -743,19 +745,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ".clone()".to_owned() }; if let Some(clone_trait_def) = tcx.lang_items().clone_trait() - && self.infcx - .type_implements_trait( - clone_trait_def, - [ty], - self.param_env, - ) + && self + .infcx + .type_implements_trait(clone_trait_def, [ty], self.param_env) .must_apply_modulo_regions() { let msg = if let ty::Adt(def, _) = ty.kind() - && [ - tcx.get_diagnostic_item(sym::Arc), - tcx.get_diagnostic_item(sym::Rc), - ].contains(&Some(def.did())) + && [tcx.get_diagnostic_item(sym::Arc), tcx.get_diagnostic_item(sym::Rc)] + .contains(&Some(def.did())) { "clone the value to increment its reference count" } else { @@ -1329,42 +1326,160 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { issue_span: Span, expr_span: Span, body_expr: Option<&'hir hir::Expr<'hir>>, - loop_bind: Option<Symbol>, + loop_bind: Option<&'hir Ident>, + loop_span: Option<Span>, + head_span: Option<Span>, + pat_span: Option<Span>, + head: Option<&'hir hir::Expr<'hir>>, } impl<'hir> Visitor<'hir> for ExprFinder<'hir> { fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) { - if let hir::ExprKind::Loop(hir::Block{ stmts: [stmt, ..], ..}, _, hir::LoopSource::ForLoop, _) = ex.kind && - let hir::StmtKind::Expr(hir::Expr{ kind: hir::ExprKind::Match(call, [_, bind, ..], _), ..}) = stmt.kind && - let hir::ExprKind::Call(path, _args) = call.kind && - let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IteratorNext, _, _, )) = path.kind && - let hir::PatKind::Struct(path, [field, ..], _) = bind.pat.kind && - let hir::QPath::LangItem(LangItem::OptionSome, _, _) = path && - let PatField { pat: hir::Pat{ kind: hir::PatKind::Binding(_, _, ident, ..), .. }, ..} = field && - self.issue_span.source_equal(call.span) { - self.loop_bind = Some(ident.name); + // Try to find + // let result = match IntoIterator::into_iter(<head>) { + // mut iter => { + // [opt_ident]: loop { + // match Iterator::next(&mut iter) { + // None => break, + // Some(<pat>) => <body>, + // }; + // } + // } + // }; + // corresponding to the desugaring of a for loop `for <pat> in <head> { <body> }`. + if let hir::ExprKind::Call(path, [arg]) = ex.kind + && let hir::ExprKind::Path(hir::QPath::LangItem( + LangItem::IntoIterIntoIter, + _, + _, + )) = path.kind + && arg.span.contains(self.issue_span) + { + // Find `IntoIterator::into_iter(<head>)` + self.head = Some(arg); + } + if let hir::ExprKind::Loop( + hir::Block { stmts: [stmt, ..], .. }, + _, + hir::LoopSource::ForLoop, + _, + ) = ex.kind + && let hir::StmtKind::Expr(hir::Expr { + kind: hir::ExprKind::Match(call, [_, bind, ..], _), + span: head_span, + .. + }) = stmt.kind + && let hir::ExprKind::Call(path, _args) = call.kind + && let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IteratorNext, _, _)) = + path.kind + && let hir::PatKind::Struct(path, [field, ..], _) = bind.pat.kind + && let hir::QPath::LangItem(LangItem::OptionSome, pat_span, _) = path + && call.span.contains(self.issue_span) + { + // Find `<pat>` and the span for the whole `for` loop. + if let PatField { + pat: hir::Pat { kind: hir::PatKind::Binding(_, _, ident, ..), .. }, + .. + } = field + { + self.loop_bind = Some(ident); } + self.head_span = Some(*head_span); + self.pat_span = Some(pat_span); + self.loop_span = Some(stmt.span); + } - if let hir::ExprKind::MethodCall(body_call, _recv, ..) = ex.kind && - body_call.ident.name == sym::next && ex.span.source_equal(self.expr_span) { - self.body_expr = Some(ex); + if let hir::ExprKind::MethodCall(body_call, recv, ..) = ex.kind + && body_call.ident.name == sym::next + && recv.span.source_equal(self.expr_span) + { + self.body_expr = Some(ex); } hir::intravisit::walk_expr(self, ex); } } - let mut finder = - ExprFinder { expr_span: span, issue_span, loop_bind: None, body_expr: None }; + let mut finder = ExprFinder { + expr_span: span, + issue_span, + loop_bind: None, + body_expr: None, + head_span: None, + loop_span: None, + pat_span: None, + head: None, + }; finder.visit_expr(hir.body(body_id).value); - if let Some(loop_bind) = finder.loop_bind && - let Some(body_expr) = finder.body_expr && - let Some(def_id) = typeck_results.type_dependent_def_id(body_expr.hir_id) && - let Some(trait_did) = tcx.trait_of_item(def_id) && - tcx.is_diagnostic_item(sym::Iterator, trait_did) { - err.note(format!( - "a for loop advances the iterator for you, the result is stored in `{loop_bind}`." + if let Some(body_expr) = finder.body_expr + && let Some(loop_span) = finder.loop_span + && let Some(def_id) = typeck_results.type_dependent_def_id(body_expr.hir_id) + && let Some(trait_did) = tcx.trait_of_item(def_id) + && tcx.is_diagnostic_item(sym::Iterator, trait_did) + { + if let Some(loop_bind) = finder.loop_bind { + err.note(format!( + "a for loop advances the iterator for you, the result is stored in `{}`", + loop_bind.name, + )); + } else { + err.note( + "a for loop advances the iterator for you, the result is stored in its pattern", + ); + } + let msg = "if you want to call `next` on a iterator within the loop, consider using \ + `while let`"; + if let Some(head) = finder.head + && let Some(pat_span) = finder.pat_span + && loop_span.contains(body_expr.span) + && loop_span.contains(head.span) + { + let sm = self.infcx.tcx.sess.source_map(); + + let mut sugg = vec![]; + if let hir::ExprKind::Path(hir::QPath::Resolved(None, _)) = head.kind { + // A bare path doesn't need a `let` assignment, it's already a simple + // binding access. + // As a new binding wasn't added, we don't need to modify the advancing call. + sugg.push((loop_span.with_hi(pat_span.lo()), format!("while let Some("))); + sugg.push(( + pat_span.shrink_to_hi().with_hi(head.span.lo()), + ") = ".to_string(), + )); + sugg.push((head.span.shrink_to_hi(), ".next()".to_string())); + } else { + // Needs a new a `let` binding. + let indent = if let Some(indent) = sm.indentation_before(loop_span) { + format!("\n{indent}") + } else { + " ".to_string() + }; + let Ok(head_str) = sm.span_to_snippet(head.span) else { + err.help(msg); + return; + }; + sugg.push(( + loop_span.with_hi(pat_span.lo()), + format!("let iter = {head_str};{indent}while let Some("), )); - err.help("if you want to call `next` on an iterator within the loop, consider using `while let`."); + sugg.push(( + pat_span.shrink_to_hi().with_hi(head.span.hi()), + ") = iter.next()".to_string(), + )); + // As a new binding was added, we should change how the iterator is advanced to + // use the newly introduced binding. + if let hir::ExprKind::MethodCall(_, recv, ..) = body_expr.kind + && let hir::ExprKind::Path(hir::QPath::Resolved(None, ..)) = recv.kind + { + // As we introduced a `let iter = <head>;`, we need to change where the + // already borrowed value was accessed from `<recv>.next()` to + // `iter.next()`. + sugg.push((recv.span, "iter".to_string())); + } + } + err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect); + } else { + err.help(msg); + } } } @@ -1540,69 +1655,80 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { if e.span.contains(self.capture_span) { if let hir::ExprKind::Closure(&hir::Closure { - movability: None, - body, - fn_arg_span, - fn_decl: hir::FnDecl{ inputs, .. }, - .. - }) = e.kind && - let Some(hir::Node::Expr(body )) = self.hir.find(body.hir_id) { - self.suggest_arg = "this: &Self".to_string(); - if inputs.len() > 0 { - self.suggest_arg.push_str(", "); - } - self.in_closure = true; - self.closure_arg_span = fn_arg_span; - self.visit_expr(body); - self.in_closure = false; + movability: None, + body, + fn_arg_span, + fn_decl: hir::FnDecl { inputs, .. }, + .. + }) = e.kind + && let Some(hir::Node::Expr(body)) = self.hir.find(body.hir_id) + { + self.suggest_arg = "this: &Self".to_string(); + if inputs.len() > 0 { + self.suggest_arg.push_str(", "); + } + self.in_closure = true; + self.closure_arg_span = fn_arg_span; + self.visit_expr(body); + self.in_closure = false; } } if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e { - if let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path && - seg.ident.name == kw::SelfLower && self.in_closure { - self.closure_change_spans.push(e.span); + if let hir::QPath::Resolved(_, hir::Path { segments: [seg], .. }) = path + && seg.ident.name == kw::SelfLower + && self.in_closure + { + self.closure_change_spans.push(e.span); } } hir::intravisit::walk_expr(self, e); } fn visit_local(&mut self, local: &'hir hir::Local<'hir>) { - if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = local.pat && - let Some(init) = local.init + if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = + local.pat + && let Some(init) = local.init { - if let hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { - movability: None, - .. - }), .. } = init && - init.span.contains(self.capture_span) { - self.closure_local_id = Some(*hir_id); + if let hir::Expr { + kind: hir::ExprKind::Closure(&hir::Closure { movability: None, .. }), + .. + } = init + && init.span.contains(self.capture_span) + { + self.closure_local_id = Some(*hir_id); } } hir::intravisit::walk_local(self, local); } fn visit_stmt(&mut self, s: &'hir hir::Stmt<'hir>) { - if let hir::StmtKind::Semi(e) = s.kind && - let hir::ExprKind::Call(hir::Expr { kind: hir::ExprKind::Path(path), ..}, args) = e.kind && - let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path && - let Res::Local(hir_id) = seg.res && - Some(hir_id) == self.closure_local_id { - let (span, arg_str) = if args.len() > 0 { - (args[0].span.shrink_to_lo(), "self, ".to_string()) - } else { - let span = e.span.trim_start(seg.ident.span).unwrap_or(e.span); - (span, "(self)".to_string()) - }; - self.closure_call_changes.push((span, arg_str)); + if let hir::StmtKind::Semi(e) = s.kind + && let hir::ExprKind::Call( + hir::Expr { kind: hir::ExprKind::Path(path), .. }, + args, + ) = e.kind + && let hir::QPath::Resolved(_, hir::Path { segments: [seg], .. }) = path + && let Res::Local(hir_id) = seg.res + && Some(hir_id) == self.closure_local_id + { + let (span, arg_str) = if args.len() > 0 { + (args[0].span.shrink_to_lo(), "self, ".to_string()) + } else { + let span = e.span.trim_start(seg.ident.span).unwrap_or(e.span); + (span, "(self)".to_string()) + }; + self.closure_call_changes.push((span, arg_str)); } hir::intravisit::walk_stmt(self, s); } } - if let Some(hir::Node::ImplItem( - hir::ImplItem { kind: hir::ImplItemKind::Fn(_fn_sig, body_id), .. } - )) = hir.find(self.mir_hir_id()) && - let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) { + if let Some(hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Fn(_fn_sig, body_id), + .. + })) = hir.find(self.mir_hir_id()) + && let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) + { let mut finder = ExpressionFinder { capture_span: *capture_kind_span, closure_change_spans: vec![], @@ -2173,15 +2299,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { visitor.visit_stmt(stmt); let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); - let expr_ty: Option<Ty<'_>> = visitor.prop_expr.map(|expr| typeck_results.expr_ty(expr).peel_refs()); - - let is_format_arguments_item = - if let Some(expr_ty) = expr_ty - && let ty::Adt(adt, _) = expr_ty.kind() { - self.infcx.tcx.lang_items().get(LangItem::FormatArguments) == Some(adt.did()) - } else { - false - }; + let expr_ty: Option<Ty<'_>> = + visitor.prop_expr.map(|expr| typeck_results.expr_ty(expr).peel_refs()); + + let is_format_arguments_item = if let Some(expr_ty) = expr_ty + && let ty::Adt(adt, _) = expr_ty.kind() + { + self.infcx.tcx.lang_items().get(LangItem::FormatArguments) + == Some(adt.did()) + } else { + false + }; if visitor.found == 0 && stmt.span.contains(proper_span) diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index c66a2447356..c9514f5604c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -76,10 +76,10 @@ impl<'tcx> BorrowExplanation<'tcx> { expr_finder.visit_expr(body.value); if let Some(mut expr) = expr_finder.result { while let hir::ExprKind::AddrOf(_, _, inner) - | hir::ExprKind::Unary(hir::UnOp::Deref, inner) - | hir::ExprKind::Field(inner, _) - | hir::ExprKind::MethodCall(_, inner, _, _) - | hir::ExprKind::Index(inner, _, _) = &expr.kind + | hir::ExprKind::Unary(hir::UnOp::Deref, inner) + | hir::ExprKind::Field(inner, _) + | hir::ExprKind::MethodCall(_, inner, _, _) + | hir::ExprKind::Index(inner, _, _) = &expr.kind { expr = inner; } @@ -88,10 +88,7 @@ impl<'tcx> BorrowExplanation<'tcx> { && let hir::def::Res::Local(hir_id) = p.res && let Some(hir::Node::Pat(pat)) = tcx.hir().find(hir_id) { - err.span_label( - pat.span, - format!("binding `{ident}` declared here"), - ); + err.span_label(pat.span, format!("binding `{ident}` declared here")); } } } @@ -419,7 +416,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if self.local_names[local].is_some() && let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place && let Some(borrowed_local) = place.as_local() - && self.local_names[borrowed_local].is_some() && local != borrowed_local + && self.local_names[borrowed_local].is_some() + && local != borrowed_local { should_note_order = true; } diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index c3cf7db32b1..8f5d5e67a7a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -780,19 +780,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("move_spans: moved_place={:?} location={:?} stmt={:?}", moved_place, location, stmt); if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind - && let AggregateKind::Closure(def_id, _) | AggregateKind::Generator(def_id, _, _) = **kind + && let AggregateKind::Closure(def_id, _) | AggregateKind::Generator(def_id, _, _) = + **kind { debug!("move_spans: def_id={:?} places={:?}", def_id, places); let def_id = def_id.expect_local(); if let Some((args_span, generator_kind, capture_kind_span, path_span)) = self.closure_span(def_id, moved_place, places) { - return ClosureUse { - generator_kind, - args_span, - capture_kind_span, - path_span, - }; + return ClosureUse { generator_kind, args_span, capture_kind_span, path_span }; } } @@ -1123,7 +1119,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &self.infcx.tcx.sess.parse_sess.span_diagnostic, CaptureReasonSuggest::FreshReborrow { span: move_span.shrink_to_hi(), - }); + }, + ); } if let Some(clone_trait) = tcx.lang_items().clone_trait() && let trait_ref = ty::TraitRef::new(tcx, clone_trait, [ty]) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index e6bde6a8c54..e5ffc8a1114 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -396,17 +396,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let upvar_hir_id = captured_place.get_root_variable(); if let Some(Node::Pat(pat)) = self.infcx.tcx.hir().find(upvar_hir_id) - && let hir::PatKind::Binding( - hir::BindingAnnotation::NONE, - _, - upvar_ident, - _, - ) = pat.kind + && let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, upvar_ident, _) = + pat.kind { if upvar_ident.name == kw::SelfLower { for (_, node) in self.infcx.tcx.hir().parent_iter(upvar_hir_id) { if let Some(fn_decl) = node.fn_decl() { - if !matches!(fn_decl.implicit_self, hir::ImplicitSelfKind::ImmRef | hir::ImplicitSelfKind::MutRef) { + if !matches!( + fn_decl.implicit_self, + hir::ImplicitSelfKind::ImmRef | hir::ImplicitSelfKind::MutRef + ) { err.span_suggestion( upvar_ident.span, "consider changing this to be mutable", @@ -573,7 +572,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.ty, ), vec![ - vec![ // val.insert(index, rv); + vec![ + // val.insert(index, rv); ( val.span.shrink_to_hi().with_hi(index.span.lo()), ".insert(".to_string(), @@ -584,7 +584,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ), (rv.span.shrink_to_hi(), ")".to_string()), ], - vec![ // val.get_mut(index).map(|v| { *v = rv; }); + vec![ + // val.get_mut(index).map(|v| { *v = rv; }); ( val.span.shrink_to_hi().with_hi(index.span.lo()), ".get_mut(".to_string(), @@ -593,12 +594,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { index.span.shrink_to_hi().with_hi(place.span.hi()), ").map(|val| { *val".to_string(), ), - ( - rv.span.shrink_to_hi(), - "; })".to_string(), - ), + (rv.span.shrink_to_hi(), "; })".to_string()), ], - vec![ // let x = val.entry(index).or_insert(rv); + vec![ + // let x = val.entry(index).or_insert(rv); (val.span.shrink_to_lo(), "let val = ".to_string()), ( val.span.shrink_to_hi().with_hi(index.span.lo()), @@ -747,10 +746,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { && let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id) { let body = hir_map.body(body_id); - let mut v = BindingFinder { - span: pat_span, - hir_id: None, - }; + let mut v = BindingFinder { span: pat_span, hir_id: None }; v.visit_body(body); v.hir_id } else { @@ -766,7 +762,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. }, .. })) = hir_map.find(hir_id) - && let Ok(name) = self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span) + && let Ok(name) = + self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span) { err.span_suggestion( pat_span, @@ -879,12 +876,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // `span` corresponds to the expression being iterated, find the `for`-loop desugared // expression with that span in order to identify potential fixes when encountering a // read-only iterator that should be mutable. - let mut v = Finder { - span, - expr: None, - }; + let mut v = Finder { span, expr: None }; v.visit_block(block); - if let Some(expr) = v.expr && let Call(_, [expr]) = expr.kind { + if let Some(expr) = v.expr + && let Call(_, [expr]) = expr.kind + { match expr.kind { MethodCall(path_segment, _, _, span) => { // We have `for _ in iter.read_only_iter()`, try to @@ -1032,38 +1028,42 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let source = self.body.source; let hir = self.infcx.tcx.hir(); if let InstanceDef::Item(def_id) = source.instance - && let Some(Node::Expr(hir::Expr { hir_id, kind, ..})) = hir.get_if_local(def_id) - && let ExprKind::Closure(closure) = kind && closure.movability == None - && let Some(Node::Expr(expr)) = hir.find_parent(*hir_id) { - let mut cur_expr = expr; - while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind { - if path_segment.ident.name == sym::iter { - // check `_ty` has `iter_mut` method - let res = self - .infcx - .tcx - .typeck(path_segment.hir_id.owner.def_id) - .type_dependent_def_id(cur_expr.hir_id) - .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id)) - .map(|def_id| self.infcx.tcx.associated_items(def_id)) - .map(|assoc_items| { - assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable() - }); - - if let Some(mut res) = res && res.peek().is_some() { - err.span_suggestion_verbose( - path_segment.ident.span, - "you may want to use `iter_mut` here", - "iter_mut", - Applicability::MaybeIncorrect, - ); - } - break; - } else { - cur_expr = recv; + && let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = hir.get_if_local(def_id) + && let ExprKind::Closure(closure) = kind + && closure.movability == None + && let Some(Node::Expr(expr)) = hir.find_parent(*hir_id) + { + let mut cur_expr = expr; + while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind { + if path_segment.ident.name == sym::iter { + // check `_ty` has `iter_mut` method + let res = self + .infcx + .tcx + .typeck(path_segment.hir_id.owner.def_id) + .type_dependent_def_id(cur_expr.hir_id) + .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id)) + .map(|def_id| self.infcx.tcx.associated_items(def_id)) + .map(|assoc_items| { + assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable() + }); + + if let Some(mut res) = res + && res.peek().is_some() + { + err.span_suggestion_verbose( + path_segment.ident.span, + "you may want to use `iter_mut` here", + "iter_mut", + Applicability::MaybeIncorrect, + ); } + break; + } else { + cur_expr = recv; } } + } } fn suggest_make_local_mut( @@ -1200,14 +1200,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } let hir_map = self.infcx.tcx.hir(); let def_id = self.body.source.def_id(); - let hir_id = if let Some(local_def_id) = def_id.as_local() && - let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id) + let hir_id = if let Some(local_def_id) = def_id.as_local() + && let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id) { let body = hir_map.body(body_id); - let mut v = BindingFinder { - span: err_label_span, - hir_id: None, - }; + let mut v = BindingFinder { span: err_label_span, hir_id: None }; v.visit_body(body); v.hir_id } else { @@ -1215,15 +1212,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }; if let Some(hir_id) = hir_id - && let Some(hir::Node::Local(local)) = hir_map.find(hir_id) + && let Some(hir::Node::Local(local)) = hir_map.find(hir_id) { let (changing, span, sugg) = match local.ty { Some(ty) => ("changing", ty.span, message), - None => ( - "specifying", - local.pat.span.shrink_to_hi(), - format!(": {message}"), - ), + None => { + ("specifying", local.pat.span.shrink_to_hi(), format!(": {message}")) + } }; err.span_suggestion_verbose( span, @@ -1234,9 +1229,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } else { err.span_label( err_label_span, - format!( - "consider changing this binding's type to be: `{message}`" - ), + format!("consider changing this binding's type to be: `{message}`"), ); } } @@ -1380,11 +1373,7 @@ fn suggest_ampmut<'tcx>( let ty_mut = decl_ty.builtin_deref(true).unwrap(); assert_eq!(ty_mut.mutbl, hir::Mutability::Not); - ( - false, - span, - format!("{}mut {}", if decl_ty.is_ref() {"&"} else {"*"}, ty_mut.ty) - ) + (false, span, format!("{}mut {}", if decl_ty.is_ref() { "&" } else { "*" }, ty_mut.ty)) } } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 55d581b3ab1..f8883c53d57 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -942,9 +942,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ty::ClauseKind::Projection(data) if data.projection_ty.self_ty() == ty => {} _ => return false, } - tcx.any_free_region_meets(pred, |r| { - *r == ty::ReEarlyBound(region) - }) + tcx.any_free_region_meets(pred, |r| *r == ty::ReEarlyBound(region)) }) } else { false diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs index 9916ebca32f..c54e7070478 100644 --- a/compiler/rustc_borrowck/src/facts.rs +++ b/compiler/rustc_borrowck/src/facts.rs @@ -41,7 +41,8 @@ pub(crate) trait AllFactsExt { impl AllFactsExt for AllFacts { /// Return fn enabled(tcx: TyCtxt<'_>) -> bool { - tcx.sess.opts.unstable_opts.nll_facts || tcx.sess.opts.unstable_opts.polonius + tcx.sess.opts.unstable_opts.nll_facts + || tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled() } fn write_to_dir( diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 9c77767e7a7..d274a3eea6c 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1,5 +1,8 @@ //! This query borrow-checks the MIR to (further) ensure it is not broken. +#![allow(internal_features)] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), doc(rust_logo))] #![feature(associated_type_bounds)] #![feature(box_patterns)] #![feature(let_chains)] @@ -11,7 +14,6 @@ #![feature(trusted_step)] #![feature(try_blocks)] #![recursion_limit = "256"] -#![allow(internal_features)] #[macro_use] extern crate rustc_middle; @@ -173,7 +175,9 @@ fn do_mir_borrowck<'tcx>( for var_debug_info in &input_body.var_debug_info { if let VarDebugInfoContents::Place(place) = var_debug_info.value { if let Some(local) = place.as_local() { - if let Some(prev_name) = local_names[local] && var_debug_info.name != prev_name { + if let Some(prev_name) = local_names[local] + && var_debug_info.name != prev_name + { span_bug!( var_debug_info.source_info.span, "local {:?} has many names (`{}` vs `{}`)", diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 3f60f5aca71..0ea4401a878 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -169,10 +169,11 @@ pub(crate) fn compute_regions<'cx, 'tcx>( upvars: &[Upvar<'tcx>], consumer_options: Option<ConsumerOptions>, ) -> NllOutput<'tcx> { + let is_polonius_legacy_enabled = infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled(); let polonius_input = consumer_options.map(|c| c.polonius_input()).unwrap_or_default() - || infcx.tcx.sess.opts.unstable_opts.polonius; + || is_polonius_legacy_enabled; let polonius_output = consumer_options.map(|c| c.polonius_output()).unwrap_or_default() - || infcx.tcx.sess.opts.unstable_opts.polonius; + || is_polonius_legacy_enabled; let mut all_facts = (polonius_input || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default()); @@ -181,22 +182,26 @@ pub(crate) fn compute_regions<'cx, 'tcx>( let elements = &Rc::new(RegionValueElements::new(&body)); // Run the MIR type-checker. - let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } = - type_check::type_check( - infcx, - param_env, - body, - promoted, - &universal_regions, - location_table, - borrow_set, - &mut all_facts, - flow_inits, - move_data, - elements, - upvars, - polonius_input, - ); + let MirTypeckResults { + constraints, + universal_region_relations, + opaque_type_values, + live_loans, + } = type_check::type_check( + infcx, + param_env, + body, + promoted, + &universal_regions, + location_table, + borrow_set, + &mut all_facts, + flow_inits, + move_data, + elements, + upvars, + polonius_input, + ); if let Some(all_facts) = &mut all_facts { let _prof_timer = infcx.tcx.prof.generic_activity("polonius_fact_generation"); @@ -274,6 +279,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>( type_tests, liveness_constraints, elements, + live_loans, ); // Generate various additional constraints. diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 852935676b6..96cbe98c216 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -7,6 +7,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::scc::Sccs; use rustc_errors::Diagnostic; use rustc_hir::def_id::CRATE_DEF_ID; +use rustc_index::bit_set::SparseBitMatrix; use rustc_index::{IndexSlice, IndexVec}; use rustc_infer::infer::outlives::test_type_match; use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq}; @@ -21,6 +22,7 @@ use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_span::Span; +use crate::dataflow::BorrowIndex; use crate::{ constraints::{ graph::NormalConstraintGraph, ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet, @@ -30,8 +32,8 @@ use crate::{ nll::PoloniusOutput, region_infer::reverse_sccs::ReverseSccGraph, region_infer::values::{ - LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues, - ToElementIndex, + LivenessValues, PlaceholderIndices, PointIndex, RegionElement, RegionValueElements, + RegionValues, ToElementIndex, }, type_check::{free_region_relations::UniversalRegionRelations, Locations}, universal_regions::UniversalRegions, @@ -119,6 +121,9 @@ pub struct RegionInferenceContext<'tcx> { /// Information about how the universally quantified regions in /// scope on this function relate to one another. universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, + + /// The set of loans that are live at a given point in the CFG, when using `-Zpolonius=next`. + live_loans: SparseBitMatrix<PointIndex, BorrowIndex>, } /// Each time that `apply_member_constraint` is successful, it appends @@ -330,6 +335,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { type_tests: Vec<TypeTest<'tcx>>, liveness_constraints: LivenessValues<RegionVid>, elements: &Rc<RegionValueElements>, + live_loans: SparseBitMatrix<PointIndex, BorrowIndex>, ) -> Self { debug!("universal_regions: {:#?}", universal_regions); debug!("outlives constraints: {:#?}", outlives_constraints); @@ -383,6 +389,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { type_tests, universal_regions, universal_region_relations, + live_loans, }; result.init_free_and_bound_regions(); @@ -683,7 +690,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // In Polonius mode, the errors about missing universal region relations are in the output // and need to be emitted or propagated. Otherwise, we need to check whether the // constraints were too strong, and if so, emit or propagate those errors. - if infcx.tcx.sess.opts.unstable_opts.polonius { + if infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled() { self.check_polonius_subset_errors( outlives_requirements.as_mut(), &mut errors_buffer, @@ -2279,6 +2286,41 @@ impl<'tcx> RegionInferenceContext<'tcx> { } None } + + /// Access to the SCC constraint graph. + pub(crate) fn constraint_sccs(&self) -> &Sccs<RegionVid, ConstraintSccIndex> { + self.constraint_sccs.as_ref() + } + + /// Returns whether the given SCC has any member constraints. + pub(crate) fn scc_has_member_constraints(&self, scc: ConstraintSccIndex) -> bool { + self.member_constraints.indices(scc).next().is_some() + } + + /// Returns whether the given SCC is live at all points: whether the representative is a + /// placeholder or a free region. + pub(crate) fn scc_is_live_at_all_points(&self, scc: ConstraintSccIndex) -> bool { + // FIXME: there must be a cleaner way to find this information. At least, when + // higher-ranked subtyping is abstracted away from the borrowck main path, we'll only + // need to check whether this is a universal region. + let representative = self.scc_representatives[scc]; + let origin = self.var_infos[representative].origin; + let live_at_all_points = matches!( + origin, + RegionVariableOrigin::Nll( + NllRegionVariableOrigin::Placeholder(_) | NllRegionVariableOrigin::FreeRegion + ) + ); + live_at_all_points + } + + /// Returns whether the `loan_idx` is live at the given `location`: whether its issuing + /// region is contained within the type of a variable that is live at this point. + /// Note: for now, the sets of live loans is only available when using `-Zpolonius=next`. + pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, location: Location) -> bool { + let point = self.liveness_constraints.point_from_location(location); + self.live_loans.contains(point, loan_idx) + } } impl<'tcx> RegionDefinition<'tcx> { diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index ff04b0237c2..fb0e5811c26 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,5 +1,6 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::ErrorGuaranteed; +use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::OpaqueTyOrigin; use rustc_infer::infer::InferCtxt; @@ -308,46 +309,38 @@ fn check_opaque_type_well_formed<'tcx>( return Ok(definition_ty); }; let param_env = tcx.param_env(def_id); - // HACK This bubble is required for this tests to pass: - // nested-return-type2-tait2.rs - // nested-return-type2-tait3.rs + + let mut parent_def_id = def_id; + while tcx.def_kind(parent_def_id) == DefKind::OpaqueTy { + parent_def_id = tcx.local_parent(parent_def_id); + } + // FIXME(-Ztrait-solver=next): We probably should use `DefiningAnchor::Error` // and prepopulate this `InferCtxt` with known opaque values, rather than // using the `Bind` anchor here. For now it's fine. let infcx = tcx .infer_ctxt() .with_next_trait_solver(next_trait_solver) - .with_opaque_type_inference(if next_trait_solver { - DefiningAnchor::Bind(def_id) - } else { - DefiningAnchor::Bubble - }) + .with_opaque_type_inference(DefiningAnchor::Bind(parent_def_id)) .build(); let ocx = ObligationCtxt::new(&infcx); let identity_args = GenericArgs::identity_for_item(tcx, def_id); // Require that the hidden type actually fulfills all the bounds of the opaque type, even without // the bounds that the function supplies. - let mut obligations = vec![]; - infcx - .insert_hidden_type( - OpaqueTypeKey { def_id, args: identity_args }, - &ObligationCause::misc(definition_span, def_id), - param_env, - definition_ty, - true, - &mut obligations, - ) - .unwrap(); - infcx.add_item_bounds_for_hidden_type( - def_id.to_def_id(), - identity_args, - ObligationCause::misc(definition_span, def_id), - param_env, - definition_ty, - &mut obligations, - ); - ocx.register_obligations(obligations); + let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), identity_args); + ocx.eq(&ObligationCause::misc(definition_span, def_id), param_env, opaque_ty, definition_ty) + .map_err(|err| { + infcx + .err_ctxt() + .report_mismatched_types( + &ObligationCause::misc(definition_span, def_id), + opaque_ty, + definition_ty, + err, + ) + .emit() + })?; // Require the hidden type to be well-formed with only the generics of the opaque type. // Defining use functions may have more bounds than the opaque type, which is ok, as long as the diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index d205862cd3f..38452df32e9 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -176,6 +176,11 @@ impl<N: Idx> LivenessValues<N> { pub(crate) fn region_value_str(&self, r: N) -> String { region_value_str(self.get_elements(r).map(RegionElement::Location)) } + + #[inline] + pub(crate) fn point_from_location(&self, location: Location) -> PointIndex { + self.elements.point_from_location(location) + } } /// Maps from `ty::PlaceholderRegion` values that are used in the rest of diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index b7adc314f07..fc600af1b76 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -49,7 +49,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // If the query has created new universes and errors are going to be emitted, register the // cause of these new universes for improved diagnostics. let universe = self.infcx.universe(); - if old_universe != universe && let Some(error_info) = error_info { + if old_universe != universe + && let Some(error_info) = error_info + { let universe_info = error_info.to_universe_info(old_universe); for u in (old_universe + 1)..=universe { self.borrowck_context.constraints.universe_causes.insert(u, universe_info.clone()); diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 5702d39db32..21da05c32dd 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -1,10 +1,11 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_index::bit_set::HybridBitSet; +use rustc_data_structures::graph::WithSuccessors; +use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix}; use rustc_index::interval::IntervalSet; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location}; use rustc_middle::traits::query::DropckOutlivesResult; -use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt}; +use rustc_middle::ty::{RegionVid, Ty, TyCtxt, TypeVisitable, TypeVisitableExt}; use rustc_span::DUMMY_SP; use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; @@ -14,6 +15,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex}; use rustc_mir_dataflow::ResultsCursor; +use crate::dataflow::BorrowIndex; use crate::{ region_infer::values::{self, PointIndex, RegionValueElements}, type_check::liveness::local_use_map::LocalUseMap, @@ -50,6 +52,33 @@ pub(super) fn trace<'mir, 'tcx>( let local_use_map = &LocalUseMap::build(&relevant_live_locals, elements, body); + // When using `-Zpolonius=next`, compute the set of loans that can reach a given region. + let num_loans = typeck.borrowck_context.borrow_set.len(); + let mut inflowing_loans = SparseBitMatrix::new(num_loans); + if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() { + let borrowck_context = &typeck.borrowck_context; + let borrow_set = &borrowck_context.borrow_set; + let constraint_set = &borrowck_context.constraints.outlives_constraints; + + let num_region_vars = typeck.infcx.num_region_vars(); + let graph = constraint_set.graph(num_region_vars); + let region_graph = + graph.region_graph(&constraint_set, borrowck_context.universal_regions.fr_static); + + // Traverse each issuing region's constraints, and record the loan as flowing into the + // outlived region. + for (loan, issuing_region_data) in borrow_set.iter_enumerated() { + for succ in region_graph.depth_first_search(issuing_region_data.region) { + // We don't need to mention that a loan flows into its issuing region. + if succ == issuing_region_data.region { + continue; + } + + inflowing_loans.insert(succ, loan); + } + } + }; + let cx = LivenessContext { typeck, body, @@ -58,6 +87,7 @@ pub(super) fn trace<'mir, 'tcx>( local_use_map, move_data, drop_data: FxIndexMap::default(), + inflowing_loans, }; let mut results = LivenessResults::new(cx); @@ -95,6 +125,9 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> { /// Index indicating where each variable is assigned, used, or /// dropped. local_use_map: &'me LocalUseMap, + + /// Set of loans that flow into a given region, when using `-Zpolonius=next`. + inflowing_loans: SparseBitMatrix<RegionVid, BorrowIndex>, } struct DropData<'tcx> { @@ -486,7 +519,13 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { ) { debug!("add_use_live_facts_for(value={:?})", value); - Self::make_all_regions_live(self.elements, &mut self.typeck, value, live_at) + Self::make_all_regions_live( + self.elements, + &mut self.typeck, + value, + live_at, + &self.inflowing_loans, + ); } /// Some variable with type `live_ty` is "drop live" at `location` @@ -537,7 +576,13 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { // All things in the `outlives` array may be touched by // the destructor and must be live at this point. for &kind in &drop_data.dropck_result.kinds { - Self::make_all_regions_live(self.elements, &mut self.typeck, kind, live_at); + Self::make_all_regions_live( + self.elements, + &mut self.typeck, + kind, + live_at, + &self.inflowing_loans, + ); polonius::add_drop_of_var_derefs_origin(&mut self.typeck, dropped_local, &kind); } @@ -548,6 +593,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { typeck: &mut TypeChecker<'_, 'tcx>, value: impl TypeVisitable<TyCtxt<'tcx>>, live_at: &IntervalSet<PointIndex>, + inflowing_loans: &SparseBitMatrix<RegionVid, BorrowIndex>, ) { debug!("make_all_regions_live(value={:?})", value); debug!( @@ -556,15 +602,35 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { ); let tcx = typeck.tcx(); + let borrowck_context = &mut typeck.borrowck_context; + + // When using `-Zpolonius=next`, we want to record the loans that flow into this value's + // regions as being live at the given `live_at` points: this will be used to compute the + // location where a loan goes out of scope. + let num_loans = borrowck_context.borrow_set.len(); + let mut value_loans = HybridBitSet::new_empty(num_loans); + tcx.for_each_free_region(&value, |live_region| { - let live_region_vid = - typeck.borrowck_context.universal_regions.to_region_vid(live_region); - typeck - .borrowck_context + let live_region_vid = borrowck_context.universal_regions.to_region_vid(live_region); + + borrowck_context .constraints .liveness_constraints .add_elements(live_region_vid, live_at); + + // There can only be inflowing loans for this region when we are using + // `-Zpolonius=next`. + if let Some(inflowing) = inflowing_loans.row(live_region_vid) { + value_loans.union(inflowing); + } }); + + // Record the loans reaching the value. + if !value_loans.is_empty() { + for point in live_at.iter() { + borrowck_context.live_loans.union_row(point, &value_loans); + } + } } fn compute_drop_data( diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index e7b1a489f5d..1ec0e62d16a 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -14,6 +14,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::lang_items::LangItem; +use rustc_index::bit_set::SparseBitMatrix; use rustc_index::{IndexSlice, IndexVec}; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives::env::RegionBoundPairs; @@ -50,6 +51,8 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::ResultsCursor; +use crate::dataflow::BorrowIndex; +use crate::region_infer::values::PointIndex; use crate::session_diagnostics::{MoveUnsized, SimdShuffleLastConst}; use crate::{ borrow_set::BorrowSet, @@ -163,6 +166,9 @@ pub(crate) fn type_check<'mir, 'tcx>( debug!(?normalized_inputs_and_output); + // When using `-Zpolonius=next`, liveness will record the set of live loans per point. + let mut live_loans = SparseBitMatrix::new(borrow_set.len()); + let mut borrowck_context = BorrowCheckContext { universal_regions, location_table, @@ -170,6 +176,7 @@ pub(crate) fn type_check<'mir, 'tcx>( all_facts, constraints: &mut constraints, upvars, + live_loans: &mut live_loans, }; let mut checker = TypeChecker::new( @@ -240,7 +247,7 @@ pub(crate) fn type_check<'mir, 'tcx>( }) .collect(); - MirTypeckResults { constraints, universal_region_relations, opaque_type_values } + MirTypeckResults { constraints, universal_region_relations, opaque_type_values, live_loans } } fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) { @@ -855,12 +862,21 @@ struct BorrowCheckContext<'a, 'tcx> { borrow_set: &'a BorrowSet<'tcx>, pub(crate) constraints: &'a mut MirTypeckRegionConstraints<'tcx>, upvars: &'a [Upvar<'tcx>], + + /// The set of loans that are live at a given point in the CFG, filled in by `liveness::trace`, + /// when using `-Zpolonius=next`. + pub(crate) live_loans: &'a mut SparseBitMatrix<PointIndex, BorrowIndex>, } +/// Holder struct for passing results from MIR typeck to the rest of the non-lexical regions +/// inference computation. pub(crate) struct MirTypeckResults<'tcx> { pub(crate) constraints: MirTypeckRegionConstraints<'tcx>, pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, pub(crate) opaque_type_values: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>, + + /// The set of loans that are live at a given point in the CFG, when using `-Zpolonius=next`. + pub(crate) live_loans: SparseBitMatrix<PointIndex, BorrowIndex>, } /// A collection of region constraints that must be satisfied for the diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index 82bae9157e7..070d50708ff 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -21,20 +21,22 @@ pub fn expand( // Allow using `#[alloc_error_handler]` on an item statement // FIXME - if we get deref patterns, use them to reduce duplication here - let (item, is_stmt, sig_span) = - if let Annotatable::Item(item) = &item - && let ItemKind::Fn(fn_kind) = &item.kind - { - (item, false, ecx.with_def_site_ctxt(fn_kind.sig.span)) - } else if let Annotatable::Stmt(stmt) = &item - && let StmtKind::Item(item) = &stmt.kind - && let ItemKind::Fn(fn_kind) = &item.kind - { - (item, true, ecx.with_def_site_ctxt(fn_kind.sig.span)) - } else { - ecx.sess.parse_sess.span_diagnostic.emit_err(errors::AllocErrorMustBeFn {span: item.span() }); - return vec![orig_item]; - }; + let (item, is_stmt, sig_span) = if let Annotatable::Item(item) = &item + && let ItemKind::Fn(fn_kind) = &item.kind + { + (item, false, ecx.with_def_site_ctxt(fn_kind.sig.span)) + } else if let Annotatable::Stmt(stmt) = &item + && let StmtKind::Item(item) = &stmt.kind + && let ItemKind::Fn(fn_kind) = &item.kind + { + (item, true, ecx.with_def_site_ctxt(fn_kind.sig.span)) + } else { + ecx.sess + .parse_sess + .span_diagnostic + .emit_err(errors::AllocErrorMustBeFn { span: item.span() }); + return vec![orig_item]; + }; // Generate a bunch of new items using the AllocFnFactory let span = ecx.with_def_site_ctxt(item.span); diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 9302db104b6..7abfcc8c50c 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -85,7 +85,7 @@ pub fn expand_assert<'cx>( DUMMY_SP, Symbol::intern(&format!( "assertion failed: {}", - pprust::expr_to_string(&cond_expr).escape_debug() + pprust::expr_to_string(&cond_expr) )), )], ); diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index 0682d48aca6..6733b9e56ad 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -193,10 +193,9 @@ impl<'cx, 'a> Context<'cx, 'a> { fn manage_cond_expr(&mut self, expr: &mut P<Expr>) { match &mut expr.kind { ExprKind::AddrOf(_, mutability, local_expr) => { - self.with_is_consumed_management( - matches!(mutability, Mutability::Mut), - |this| this.manage_cond_expr(local_expr) - ); + self.with_is_consumed_management(matches!(mutability, Mutability::Mut), |this| { + this.manage_cond_expr(local_expr) + }); } ExprKind::Array(local_exprs) => { for local_expr in local_exprs { @@ -223,7 +222,7 @@ impl<'cx, 'a> Context<'cx, 'a> { |this| { this.manage_cond_expr(lhs); this.manage_cond_expr(rhs); - } + }, ); } ExprKind::Call(_, local_exprs) => { @@ -285,10 +284,9 @@ impl<'cx, 'a> Context<'cx, 'a> { } } ExprKind::Unary(un_op, local_expr) => { - self.with_is_consumed_management( - matches!(un_op, UnOp::Neg | UnOp::Not), - |this| this.manage_cond_expr(local_expr) - ); + self.with_is_consumed_management(matches!(un_op, UnOp::Neg | UnOp::Not), |this| { + this.manage_cond_expr(local_expr) + }); } // Expressions that are not worth or can not be captured. // diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs index 9695fb4fee1..6b8330bfdaf 100644 --- a/compiler/rustc_builtin_macros/src/concat.rs +++ b/compiler/rustc_builtin_macros/src/concat.rs @@ -33,7 +33,7 @@ pub fn expand_concat( accumulator.push_str(&b.to_string()); } Ok(ast::LitKind::CStr(..)) => { - cx.emit_err(errors::ConcatCStrLit{ span: e.span}); + cx.emit_err(errors::ConcatCStrLit { span: e.span }); has_errors = true; } Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => { @@ -49,7 +49,9 @@ pub fn expand_concat( } }, // We also want to allow negative numeric literals. - ast::ExprKind::Unary(ast::UnOp::Neg, ref expr) if let ast::ExprKind::Lit(token_lit) = expr.kind => { + ast::ExprKind::Unary(ast::UnOp::Neg, ref expr) + if let ast::ExprKind::Lit(token_lit) = expr.kind => + { match ast::LitKind::from_token_lit(token_lit) { Ok(ast::LitKind::Int(i, _)) => accumulator.push_str(&format!("-{i}")), Ok(ast::LitKind::Float(f, _)) => accumulator.push_str(&format!("-{f}")), diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 6a1586f071c..c4f5af384c1 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -140,8 +140,8 @@ pub fn expand_concat_bytes( } ast::ExprKind::Repeat(expr, count) => { if let ast::ExprKind::Lit(token_lit) = count.value.kind - && let Ok(ast::LitKind::Int(count_val, _)) = - ast::LitKind::from_token_lit(token_lit) + && let Ok(ast::LitKind::Int(count_val, _)) = + ast::LitKind::from_token_lit(token_lit) { if let Some(elem) = handle_array_element(cx, &mut has_errors, &mut missing_literals, expr) @@ -151,7 +151,7 @@ pub fn expand_concat_bytes( } } } else { - cx.emit_err(errors::ConcatBytesBadRepeat {span: count.value.span }); + cx.emit_err(errors::ConcatBytesBadRepeat { span: count.value.span }); } } &ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index b468abe3249..1649cc76c8d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -106,7 +106,9 @@ fn cs_clone_simple( // This basic redundancy checking only prevents duplication of // assertions like `AssertParamIsClone<Foo>` where the type is a // simple name. That's enough to get a lot of cases, though. - if let Some(name) = field.ty.kind.is_simple_path() && !seen_type_names.insert(name) { + if let Some(name) = field.ty.kind.is_simple_path() + && !seen_type_names.insert(name) + { // Already produced an assertion for this type. } else { // let _: AssertParamIsClone<FieldTy>; diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index a000e4895d1..8a6d219379f 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -73,7 +73,9 @@ fn cs_total_eq_assert( // This basic redundancy checking only prevents duplication of // assertions like `AssertParamIsEq<Foo>` where the type is a // simple name. That's enough to get a lot of cases, though. - if let Some(name) = field.ty.kind.is_simple_path() && !seen_type_names.insert(name) { + if let Some(name) = field.ty.kind.is_simple_path() + && !seen_type_names.insert(name) + { // Already produced an assertion for this type. } else { // let _: AssertParamIsEq<FieldTy>; diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index a5b3a504e38..f3164bd2c2a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -21,25 +21,26 @@ pub fn expand_deriving_partial_ord( // Order in which to perform matching let tag_then_data = if let Annotatable::Item(item) = item - && let ItemKind::Enum(def, _) = &item.kind { - let dataful: Vec<bool> = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect(); - match dataful.iter().filter(|&&b| b).count() { - // No data, placing the tag check first makes codegen simpler - 0 => true, - 1..=2 => false, - _ => { - (0..dataful.len()-1).any(|i| { - if dataful[i] && let Some(idx) = dataful[i+1..].iter().position(|v| *v) { - idx >= 2 - } else { - false - } - }) + && let ItemKind::Enum(def, _) = &item.kind + { + let dataful: Vec<bool> = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect(); + match dataful.iter().filter(|&&b| b).count() { + // No data, placing the tag check first makes codegen simpler + 0 => true, + 1..=2 => false, + _ => (0..dataful.len() - 1).any(|i| { + if dataful[i] + && let Some(idx) = dataful[i + 1..].iter().position(|v| *v) + { + idx >= 2 + } else { + false } - } - } else { - true - }; + }), + } + } else { + true + }; let partial_cmp_def = MethodDef { name: sym::partial_cmp, generics: Bounds::empty(), @@ -133,12 +134,16 @@ fn cs_partial_cmp( if !tag_then_data && let ExprKind::Match(_, arms) = &mut expr1.kind && let Some(last) = arms.last_mut() - && let PatKind::Wild = last.pat.kind { - last.body = expr2; - expr1 + && let PatKind::Wild = last.pat.kind + { + last.body = expr2; + expr1 } else { - let eq_arm = - cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1); + let eq_arm = cx.arm( + span, + cx.pat_some(span, cx.pat_path(span, equal_path.clone())), + expr1, + ); let neq_arm = cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id)); cx.expr_match(span, expr2, thin_vec![eq_arm, neq_arm]) diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 8397b5e4221..4b5c777f4ad 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -73,7 +73,9 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult< let first_token = &p.token; - let fmtstr = if let token::Literal(lit) = first_token.kind && matches!(lit.kind, token::Str | token::StrRaw(_)) { + let fmtstr = if let token::Literal(lit) = first_token.kind + && matches!(lit.kind, token::Str | token::StrRaw(_)) + { // This allows us to properly handle cases when the first comma // after the format string is mistakenly replaced with any operator, // which cause the expression parser to eat too much tokens. @@ -176,7 +178,7 @@ fn make_format_args( && block.stmts.len() == 1 && let StmtKind::Expr(expr) = &block.stmts[0].kind && let ExprKind::Path(None, path) = &expr.kind - && path.is_potential_trivial_const_arg() + && path.is_potential_trivial_const_arg() { err.multipart_suggestion( "quote your inlined format argument to use as string literal", @@ -184,7 +186,7 @@ fn make_format_args( (unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()), (unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()), ], - Applicability::MaybeIncorrect, + Applicability::MaybeIncorrect, ); } else { let sugg_fmt = match args.explicit_args().len() { @@ -257,8 +259,13 @@ fn make_format_args( if let Some(note) = err.note { e.note_ = Some(errors::InvalidFormatStringNote { note }); } - if let Some((label, span)) = err.secondary_label && is_source_literal { - e.label_ = Some(errors::InvalidFormatStringLabel { span: fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label } ); + if let Some((label, span)) = err.secondary_label + && is_source_literal + { + e.label_ = Some(errors::InvalidFormatStringLabel { + span: fmt_span.from_inner(InnerSpan::new(span.start, span.end)), + label, + }); } match err.suggestion { parse::Suggestion::None => {} diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 1bec00add55..33392edf060 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -24,20 +24,22 @@ pub fn expand( // Allow using `#[global_allocator]` on an item statement // FIXME - if we get deref patterns, use them to reduce duplication here - let (item, is_stmt, ty_span) = - if let Annotatable::Item(item) = &item - && let ItemKind::Static(box ast::StaticItem { ty, ..}) = &item.kind - { - (item, false, ecx.with_def_site_ctxt(ty.span)) - } else if let Annotatable::Stmt(stmt) = &item - && let StmtKind::Item(item) = &stmt.kind - && let ItemKind::Static(box ast::StaticItem { ty, ..}) = &item.kind - { - (item, true, ecx.with_def_site_ctxt(ty.span)) - } else { - ecx.sess.parse_sess.span_diagnostic.emit_err(errors::AllocMustStatics{span: item.span()}); - return vec![orig_item]; - }; + let (item, is_stmt, ty_span) = if let Annotatable::Item(item) = &item + && let ItemKind::Static(box ast::StaticItem { ty, .. }) = &item.kind + { + (item, false, ecx.with_def_site_ctxt(ty.span)) + } else if let Annotatable::Stmt(stmt) = &item + && let StmtKind::Item(item) = &stmt.kind + && let ItemKind::Static(box ast::StaticItem { ty, .. }) = &item.kind + { + (item, true, ecx.with_def_site_ctxt(ty.span)) + } else { + ecx.sess + .parse_sess + .span_diagnostic + .emit_err(errors::AllocMustStatics { span: item.span() }); + return vec![orig_item]; + }; // Generate a bunch of new items using the AllocFnFactory let span = ecx.with_def_site_ctxt(item.span); diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index ebf1448f55c..d84742c9b82 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -1,6 +1,9 @@ //! This crate contains implementations of built-in macros and other code generating facilities //! injecting code into the crate before it is lowered to HIR. +#![cfg_attr(not(bootstrap), allow(internal_features))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), doc(rust_logo))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(array_windows)] #![feature(box_patterns)] @@ -71,33 +74,35 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { } register_bang! { + // tidy-alphabetical-start asm: asm::expand_asm, assert: assert::expand_assert, cfg: cfg::expand_cfg, column: source_util::expand_column, compile_error: compile_error::expand_compile_error, + concat: concat::expand_concat, concat_bytes: concat_bytes::expand_concat_bytes, concat_idents: concat_idents::expand_concat_idents, - concat: concat::expand_concat, + const_format_args: format::expand_format_args, + core_panic: edition_panic::expand_panic, env: env::expand_env, file: source_util::expand_file, - format_args_nl: format::expand_format_args_nl, format_args: format::expand_format_args, - const_format_args: format::expand_format_args, + format_args_nl: format::expand_format_args_nl, global_asm: asm::expand_global_asm, + include: source_util::expand_include, include_bytes: source_util::expand_include_bytes, include_str: source_util::expand_include_str, - include: source_util::expand_include, line: source_util::expand_line, log_syntax: log_syntax::expand_log_syntax, module_path: source_util::expand_mod, option_env: env::expand_option_env, - core_panic: edition_panic::expand_panic, std_panic: edition_panic::expand_panic, - unreachable: edition_panic::expand_unreachable, stringify: source_util::expand_stringify, trace_macros: trace_macros::expand_trace_macros, type_ascribe: type_ascribe::expand_type_ascribe, + unreachable: edition_panic::expand_unreachable, + // tidy-alphabetical-end } register_attr! { diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 1580a6f6dd3..6d55603c708 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -35,11 +35,13 @@ pub fn expand_test_case( let sp = ecx.with_def_site_ctxt(attr_sp); let (mut item, is_stmt) = match anno_item { Annotatable::Item(item) => (item, false), - Annotatable::Stmt(stmt) if let ast::StmtKind::Item(_) = stmt.kind => if let ast::StmtKind::Item(i) = stmt.into_inner().kind { - (i, true) - } else { - unreachable!() - }, + Annotatable::Stmt(stmt) if let ast::StmtKind::Item(_) = stmt.kind => { + if let ast::StmtKind::Item(i) = stmt.into_inner().kind { + (i, true) + } else { + unreachable!() + } + } _ => { ecx.emit_err(errors::TestCaseNonItem { span: anno_item.span() }); return vec![]; diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index cc2f5d72714..49f51f9f956 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -7,14 +7,15 @@ use std::sync::Arc; use std::thread::JoinHandle; use cranelift_object::{ObjectBuilder, ObjectModule}; +use rustc_codegen_ssa::assert_module_sources::CguReuse; use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file; +use rustc_codegen_ssa::base::determine_cgu_reuse; use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::mir::mono::{CodegenUnit, MonoItem}; -use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{DebugInfo, OutputFilenames, OutputType}; use rustc_session::Session; @@ -374,43 +375,47 @@ pub(crate) fn run_aot( } } + // Calculate the CGU reuse + let cgu_reuse = tcx.sess.time("find_cgu_reuse", || { + cgus.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect::<Vec<_>>() + }); + + rustc_codegen_ssa::assert_module_sources::assert_module_sources(tcx, &|cgu_reuse_tracker| { + for (i, cgu) in cgus.iter().enumerate() { + let cgu_reuse = cgu_reuse[i]; + cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse); + } + }); + let global_asm_config = Arc::new(crate::global_asm::GlobalAsmConfig::new(tcx)); let mut concurrency_limiter = ConcurrencyLimiter::new(tcx.sess, cgus.len()); let modules = tcx.sess.time("codegen mono items", || { cgus.iter() - .map(|cgu| { - let cgu_reuse = if backend_config.disable_incr_cache { - CguReuse::No - } else { - determine_cgu_reuse(tcx, cgu) - }; - tcx.sess.cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse); - - match cgu_reuse { - CguReuse::No => { - let dep_node = cgu.codegen_dep_node(tcx); - tcx.dep_graph - .with_task( - dep_node, - tcx, - ( - backend_config.clone(), - global_asm_config.clone(), - cgu.name(), - concurrency_limiter.acquire(tcx.sess.diagnostic()), - ), - module_codegen, - Some(rustc_middle::dep_graph::hash_result), - ) - .0 - } - CguReuse::PreLto => unreachable!(), - CguReuse::PostLto => { - concurrency_limiter.job_already_done(); - OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu)) - } + .enumerate() + .map(|(i, cgu)| match cgu_reuse[i] { + CguReuse::No => { + let dep_node = cgu.codegen_dep_node(tcx); + tcx.dep_graph + .with_task( + dep_node, + tcx, + ( + backend_config.clone(), + global_asm_config.clone(), + cgu.name(), + concurrency_limiter.acquire(tcx.sess.diagnostic()), + ), + module_codegen, + Some(rustc_middle::dep_graph::hash_result), + ) + .0 + } + CguReuse::PreLto => unreachable!("LTO not yet supported"), + CguReuse::PostLto => { + concurrency_limiter.job_already_done(); + OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu)) } }) .collect::<Vec<_>>() @@ -489,32 +494,3 @@ pub(crate) fn run_aot( concurrency_limiter, }) } - -// Adapted from https://github.com/rust-lang/rust/blob/303d8aff6092709edd4dbd35b1c88e9aa40bf6d8/src/librustc_codegen_ssa/base.rs#L922-L953 -fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse { - if !tcx.dep_graph.is_fully_enabled() { - return CguReuse::No; - } - - let work_product_id = &cgu.work_product_id(); - if tcx.dep_graph.previous_work_product(work_product_id).is_none() { - // We don't have anything cached for this CGU. This can happen - // if the CGU did not exist in the previous session. - return CguReuse::No; - } - - // Try to mark the CGU as green. If it we can do so, it means that nothing - // affecting the LLVM module has changed and we can re-use a cached version. - // If we compile with any kind of LTO, this means we can re-use the bitcode - // of the Pre-LTO stage (possibly also the Post-LTO version but we'll only - // know that later). If we are not doing LTO, there is only one optimized - // version of each module, so we re-use that. - let dep_node = cgu.codegen_dep_node(tcx); - assert!( - !tcx.dep_graph.dep_node_exists(&dep_node), - "CompileCodegenUnit dep-node for CGU `{}` already exists before marking.", - cgu.name() - ); - - if tcx.try_mark_green(&dep_node) { CguReuse::PostLto } else { CguReuse::No } -} diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 522fe7e425b..8992de5a923 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -1,3 +1,6 @@ +#![cfg_attr(not(bootstrap), allow(internal_features))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), doc(rust_logo))] #![feature(rustc_private)] // Note: please avoid adding other feature gates where possible #![warn(rust_2018_idioms)] diff --git a/compiler/rustc_codegen_gcc/.github/workflows/ci.yml b/compiler/rustc_codegen_gcc/.github/workflows/ci.yml index d2b7724a221..f075c744e45 100644 --- a/compiler/rustc_codegen_gcc/.github/workflows/ci.yml +++ b/compiler/rustc_codegen_gcc/.github/workflows/ci.yml @@ -57,8 +57,8 @@ jobs: uses: dawidd6/action-download-artifact@v2 with: workflow: main.yml - name: ${{ matrix.libgccjit_version.gcc }} - path: gcc-build + name: gcc-13 + path: gcc-13 repo: antoyo/gcc branch: ${{ matrix.libgccjit_version.artifacts_branch }} event: push @@ -71,9 +71,8 @@ jobs: - name: Setup path to libgccjit if: matrix.libgccjit_version.gcc != 'libgccjit12.so' run: | - echo $(readlink -f gcc-build) > gcc_path - # NOTE: the filename is still libgccjit.so even when the artifact name is different. - ln gcc-build/libgccjit.so gcc-build/libgccjit.so.0 + sudo dpkg --force-overwrite -i gcc-13/gcc-13.deb + echo /usr/lib/ > gcc_path - name: Set env run: | @@ -119,8 +118,8 @@ jobs: - name: Build run: | - ./prepare_build.sh - ${{ matrix.libgccjit_version.env_extra }} ./build.sh ${{ matrix.libgccjit_version.extra }} + ./y.sh prepare --only-libcore + ${{ matrix.libgccjit_version.env_extra }} ./y.sh build ${{ matrix.libgccjit_version.extra }} ${{ matrix.libgccjit_version.env_extra }} cargo test ${{ matrix.libgccjit_version.extra }} ./clean_all.sh @@ -128,7 +127,7 @@ jobs: run: | git config --global user.email "user@example.com" git config --global user.name "User" - ./prepare.sh + ./y.sh prepare # Compile is a separate step, as the actions-rs/cargo action supports error annotations - name: Compile @@ -141,6 +140,9 @@ jobs: if: ${{ matrix.libgccjit_version.gcc == 'libgccjit12.so' }} run: cat failing-ui-tests12.txt >> failing-ui-tests.txt + - name: Add more failing tests because the sysroot is not compiled with LTO + run: cat failing-non-lto-tests.txt >> failing-ui-tests.txt + - name: Run tests run: | ${{ matrix.libgccjit_version.env_extra }} ./test.sh --release --clean --build-sysroot ${{ matrix.commands }} ${{ matrix.libgccjit_version.extra }} diff --git a/compiler/rustc_codegen_gcc/.github/workflows/release.yml b/compiler/rustc_codegen_gcc/.github/workflows/release.yml index c4e99469bc2..bd0415040e7 100644 --- a/compiler/rustc_codegen_gcc/.github/workflows/release.yml +++ b/compiler/rustc_codegen_gcc/.github/workflows/release.yml @@ -18,8 +18,6 @@ jobs: strategy: fail-fast: false matrix: - libgccjit_version: - - { gcc: "libgccjit.so", artifacts_branch: "master" } commands: [ "--test-successful-rustc --nb-parts 2 --current-part 0", "--test-successful-rustc --nb-parts 2 --current-part 1", @@ -40,18 +38,17 @@ jobs: uses: dawidd6/action-download-artifact@v2 with: workflow: main.yml - name: ${{ matrix.libgccjit_version.gcc }} - path: gcc-build + name: gcc-13 + path: gcc-13 repo: antoyo/gcc - branch: ${{ matrix.libgccjit_version.artifacts_branch }} + branch: "master" event: push search_artifacts: true # Because, instead, the action only check the last job ran and that won't work since we want multiple artifacts. - name: Setup path to libgccjit run: | - echo $(readlink -f gcc-build) > gcc_path - # NOTE: the filename is still libgccjit.so even when the artifact name is different. - ln gcc-build/libgccjit.so gcc-build/libgccjit.so.0 + sudo dpkg --force-overwrite -i gcc-13/gcc-13.deb + echo /usr/lib/ > gcc_path - name: Set env run: | @@ -88,8 +85,8 @@ jobs: - name: Build run: | - ./prepare_build.sh - ./build.sh --release --release-sysroot + ./y.sh prepare --only-libcore + EMBED_LTO_BITCODE=1 ./y.sh build --release --release-sysroot cargo test ./clean_all.sh @@ -97,7 +94,9 @@ jobs: run: | git config --global user.email "user@example.com" git config --global user.name "User" - ./prepare.sh + ./y.sh prepare + # FIXME(antoyo): we cannot enable LTO for stdarch tests currently because of some failing LTO tests using proc-macros. + echo -n 'lto = "fat"' >> build_sysroot/Cargo.toml # Compile is a separate step, as the actions-rs/cargo action supports error annotations - name: Compile @@ -106,6 +105,9 @@ jobs: command: build args: --release + - name: Add more failing tests because of undefined symbol errors (FIXME) + run: cat failing-lto-tests.txt >> failing-ui-tests.txt + - name: Run tests run: | - ./test.sh --release --clean --release-sysroot --build-sysroot ${{ matrix.commands }} + EMBED_LTO_BITCODE=1 ./test.sh --release --clean --release-sysroot --build-sysroot ${{ matrix.commands }} diff --git a/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml b/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml index 556c6444833..6c28326823c 100644 --- a/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml +++ b/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml @@ -18,8 +18,6 @@ jobs: strategy: fail-fast: false matrix: - libgccjit_version: - - { gcc: "libgccjit.so", artifacts_branch: "master" } cargo_runner: [ "sde -future -rtm_mode full --", "", @@ -54,18 +52,17 @@ jobs: uses: dawidd6/action-download-artifact@v2 with: workflow: main.yml - name: ${{ matrix.libgccjit_version.gcc }} - path: gcc-build + name: gcc-13 + path: gcc-13 repo: antoyo/gcc - branch: ${{ matrix.libgccjit_version.artifacts_branch }} + branch: "master" event: push search_artifacts: true # Because, instead, the action only check the last job ran and that won't work since we want multiple artifacts. - name: Setup path to libgccjit run: | - echo $(readlink -f gcc-build) > gcc_path - # NOTE: the filename is still libgccjit.so even when the artifact name is different. - ln gcc-build/libgccjit.so gcc-build/libgccjit.so.0 + sudo dpkg --force-overwrite -i gcc-13/gcc-13.deb + echo /usr/lib/ > gcc_path - name: Set env run: | @@ -102,8 +99,8 @@ jobs: - name: Build run: | - ./prepare_build.sh - ./build.sh --release --release-sysroot + ./y.sh prepare --only-libcore + ./y.sh build --release --release-sysroot cargo test - name: Clean @@ -115,7 +112,7 @@ jobs: run: | git config --global user.email "user@example.com" git config --global user.name "User" - ./prepare.sh + ./y.sh prepare # Compile is a separate step, as the actions-rs/cargo action supports error annotations - name: Compile @@ -133,10 +130,11 @@ jobs: if: ${{ !matrix.cargo_runner }} run: | cd build_sysroot/sysroot_src/library/stdarch/ - CHANNEL=release TARGET=x86_64-unknown-linux-gnu ../../../../cargo.sh test + CHANNEL=release TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features" ../../../../cargo.sh test - name: Run stdarch tests if: ${{ matrix.cargo_runner }} run: | cd build_sysroot/sysroot_src/library/stdarch/ - STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu ../../../../cargo.sh test -- --skip rtm --skip tbm --skip sse4a + # FIXME: these tests fail when the sysroot is compiled with LTO because of a missing symbol in proc-macro. + STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features" ../../../../cargo.sh test -- --skip rtm --skip tbm --skip sse4a diff --git a/compiler/rustc_codegen_gcc/.gitignore b/compiler/rustc_codegen_gcc/.gitignore index c5ed7de200c..b44d1aa78c2 100644 --- a/compiler/rustc_codegen_gcc/.gitignore +++ b/compiler/rustc_codegen_gcc/.gitignore @@ -25,3 +25,4 @@ tools/llvmint tools/llvmint-2 # The `llvm` folder is generated by the `tools/generate_intrinsics.py` script to update intrinsics. llvm +build_system/target diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock index 1c8754bf675..85675fc40c3 100644 --- a/compiler/rustc_codegen_gcc/Cargo.lock +++ b/compiler/rustc_codegen_gcc/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "aho-corasick" -version = "0.7.18" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] @@ -18,12 +18,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fastrand" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" + +[[package]] name = "fm" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -35,7 +74,7 @@ dependencies = [ [[package]] name = "gccjit" version = "1.0.0" -source = "git+https://github.com/antoyo/gccjit.rs#d6e52626cfc6f487094a5d5ac66302baf3439984" +source = "git+https://github.com/antoyo/gccjit.rs#0b158c68bf7e46732869d90550a98e886dee8858" dependencies = [ "gccjit_sys", ] @@ -43,7 +82,7 @@ dependencies = [ [[package]] name = "gccjit_sys" version = "0.0.1" -source = "git+https://github.com/antoyo/gccjit.rs#d6e52626cfc6f487094a5d5ac66302baf3439984" +source = "git+https://github.com/antoyo/gccjit.rs#0b158c68bf7e46732869d90550a98e886dee8858" dependencies = [ "libc", ] @@ -58,24 +97,10 @@ dependencies = [ ] [[package]] -name = "getrandom" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] name = "hermit-abi" -version = "0.1.19" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" [[package]] name = "lang_tester" @@ -95,86 +120,55 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.112" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] -name = "memchr" -version = "2.4.1" +name = "linux-raw-sys" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" [[package]] -name = "num_cpus" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.15" +name = "memchr" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] -name = "rand" -version = "0.8.4" +name = "num_cpus" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ + "hermit-abi", "libc", - "rand_chacha", - "rand_core", - "rand_hc", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" -dependencies = [ - "getrandom", ] [[package]] -name = "rand_hc" -version = "0.3.1" +name = "object" +version = "0.30.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" dependencies = [ - "rand_core", + "memchr", ] [[package]] name = "redox_syscall" -version = "0.2.10" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] name = "regex" -version = "1.5.4" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ "aho-corasick", "memchr", @@ -183,18 +177,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" - -[[package]] -name = "remove_dir_all" -version = "0.5.3" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "rustc_codegen_gcc" @@ -202,11 +187,25 @@ version = "0.1.0" dependencies = [ "gccjit", "lang_tester", + "object", "smallvec", "tempfile", ] [[package]] +name = "rustix" +version = "0.38.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -223,23 +222,22 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "tempfile" -version = "3.2.0" +version = "3.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651" dependencies = [ "cfg-if", - "libc", - "rand", + "fastrand", "redox_syscall", - "remove_dir_all", - "winapi", + "rustix", + "windows-sys", ] [[package]] name = "termcolor" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] @@ -255,9 +253,9 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "wait-timeout" @@ -270,22 +268,15 @@ dependencies = [ [[package]] name = "walkdir" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" dependencies = [ "same-file", - "winapi", "winapi-util", ] [[package]] -name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" - -[[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -315,3 +306,69 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml index 81066d9ce1f..51fab147aa2 100644 --- a/compiler/rustc_codegen_gcc/Cargo.toml +++ b/compiler/rustc_codegen_gcc/Cargo.toml @@ -27,7 +27,13 @@ gccjit = { git = "https://github.com/antoyo/gccjit.rs" } # Local copy. #gccjit = { path = "../gccjit.rs" } +object = { version = "0.30.1", default-features = false, features = [ + "std", + "read", +] } smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } +# TODO(antoyo): make tempfile optional. +tempfile = "3.7.1" [dev-dependencies] lang_tester = "0.3.9" diff --git a/compiler/rustc_codegen_gcc/Readme.md b/compiler/rustc_codegen_gcc/Readme.md index a93637d9038..f001c83b08d 100644 --- a/compiler/rustc_codegen_gcc/Readme.md +++ b/compiler/rustc_codegen_gcc/Readme.md @@ -1,6 +1,7 @@ # WIP libgccjit codegen backend for rust [](https://web.libera.chat/#rustc_codegen_gcc) +[](https://matrix.to/#/#rustc_codegen_gcc:matrix.org) This is a GCC codegen for rustc, which means it can be loaded by the existing rustc frontend, but benefits from GCC: more architectures are supported and GCC's optimizations are used. @@ -14,9 +15,7 @@ A secondary goal is to check if using the gcc backend will provide any run-time ## Building **This requires a patched libgccjit in order to work. -The patches in [this repository](https://github.com/antoyo/libgccjit-patches) need to be applied. -(Those patches should work when applied on master, but in case it doesn't work, they are known to work when applied on 079c23cfe079f203d5df83fea8e92a60c7d7e878.) -You can also use my [fork of gcc](https://github.com/antoyo/gcc) which already includes these patches.** +You need to use my [fork of gcc](https://github.com/antoyo/gcc) which already includes these patches.** To build it (most of these instructions come from [here](https://gcc.gnu.org/onlinedocs/jit/internals/index.html), so don't hesitate to take a look there if you encounter an issue): @@ -66,8 +65,8 @@ $ export RUST_COMPILER_RT_ROOT="$PWD/llvm/compiler-rt" Then you can run commands like this: ```bash -$ ./prepare.sh # download and patch sysroot src and install hyperfine for benchmarking -$ LIBRARY_PATH=$(cat gcc_path) LD_LIBRARY_PATH=$(cat gcc_path) ./build.sh --release +$ ./y.sh prepare # download and patch sysroot src and install hyperfine for benchmarking +$ LIBRARY_PATH=$(cat gcc_path) LD_LIBRARY_PATH=$(cat gcc_path) ./y.sh build --release ``` To run the tests: @@ -78,22 +77,29 @@ $ ./test.sh --release ## Usage -`$cg_gccjit_dir` is the directory you cloned this repo into in the following instructions. +`$CG_GCCJIT_DIR` is the directory you cloned this repo into in the following instructions: + +```bash +export CG_GCCJIT_DIR=[the full path to rustc_codegen_gcc] +``` ### Cargo ```bash -$ CHANNEL="release" $cg_gccjit_dir/cargo.sh run +$ CHANNEL="release" $CG_GCCJIT_DIR/cargo.sh run ``` If you compiled cg_gccjit in debug mode (aka you didn't pass `--release` to `./test.sh`) you should use `CHANNEL="debug"` instead or omit `CHANNEL="release"` completely. +To use LTO, you need to set the variable `FAT_LTO=1` and `EMBED_LTO_BITCODE=1` in addition to setting `lto = "fat"` in the `Cargo.toml`. +Don't set `FAT_LTO` when compiling the sysroot, though: only set `EMBED_LTO_BITCODE=1`. + ### Rustc > You should prefer using the Cargo method. ```bash -$ rustc +$(cat $cg_gccjit_dir/rust-toolchain) -Cpanic=abort -Zcodegen-backend=$cg_gccjit_dir/target/release/librustc_codegen_gcc.so --sysroot $cg_gccjit_dir/build_sysroot/sysroot my_crate.rs +$ LIBRARY_PATH=$(cat gcc_path) LD_LIBRARY_PATH=$(cat gcc_path) rustc +$(cat $CG_GCCJIT_DIR/rust-toolchain | grep 'channel' | cut -d '=' -f 2 | sed 's/"//g' | sed 's/ //g') -Cpanic=abort -Zcodegen-backend=$CG_GCCJIT_DIR/target/release/librustc_codegen_gcc.so --sysroot $CG_GCCJIT_DIR/build_sysroot/sysroot my_crate.rs ``` ## Env vars @@ -105,8 +111,18 @@ $ rustc +$(cat $cg_gccjit_dir/rust-toolchain) -Cpanic=abort -Zcodegen-backend=$c object files when their content should have been changed by a change to cg_gccjit.</dd> <dt>CG_GCCJIT_DISPLAY_CG_TIME</dt> <dd>Display the time it took to perform codegen for a crate</dd> + <dt>CG_RUSTFLAGS</dt> + <dd>Send additional flags to rustc. Can be used to build the sysroot without unwinding by setting `CG_RUSTFLAGS=-Cpanic=abort`.</dd> + <dt>CG_GCCJIT_DUMP_TO_FILE</dt> + <dd>Dump a C-like representation to /tmp/gccjit_dumps and enable debug info in order to debug this C-like representation.</dd> </dl> +## Licensing + +While this crate is licensed under a dual Apache/MIT license, it links to `libgccjit` which is under the GPLv3+ and thus, the resulting toolchain (rustc + GCC codegen) will need to be released under the GPL license. + +However, programs compiled with `rustc_codegen_gcc` do not need to be released under a GPL license. + ## Debugging Sometimes, libgccjit will crash and output an error like this: @@ -182,6 +198,61 @@ set substitute-path /usr/src/debug/gcc /path/to/gcc-repo/gcc TODO(antoyo): but that's not what I remember I was doing. +### `failed to build archive` error + +When you get this error: + +``` +error: failed to build archive: failed to open object file: No such file or directory (os error 2) +``` + +That can be caused by the fact that you try to compile with `lto = "fat"`, but you didn't compile the sysroot with LTO. +(Not sure if that's the reason since I cannot reproduce anymore. Maybe it happened when forgetting setting `FAT_LTO`.) + +### ld: cannot find crtbegin.o + +When compiling an executable with libgccijt, if setting the `*LIBRARY_PATH` variables to the install directory, you will get the following errors: + +``` +ld: cannot find crtbegin.o: No such file or directory +ld: cannot find -lgcc: No such file or directory +ld: cannot find -lgcc: No such file or directory +libgccjit.so: error: error invoking gcc driver +``` + +To fix this, set the variables to `gcc-build/build/gcc`. + +### How to debug GCC LTO + +Run do the command with `-v -save-temps` and then extract the `lto1` line from the output and run that under the debugger. + +### How to send arguments to the GCC linker + +``` +CG_RUSTFLAGS="-Clink-args=-save-temps -v" ../cargo.sh build +``` + +### How to see the personality functions in the asm dump + +``` +CG_RUSTFLAGS="-Clink-arg=-save-temps -v -Clink-arg=-dA" ../cargo.sh build +``` + +### How to see the LLVM IR for a sysroot crate + +``` +cargo build -v --target x86_64-unknown-linux-gnu -Zbuild-std +# Take the command from the output and add --emit=llvm-ir +``` + +### To prevent the linker from unmangling symbols + +Run with: + +``` +COLLECT_NO_DEMANGLE=1 +``` + ### How to use a custom-build rustc * Build the stage2 compiler (`rustup toolchain link debug-current build/x86_64-unknown-linux-gnu/stage2`). @@ -223,6 +294,11 @@ https://rust-lang.zulipchat.com/#narrow/stream/301329-t-devtools/topic/subtree.2 `rustc` needs to be built without `jemalloc` so that `mem-trace` can overload `malloc` since `jemalloc` is linked statically, so a `LD_PRELOAD`-ed library won't a chance to intercept the calls to `malloc`. +### How to generate GIMPLE + +If you need to check what gccjit is generating (GIMPLE), then take a look at how to +generate it in [gimple.md](./doc/gimple.md). + ### How to build a cross-compiling libgccjit #### Building libgccjit @@ -239,4 +315,4 @@ https://rust-lang.zulipchat.com/#narrow/stream/301329-t-devtools/topic/subtree.2 * Set `linker='-Clinker=m68k-linux-gcc'`. * Set the path to the cross-compiling libgccjit in `gcc_path`. * Comment the line: `context.add_command_line_option("-masm=intel");` in src/base.rs. - * (might not be necessary) Disable the compilation of libstd.so (and possibly libcore.so?). + * (might not be necessary) Disable the compilation of libstd.so (and possibly libcore.so?): Remove dylib from build_sysroot/sysroot_src/library/std/Cargo.toml. diff --git a/compiler/rustc_codegen_gcc/build.sh b/compiler/rustc_codegen_gcc/build.sh deleted file mode 100755 index ba0d0d04948..00000000000 --- a/compiler/rustc_codegen_gcc/build.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env bash - -#set -x -set -e - -codegen_channel=debug -sysroot_channel=debug - -flags= - -while [[ $# -gt 0 ]]; do - case $1 in - --release) - codegen_channel=release - shift - ;; - --release-sysroot) - sysroot_channel=release - shift - ;; - --no-default-features) - flags="$flags --no-default-features" - shift - ;; - --features) - shift - flags="$flags --features $1" - shift - ;; - *) - echo "Unknown option $1" - exit 1 - ;; - esac -done - -if [ -f ./gcc_path ]; then - export GCC_PATH=$(cat gcc_path) -else - echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details' - exit 1 -fi - -export LD_LIBRARY_PATH="$GCC_PATH" -export LIBRARY_PATH="$GCC_PATH" - -if [[ "$codegen_channel" == "release" ]]; then - export CHANNEL='release' - CARGO_INCREMENTAL=1 cargo rustc --release $flags -else - echo $LD_LIBRARY_PATH - export CHANNEL='debug' - cargo rustc $flags -fi - -source config.sh - -rm -r target/out || true -mkdir -p target/out/gccjit - -echo "[BUILD] sysroot" -if [[ "$sysroot_channel" == "release" ]]; then - time ./build_sysroot/build_sysroot.sh --release -else - time ./build_sysroot/build_sysroot.sh -fi - diff --git a/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml b/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml index a84f86a8218..e5658273c97 100644 --- a/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml +++ b/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml @@ -2,6 +2,7 @@ authors = ["bjorn3 <bjorn3@users.noreply.github.com>"] name = "sysroot" version = "0.0.0" +resolver = "2" [dependencies] core = { path = "./sysroot_src/library/core" } @@ -18,3 +19,4 @@ rustc-std-workspace-std = { path = "./sysroot_src/library/rustc-std-workspace-st [profile.release] debug = true +#lto = "fat" # TODO(antoyo): re-enable when the failing LTO tests regarding proc-macros are fixed. diff --git a/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh b/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh index 9d692d599f6..851e9895ce2 100755 --- a/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh +++ b/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh @@ -5,9 +5,9 @@ set -e cd $(dirname "$0") -pushd ../ >/dev/null +pushd ../ source ./config.sh -popd >/dev/null +popd # Cleanup for previous run # v Clean target dir except for build scripts and incremental cache diff --git a/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh b/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh deleted file mode 100755 index 71b3876bac2..00000000000 --- a/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash -set -e -cd $(dirname "$0") - -SRC_DIR=$(dirname $(rustup which rustc))"/../lib/rustlib/src/rust/" -DST_DIR="sysroot_src" - -if [ ! -e $SRC_DIR ]; then - echo "Please install rust-src component" - exit 1 -fi - -rm -rf $DST_DIR -mkdir -p $DST_DIR/library -cp -r $SRC_DIR/library $DST_DIR/ - -pushd $DST_DIR -echo "[GIT] init" -git init -echo "[GIT] add" -git add . -echo "[GIT] commit" - -# This is needed on systems where nothing is configured. -# git really needs something here, or it will fail. -# Even using --author is not enough. -git config user.email || git config user.email "none@example.com" -git config user.name || git config user.name "None" - -git commit -m "Initial commit" -q -for file in $(ls ../../patches/ | grep -v patcha); do - echo "[GIT] apply" $file - git apply ../../patches/$file - git add -A - git commit --no-gpg-sign -m "Patch $file" -done -popd - -echo "Successfully prepared libcore for building" diff --git a/compiler/rustc_codegen_gcc/build_system/Cargo.lock b/compiler/rustc_codegen_gcc/build_system/Cargo.lock new file mode 100644 index 00000000000..86268e19160 --- /dev/null +++ b/compiler/rustc_codegen_gcc/build_system/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "y" +version = "0.1.0" diff --git a/compiler/rustc_codegen_gcc/build_system/Cargo.toml b/compiler/rustc_codegen_gcc/build_system/Cargo.toml new file mode 100644 index 00000000000..f36709ea036 --- /dev/null +++ b/compiler/rustc_codegen_gcc/build_system/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "y" +version = "0.1.0" +edition = "2021" + +[[bin]] +name = "y" +path = "src/main.rs" diff --git a/compiler/rustc_codegen_gcc/build_system/src/build.rs b/compiler/rustc_codegen_gcc/build_system/src/build.rs new file mode 100644 index 00000000000..e2819c37ad9 --- /dev/null +++ b/compiler/rustc_codegen_gcc/build_system/src/build.rs @@ -0,0 +1,233 @@ +use crate::config::set_config; +use crate::utils::{ + get_gcc_path, run_command, run_command_with_env, run_command_with_output_and_env, walk_dir, +}; +use std::collections::HashMap; +use std::ffi::OsStr; +use std::fs; +use std::path::Path; + +#[derive(Default)] +struct BuildArg { + codegen_release_channel: bool, + sysroot_release_channel: bool, + features: Vec<String>, + gcc_path: String, +} + +impl BuildArg { + fn new() -> Result<Option<Self>, String> { + let gcc_path = get_gcc_path()?; + let mut build_arg = Self { + gcc_path, + ..Default::default() + }; + // We skip binary name and the `build` command. + let mut args = std::env::args().skip(2); + + while let Some(arg) = args.next() { + match arg.as_str() { + "--release" => build_arg.codegen_release_channel = true, + "--release-sysroot" => build_arg.sysroot_release_channel = true, + "--no-default-features" => { + build_arg.features.push("--no-default-features".to_string()); + } + "--features" => { + if let Some(arg) = args.next() { + build_arg.features.push("--features".to_string()); + build_arg.features.push(arg.as_str().into()); + } else { + return Err( + "Expected a value after `--features`, found nothing".to_string() + ); + } + } + "--help" => { + Self::usage(); + return Ok(None); + } + arg => return Err(format!("Unknown argument `{}`", arg)), + } + } + Ok(Some(build_arg)) + } + + fn usage() { + println!( + r#" +`build` command help: + + --release : Build codegen in release mode + --release-sysroot : Build sysroot in release mode + --no-default-features : Add `--no-default-features` flag + --features [arg] : Add a new feature [arg] + --help : Show this help +"# + ) + } +} + +fn build_sysroot( + env: &mut HashMap<String, String>, + release_mode: bool, + target_triple: &str, +) -> Result<(), String> { + std::env::set_current_dir("build_sysroot") + .map_err(|error| format!("Failed to go to `build_sysroot` directory: {:?}", error))?; + // Cleanup for previous run + // Clean target dir except for build scripts and incremental cache + let _ = walk_dir( + "target", + |dir: &Path| { + for top in &["debug", "release"] { + let _ = fs::remove_dir_all(dir.join(top).join("build")); + let _ = fs::remove_dir_all(dir.join(top).join("deps")); + let _ = fs::remove_dir_all(dir.join(top).join("examples")); + let _ = fs::remove_dir_all(dir.join(top).join("native")); + + let _ = walk_dir( + dir.join(top), + |sub_dir: &Path| { + if sub_dir + .file_name() + .map(|filename| filename.to_str().unwrap().starts_with("libsysroot")) + .unwrap_or(false) + { + let _ = fs::remove_dir_all(sub_dir); + } + Ok(()) + }, + |file: &Path| { + if file + .file_name() + .map(|filename| filename.to_str().unwrap().starts_with("libsysroot")) + .unwrap_or(false) + { + let _ = fs::remove_file(file); + } + Ok(()) + }, + ); + } + Ok(()) + }, + |_| Ok(()), + ); + + let _ = fs::remove_file("Cargo.lock"); + let _ = fs::remove_file("test_target/Cargo.lock"); + let _ = fs::remove_dir_all("sysroot"); + + // Builds libs + let channel = if release_mode { + let rustflags = env + .get("RUSTFLAGS") + .cloned() + .unwrap_or_default(); + env.insert( + "RUSTFLAGS".to_string(), + format!("{} -Zmir-opt-level=3", rustflags), + ); + run_command_with_output_and_env( + &[ + &"cargo", + &"build", + &"--target", + &target_triple, + &"--release", + ], + None, + Some(&env), + )?; + "release" + } else { + run_command_with_output_and_env( + &[ + &"cargo", + &"build", + &"--target", + &target_triple, + &"--features", + &"compiler_builtins/c", + ], + None, + Some(env), + )?; + "debug" + }; + + // Copy files to sysroot + let sysroot_path = format!("sysroot/lib/rustlib/{}/lib/", target_triple); + fs::create_dir_all(&sysroot_path) + .map_err(|error| format!("Failed to create directory `{}`: {:?}", sysroot_path, error))?; + let copier = |dir_to_copy: &Path| { + run_command(&[&"cp", &"-r", &dir_to_copy, &sysroot_path], None).map(|_| ()) + }; + walk_dir( + &format!("target/{}/{}/deps", target_triple, channel), + copier, + copier, + )?; + + Ok(()) +} + +fn build_codegen(args: &BuildArg) -> Result<(), String> { + let mut env = HashMap::new(); + + let current_dir = + std::env::current_dir().map_err(|error| format!("`current_dir` failed: {:?}", error))?; + if let Ok(rt_root) = std::env::var("RUST_COMPILER_RT_ROOT") { + env.insert("RUST_COMPILER_RT_ROOT".to_string(), rt_root); + } else { + env.insert( + "RUST_COMPILER_RT_ROOT".to_string(), + format!("{}", current_dir.join("llvm/compiler-rt").display()), + ); + } + env.insert("LD_LIBRARY_PATH".to_string(), args.gcc_path.clone()); + env.insert("LIBRARY_PATH".to_string(), args.gcc_path.clone()); + + let mut command: Vec<&dyn AsRef<OsStr>> = vec![&"cargo", &"rustc"]; + if args.codegen_release_channel { + command.push(&"--release"); + env.insert("CHANNEL".to_string(), "release".to_string()); + env.insert("CARGO_INCREMENTAL".to_string(), "1".to_string()); + } else { + env.insert("CHANNEL".to_string(), "debug".to_string()); + } + let ref_features = args.features.iter().map(|s| s.as_str()).collect::<Vec<_>>(); + for feature in &ref_features { + command.push(feature); + } + run_command_with_env(&command, None, Some(&env))?; + + let config = set_config(&mut env, &[], Some(&args.gcc_path))?; + + // We voluntarily ignore the error. + let _ = fs::remove_dir_all("target/out"); + let gccjit_target = "target/out/gccjit"; + fs::create_dir_all(gccjit_target).map_err(|error| { + format!( + "Failed to create directory `{}`: {:?}", + gccjit_target, error + ) + })?; + + println!("[BUILD] sysroot"); + build_sysroot( + &mut env, + args.sysroot_release_channel, + &config.target_triple, + )?; + Ok(()) +} + +pub fn run() -> Result<(), String> { + let args = match BuildArg::new()? { + Some(args) => args, + None => return Ok(()), + }; + build_codegen(&args)?; + Ok(()) +} diff --git a/compiler/rustc_codegen_gcc/build_system/src/config.rs b/compiler/rustc_codegen_gcc/build_system/src/config.rs new file mode 100644 index 00000000000..4f2e33f0f99 --- /dev/null +++ b/compiler/rustc_codegen_gcc/build_system/src/config.rs @@ -0,0 +1,125 @@ +use crate::utils::{get_gcc_path, get_os_name, get_rustc_host_triple}; +use std::collections::HashMap; +use std::env as std_env; + +pub struct ConfigInfo { + pub target_triple: String, + pub rustc_command: Vec<String>, + pub run_wrapper: Option<&'static str>, +} + +// Returns the beginning for the command line of rustc. +pub fn set_config( + env: &mut HashMap<String, String>, + test_flags: &[String], + gcc_path: Option<&str>, +) -> Result<ConfigInfo, String> { + env.insert("CARGO_INCREMENTAL".to_string(), "0".to_string()); + + let gcc_path = match gcc_path { + Some(path) => path.to_string(), + None => get_gcc_path()?, + }; + env.insert("GCC_PATH".to_string(), gcc_path.clone()); + + let os_name = get_os_name()?; + let dylib_ext = match os_name.as_str() { + "Linux" => "so", + "Darwin" => "dylib", + os => return Err(format!("unsupported OS `{}`", os)), + }; + let host_triple = get_rustc_host_triple()?; + let mut linker = None; + let mut target_triple = host_triple.as_str(); + let mut run_wrapper = None; + // FIXME: handle this with a command line flag? + // let mut target_triple = "m68k-unknown-linux-gnu"; + + if host_triple != target_triple { + if target_triple == "m68k-unknown-linux-gnu" { + target_triple = "mips-unknown-linux-gnu"; + linker = Some("-Clinker=m68k-linux-gcc"); + } else if target_triple == "aarch64-unknown-linux-gnu" { + // We are cross-compiling for aarch64. Use the correct linker and run tests in qemu. + linker = Some("-Clinker=aarch64-linux-gnu-gcc"); + run_wrapper = Some("qemu-aarch64 -L /usr/aarch64-linux-gnu"); + } else { + return Err(format!("unknown non-native platform `{}`", target_triple)); + } + } + let current_dir = + std_env::current_dir().map_err(|error| format!("`current_dir` failed: {:?}", error))?; + let channel = if let Some(channel) = env.get("CHANNEL") { + channel.as_str() + } else { + "debug" + }; + let cg_backend_path = current_dir + .join("target") + .join(channel) + .join(&format!("librustc_codegen_gcc.{}", dylib_ext)); + let sysroot_path = current_dir.join("build_sysroot/sysroot"); + let mut rustflags = Vec::new(); + if let Some(cg_rustflags) = env.get("CG_RUSTFLAGS") { + rustflags.push(cg_rustflags.clone()); + } + if let Some(linker) = linker { + rustflags.push(linker.to_string()); + } + rustflags.extend_from_slice(&[ + "-Csymbol-mangling-version=v0".to_string(), + "-Cdebuginfo=2".to_string(), + format!("-Zcodegen-backend={}", cg_backend_path.display()), + "--sysroot".to_string(), + sysroot_path.display().to_string(), + ]); + + // Since we don't support ThinLTO, disable LTO completely when not trying to do LTO. + // TODO(antoyo): remove when we can handle ThinLTO. + if !env.contains_key(&"FAT_LTO".to_string()) { + rustflags.push("-Clto=off".to_string()); + } + rustflags.extend_from_slice(test_flags); + // FIXME(antoyo): remove once the atomic shim is gone + if os_name == "Darwin" { + rustflags.extend_from_slice(&[ + "-Clink-arg=-undefined".to_string(), + "-Clink-arg=dynamic_lookup".to_string(), + ]); + } + env.insert("RUSTFLAGS".to_string(), rustflags.join(" ")); + // display metadata load errors + env.insert("RUSTC_LOG".to_string(), "warn".to_string()); + + let sysroot = current_dir.join(&format!( + "build_sysroot/sysroot/lib/rustlib/{}/lib", + target_triple + )); + let ld_library_path = format!( + "{target}:{sysroot}:{gcc_path}", + target = current_dir.join("target/out").display(), + sysroot = sysroot.display(), + ); + env.insert("LD_LIBRARY_PATH".to_string(), ld_library_path.clone()); + env.insert("DYLD_LIBRARY_PATH".to_string(), ld_library_path); + + // NOTE: To avoid the -fno-inline errors, use /opt/gcc/bin/gcc instead of cc. + // To do so, add a symlink for cc to /opt/gcc/bin/gcc in our PATH. + // Another option would be to add the following Rust flag: -Clinker=/opt/gcc/bin/gcc + let path = std::env::var("PATH").unwrap_or_default(); + env.insert("PATH".to_string(), format!("/opt/gcc/bin:{}", path)); + + let mut rustc_command = vec!["rustc".to_string()]; + rustc_command.extend_from_slice(&rustflags); + rustc_command.extend_from_slice(&[ + "-L".to_string(), + "crate=target/out".to_string(), + "--out-dir".to_string(), + "target/out".to_string(), + ]); + Ok(ConfigInfo { + target_triple: target_triple.to_string(), + rustc_command, + run_wrapper, + }) +} diff --git a/compiler/rustc_codegen_gcc/build_system/src/main.rs b/compiler/rustc_codegen_gcc/build_system/src/main.rs new file mode 100644 index 00000000000..332a14ff0a2 --- /dev/null +++ b/compiler/rustc_codegen_gcc/build_system/src/main.rs @@ -0,0 +1,62 @@ +use std::env; +use std::process; + +mod build; +mod config; +mod prepare; +mod rustc_info; +mod utils; + +macro_rules! arg_error { + ($($err:tt)*) => {{ + eprintln!($($err)*); + eprintln!(); + usage(); + std::process::exit(1); + }}; +} + +fn usage() { + println!( + "\ +Available commands for build_system: + + prepare : Run prepare command + build : Run build command + --help : Show this message" + ); +} + +pub enum Command { + Prepare, + Build, +} + +fn main() { + if env::var("RUST_BACKTRACE").is_err() { + env::set_var("RUST_BACKTRACE", "1"); + } + + let command = match env::args().nth(1).as_deref() { + Some("prepare") => Command::Prepare, + Some("build") => Command::Build, + Some("--help") => { + usage(); + process::exit(0); + } + Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag), + Some(command) => arg_error!("Unknown command {}", command), + None => { + usage(); + process::exit(0); + } + }; + + if let Err(e) = match command { + Command::Prepare => prepare::run(), + Command::Build => build::run(), + } { + eprintln!("Command failed to run: {e:?}"); + process::exit(1); + } +} diff --git a/compiler/rustc_codegen_gcc/build_system/src/prepare.rs b/compiler/rustc_codegen_gcc/build_system/src/prepare.rs new file mode 100644 index 00000000000..b258ddf3664 --- /dev/null +++ b/compiler/rustc_codegen_gcc/build_system/src/prepare.rs @@ -0,0 +1,227 @@ +use crate::rustc_info::get_rustc_path; +use crate::utils::{cargo_install, git_clone, run_command, run_command_with_output, walk_dir}; + +use std::fs; +use std::path::Path; + +fn prepare_libcore(sysroot_path: &Path) -> Result<(), String> { + let rustc_path = match get_rustc_path() { + Some(path) => path, + None => return Err("`rustc` path not found".to_string()), + }; + + let parent = match rustc_path.parent() { + Some(path) => path, + None => return Err(format!("No parent for `{}`", rustc_path.display())), + }; + + let rustlib_dir = parent + .join("../lib/rustlib/src/rust") + .canonicalize() + .map_err(|error| format!("Failed to canonicalize path: {:?}", error))?; + if !rustlib_dir.is_dir() { + return Err("Please install `rust-src` component".to_string()); + } + + let sysroot_dir = sysroot_path.join("sysroot_src"); + if sysroot_dir.is_dir() { + if let Err(error) = fs::remove_dir_all(&sysroot_dir) { + return Err(format!( + "Failed to remove `{}`: {:?}", + sysroot_dir.display(), + error, + )); + } + } + + let sysroot_library_dir = sysroot_dir.join("library"); + fs::create_dir_all(&sysroot_library_dir).map_err(|error| { + format!( + "Failed to create folder `{}`: {:?}", + sysroot_library_dir.display(), + error, + ) + })?; + + run_command( + &[&"cp", &"-r", &rustlib_dir.join("library"), &sysroot_dir], + None, + )?; + + println!("[GIT] init (cwd): `{}`", sysroot_dir.display()); + run_command(&[&"git", &"init"], Some(&sysroot_dir))?; + println!("[GIT] add (cwd): `{}`", sysroot_dir.display()); + run_command(&[&"git", &"add", &"."], Some(&sysroot_dir))?; + println!("[GIT] commit (cwd): `{}`", sysroot_dir.display()); + + // This is needed on systems where nothing is configured. + // git really needs something here, or it will fail. + // Even using --author is not enough. + run_command( + &[&"git", &"config", &"user.email", &"none@example.com"], + Some(&sysroot_dir), + )?; + run_command( + &[&"git", &"config", &"user.name", &"None"], + Some(&sysroot_dir), + )?; + run_command( + &[&"git", &"config", &"core.autocrlf", &"false"], + Some(&sysroot_dir), + )?; + run_command( + &[&"git", &"config", &"commit.gpgSign", &"false"], + Some(&sysroot_dir), + )?; + run_command( + &[&"git", &"commit", &"-m", &"Initial commit", &"-q"], + Some(&sysroot_dir), + )?; + + let mut patches = Vec::new(); + walk_dir( + "patches", + |_| Ok(()), + |file_path: &Path| { + patches.push(file_path.to_path_buf()); + Ok(()) + }, + )?; + patches.sort(); + for file_path in patches { + println!("[GIT] apply `{}`", file_path.display()); + let path = Path::new("../..").join(file_path); + run_command_with_output(&[&"git", &"apply", &path], Some(&sysroot_dir))?; + run_command_with_output(&[&"git", &"add", &"-A"], Some(&sysroot_dir))?; + run_command_with_output( + &[ + &"git", + &"commit", + &"--no-gpg-sign", + &"-m", + &format!("Patch {}", path.display()), + ], + Some(&sysroot_dir), + )?; + } + println!("Successfully prepared libcore for building"); + Ok(()) +} + +// build with cg_llvm for perf comparison +fn build_raytracer(repo_dir: &Path) -> Result<(), String> { + run_command(&[&"cargo", &"build"], Some(repo_dir))?; + let mv_target = repo_dir.join("raytracer_cg_llvm"); + if mv_target.is_file() { + std::fs::remove_file(&mv_target) + .map_err(|e| format!("Failed to remove file `{}`: {e:?}", mv_target.display()))?; + } + run_command( + &[&"mv", &"target/debug/main", &"raytracer_cg_llvm"], + Some(repo_dir), + )?; + Ok(()) +} + +fn clone_and_setup<F>(repo_url: &str, checkout_commit: &str, extra: Option<F>) -> Result<(), String> +where + F: Fn(&Path) -> Result<(), String>, +{ + let clone_result = git_clone(repo_url, None)?; + if !clone_result.ran_clone { + println!("`{}` has already been cloned", clone_result.repo_name); + } + let repo_path = Path::new(&clone_result.repo_name); + run_command(&[&"git", &"checkout", &"--", &"."], Some(&repo_path))?; + run_command(&[&"git", &"checkout", &checkout_commit], Some(&repo_path))?; + let filter = format!("-{}-", clone_result.repo_name); + walk_dir( + "crate_patches", + |_| Ok(()), + |file_path| { + let patch = file_path.as_os_str().to_str().unwrap(); + if patch.contains(&filter) && patch.ends_with(".patch") { + run_command_with_output( + &[&"git", &"am", &file_path.canonicalize().unwrap()], + Some(&repo_path), + )?; + } + Ok(()) + }, + )?; + if let Some(extra) = extra { + extra(&repo_path)?; + } + Ok(()) +} + +struct PrepareArg { + only_libcore: bool, +} + +impl PrepareArg { + fn new() -> Result<Option<Self>, String> { + let mut only_libcore = false; + + for arg in std::env::args().skip(2) { + match arg.as_str() { + "--only-libcore" => only_libcore = true, + "--help" => { + Self::usage(); + return Ok(None); + } + a => return Err(format!("Unknown argument `{a}`")), + } + } + Ok(Some(Self { only_libcore })) + } + + fn usage() { + println!( + r#" +`prepare` command help: + + --only-libcore : Only setup libcore and don't clone other repositories + --help : Show this help +"# + ) + } +} + +pub fn run() -> Result<(), String> { + let args = match PrepareArg::new()? { + Some(a) => a, + None => return Ok(()), + }; + let sysroot_path = Path::new("build_sysroot"); + prepare_libcore(sysroot_path)?; + + if !args.only_libcore { + cargo_install("hyperfine")?; + + let to_clone = &[ + ( + "https://github.com/rust-random/rand.git", + "0f933f9c7176e53b2a3c7952ded484e1783f0bf1", + None, + ), + ( + "https://github.com/rust-lang/regex.git", + "341f207c1071f7290e3f228c710817c280c8dca1", + None, + ), + ( + "https://github.com/ebobby/simple-raytracer", + "804a7a21b9e673a482797aa289a18ed480e4d813", + Some(build_raytracer), + ), + ]; + + for (repo_url, checkout_commit, cb) in to_clone { + clone_and_setup(repo_url, checkout_commit, *cb)?; + } + } + + println!("Successfully ran `prepare`"); + Ok(()) +} diff --git a/compiler/rustc_codegen_gcc/build_system/src/rustc_info.rs b/compiler/rustc_codegen_gcc/build_system/src/rustc_info.rs new file mode 100644 index 00000000000..0988b56d81e --- /dev/null +++ b/compiler/rustc_codegen_gcc/build_system/src/rustc_info.rs @@ -0,0 +1,12 @@ +use std::path::{Path, PathBuf}; + +use crate::utils::run_command; + +pub fn get_rustc_path() -> Option<PathBuf> { + if let Ok(rustc) = std::env::var("RUSTC") { + return Some(PathBuf::from(rustc)); + } + run_command(&[&"rustup", &"which", &"rustc"], None) + .ok() + .map(|out| Path::new(String::from_utf8(out.stdout).unwrap().trim()).to_path_buf()) +} diff --git a/compiler/rustc_codegen_gcc/build_system/src/utils.rs b/compiler/rustc_codegen_gcc/build_system/src/utils.rs new file mode 100644 index 00000000000..536f33a8029 --- /dev/null +++ b/compiler/rustc_codegen_gcc/build_system/src/utils.rs @@ -0,0 +1,240 @@ +use std::collections::HashMap; +use std::ffi::OsStr; +use std::fmt::Debug; +use std::fs; +use std::path::Path; +use std::process::{Command, ExitStatus, Output}; + +fn get_command_inner( + input: &[&dyn AsRef<OsStr>], + cwd: Option<&Path>, + env: Option<&HashMap<String, String>>, +) -> Command { + let (cmd, args) = match input { + [] => panic!("empty command"), + [cmd, args @ ..] => (cmd, args), + }; + let mut command = Command::new(cmd); + command.args(args); + if let Some(cwd) = cwd { + command.current_dir(cwd); + } + if let Some(env) = env { + command.envs(env.iter().map(|(k, v)| (k.as_str(), v.as_str()))); + } + command +} + +fn check_exit_status( + input: &[&dyn AsRef<OsStr>], + cwd: Option<&Path>, + exit_status: ExitStatus, +) -> Result<(), String> { + if exit_status.success() { + Ok(()) + } else { + Err(format!( + "Command `{}`{} exited with status {:?}", + input + .iter() + .map(|s| s.as_ref().to_str().unwrap()) + .collect::<Vec<_>>() + .join(" "), + cwd.map(|cwd| format!(" (running in folder `{}`)", cwd.display())) + .unwrap_or_default(), + exit_status.code(), + )) + } +} + +fn command_error<D: Debug>(input: &[&dyn AsRef<OsStr>], cwd: &Option<&Path>, error: D) -> String { + format!( + "Command `{}`{} failed to run: {error:?}", + input + .iter() + .map(|s| s.as_ref().to_str().unwrap()) + .collect::<Vec<_>>() + .join(" "), + cwd.as_ref() + .map(|cwd| format!(" (running in folder `{}`)", cwd.display(),)) + .unwrap_or_default(), + ) +} + +pub fn run_command(input: &[&dyn AsRef<OsStr>], cwd: Option<&Path>) -> Result<Output, String> { + run_command_with_env(input, cwd, None) +} + +pub fn run_command_with_env( + input: &[&dyn AsRef<OsStr>], + cwd: Option<&Path>, + env: Option<&HashMap<String, String>>, +) -> Result<Output, String> { + let output = get_command_inner(input, cwd, env) + .output() + .map_err(|e| command_error(input, &cwd, e))?; + check_exit_status(input, cwd, output.status)?; + Ok(output) +} + +pub fn run_command_with_output( + input: &[&dyn AsRef<OsStr>], + cwd: Option<&Path>, +) -> Result<(), String> { + let exit_status = get_command_inner(input, cwd, None) + .spawn() + .map_err(|e| command_error(input, &cwd, e))? + .wait() + .map_err(|e| command_error(input, &cwd, e))?; + check_exit_status(input, cwd, exit_status)?; + Ok(()) +} + +pub fn run_command_with_output_and_env( + input: &[&dyn AsRef<OsStr>], + cwd: Option<&Path>, + env: Option<&HashMap<String, String>>, +) -> Result<(), String> { + let exit_status = get_command_inner(input, cwd, env) + .spawn() + .map_err(|e| command_error(input, &cwd, e))? + .wait() + .map_err(|e| command_error(input, &cwd, e))?; + check_exit_status(input, cwd, exit_status)?; + Ok(()) +} + +pub fn cargo_install(to_install: &str) -> Result<(), String> { + let output = run_command(&[&"cargo", &"install", &"--list"], None)?; + + let to_install_needle = format!("{to_install} "); + // cargo install --list returns something like this: + // + // mdbook-toc v0.8.0: + // mdbook-toc + // rust-reduce v0.1.0: + // rust-reduce + // + // We are only interested into the command name so we only look for lines ending with `:`. + if String::from_utf8(output.stdout) + .unwrap() + .lines() + .any(|line| line.ends_with(':') && line.starts_with(&to_install_needle)) + { + return Ok(()); + } + // We voluntarily ignore this error. + if run_command_with_output(&[&"cargo", &"install", &to_install], None).is_err() { + println!("Skipping installation of `{to_install}`"); + } + Ok(()) +} + +pub fn get_os_name() -> Result<String, String> { + let output = run_command(&[&"uname"], None)?; + let name = std::str::from_utf8(&output.stdout) + .unwrap_or("") + .trim() + .to_string(); + if !name.is_empty() { + Ok(name) + } else { + Err("Failed to retrieve the OS name".to_string()) + } +} + +pub fn get_rustc_host_triple() -> Result<String, String> { + let output = run_command(&[&"rustc", &"-vV"], None)?; + let content = std::str::from_utf8(&output.stdout).unwrap_or(""); + + for line in content.split('\n').map(|line| line.trim()) { + if !line.starts_with("host:") { + continue; + } + return Ok(line.split(':').nth(1).unwrap().trim().to_string()); + } + Err("Cannot find host triple".to_string()) +} + +pub fn get_gcc_path() -> Result<String, String> { + let content = match fs::read_to_string("gcc_path") { + Ok(content) => content, + Err(_) => { + return Err( + "Please put the path to your custom build of libgccjit in the file \ + `gcc_path`, see Readme.md for details" + .into(), + ) + } + }; + match content + .split('\n') + .map(|line| line.trim()) + .filter(|line| !line.is_empty()) + .next() + { + Some(gcc_path) => { + let path = Path::new(gcc_path); + if !path.exists() { + Err(format!( + "Path `{}` contained in the `gcc_path` file doesn't exist", + gcc_path, + )) + } else { + Ok(gcc_path.into()) + } + } + None => Err("No path found in `gcc_path` file".into()), + } +} + +pub struct CloneResult { + pub ran_clone: bool, + pub repo_name: String, +} + +pub fn git_clone(to_clone: &str, dest: Option<&Path>) -> Result<CloneResult, String> { + let repo_name = to_clone.split('/').last().unwrap(); + let repo_name = match repo_name.strip_suffix(".git") { + Some(n) => n.to_string(), + None => repo_name.to_string(), + }; + + let dest = dest + .map(|dest| dest.join(&repo_name)) + .unwrap_or_else(|| Path::new(&repo_name).into()); + if dest.is_dir() { + return Ok(CloneResult { + ran_clone: false, + repo_name, + }); + } + + run_command_with_output(&[&"git", &"clone", &to_clone, &dest], None)?; + Ok(CloneResult { + ran_clone: true, + repo_name, + }) +} + +pub fn walk_dir<P, D, F>(dir: P, mut dir_cb: D, mut file_cb: F) -> Result<(), String> +where + P: AsRef<Path>, + D: FnMut(&Path) -> Result<(), String>, + F: FnMut(&Path) -> Result<(), String>, +{ + let dir = dir.as_ref(); + for entry in fs::read_dir(dir) + .map_err(|error| format!("Failed to read dir `{}`: {:?}", dir.display(), error))? + { + let entry = entry + .map_err(|error| format!("Failed to read entry in `{}`: {:?}", dir.display(), error))?; + let entry_path = entry.path(); + if entry_path.is_dir() { + dir_cb(&entry_path)?; + } else { + file_cb(&entry_path)?; + } + } + Ok(()) +} diff --git a/compiler/rustc_codegen_gcc/config.sh b/compiler/rustc_codegen_gcc/config.sh index 166e83901c4..c686df0c72a 100644 --- a/compiler/rustc_codegen_gcc/config.sh +++ b/compiler/rustc_codegen_gcc/config.sh @@ -38,10 +38,17 @@ if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then fi fi -export RUSTFLAGS="$CG_RUSTFLAGS $linker -Csymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot $TEST_FLAGS" +# Since we don't support ThinLTO, disable LTO completely when not trying to do LTO. +# TODO(antoyo): remove when we can handle ThinLTO. +disable_lto_flags='' +if [[ ! -v FAT_LTO ]]; then + disable_lto_flags='-Clto=off' +fi + +export RUSTFLAGS="$CG_RUSTFLAGS $linker -Csymbol-mangling-version=v0 -Cdebuginfo=2 $disable_lto_flags -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot $TEST_FLAGS" # FIXME(antoyo): remove once the atomic shim is gone -if [[ `uname` == 'Darwin' ]]; then +if [[ unamestr == 'Darwin' ]]; then export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup" fi @@ -50,3 +57,7 @@ export RUSTC_LOG=warn # display metadata load errors export LD_LIBRARY_PATH="$(pwd)/target/out:$(pwd)/build_sysroot/sysroot/lib/rustlib/$TARGET_TRIPLE/lib:$GCC_PATH" export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH +# NOTE: To avoid the -fno-inline errors, use /opt/gcc/bin/gcc instead of cc. +# To do so, add a symlink for cc to /opt/gcc/bin/gcc in our PATH. +# Another option would be to add the following Rust flag: -Clinker=/opt/gcc/bin/gcc +export PATH="/opt/gcc/bin:$PATH" diff --git a/compiler/rustc_codegen_gcc/doc/add-attribute.md b/compiler/rustc_codegen_gcc/doc/add-attribute.md new file mode 100644 index 00000000000..ae3bcc5e2eb --- /dev/null +++ b/compiler/rustc_codegen_gcc/doc/add-attribute.md @@ -0,0 +1,17 @@ +# Add support for a new function attribute + +To add support for a new function attribute in libgccjit, you need to do the following steps: + + 1. Copy the corresponding function from `c-family/c-attribs.cc` into `jit/dummy-frontend.cc`. For example if you add the `target` attribute, the function name will be `handle_target_attribute`. + 2. Copy the corresponding entry from the `c_common_attribute_table` variable in the `c-family/c-attribs.cc` file into the `jit_attribute_table` variable in `jit/dummy-frontend.cc`. + 3. Add a new variant in the `gcc_jit_fn_attribute` enum in the `jit/libgccjit.h` file. + 4. Add a test to ensure the attribute is correctly applied in `gcc/testsuite/jit.dg/`. Take a look at `gcc/testsuite/jit.dg/test-nonnull.c` if you want an example. + 5. Run the example like this (in your `gcc-build` folder): `make check-jit RUNTESTFLAGS="-v -v -v jit.exp=jit.dg/test-nonnull.c"` + +Once done, you need to update the [gccjit.rs] crate to add the new enum variant in the corresponding enum (`FnAttribute`). + +Finally, you need to update this repository by calling the relevant API you added in [gccjit.rs]. + +To test it, build `gcc`, run `cargo update -p gccjit` and then you can test the generated output for a given Rust crate. + +[gccjit.rs]: https://github.com/antoyo/gccjit.rs diff --git a/compiler/rustc_codegen_gcc/doc/gimple.md b/compiler/rustc_codegen_gcc/doc/gimple.md new file mode 100644 index 00000000000..145c4eda3c1 --- /dev/null +++ b/compiler/rustc_codegen_gcc/doc/gimple.md @@ -0,0 +1,111 @@ +# GIMPLE + +You can see the full documentation about what GIMPLE is [here](https://gcc.gnu.org/onlinedocs/gccint/GIMPLE.html). In this document we will explain how to generate it. + +First, we'll copy the content from `gcc/gcc/testsuite/jit.dg/test-const-attribute.c` into a +file named `local.c` and remove the content we're not interested into: + +```diff +- /* { dg-do compile { target x86_64-*-* } } */ +... +- /* We don't want set_options() in harness.h to set -O3 to see that the const +- attribute affects the optimizations. */ +- #define TEST_ESCHEWS_SET_OPTIONS +- static void set_options (gcc_jit_context *ctxt, const char *argv0) +- { +- // Set "-O3". +- gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3); +- } +- +- #define TEST_COMPILING_TO_FILE +- #define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER +- #define OUTPUT_FILENAME "output-of-test-const-attribute.c.s" +- #include "harness.h" +... +- /* { dg-final { jit-verify-output-file-was-created "" } } */ +- /* Check that the loop was optimized away */ +- /* { dg-final { jit-verify-assembler-output-not "jne" } } */ +``` + +Then we'll add a `main` function which will call the `create_code` function but +also add the calls we need to generate the GIMPLE: + +```C +int main() { + gcc_jit_context *ctxt = gcc_jit_context_acquire(); + // To set `-O3`, update it depending on your needs. + gcc_jit_context_set_int_option(ctxt, GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 3); + // Very important option to generate the gimple format. + gcc_jit_context_set_bool_option(ctxt, GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, 1); + create_code(ctxt, NULL); + + gcc_jit_context_compile(ctxt); + // If you want to compile to assembly (or any other format) directly, you can + // use the following call instead: + // gcc_jit_context_compile_to_file(ctxt, GCC_JIT_OUTPUT_KIND_ASSEMBLER, "out.s"); + + return 0; +} +``` + +Then we can compile it by using: + +```console +gcc local.c -I `pwd`/gcc/gcc/jit/ -L `pwd`/gcc-build/gcc -lgccjit -o out +``` + +And finally when you run it: + +```console +LD_LIBRARY_PATH=`pwd`/gcc-build/gcc LIBRARY_PATH=`pwd`/gcc-build/gcc ./out +``` + +It should display: + +```c +__attribute__((const)) +int xxx () +{ + int D.3394; + int sum; + int x; + + <D.3377>: + x = 45; + sum = 0; + goto loop_cond; + loop_cond: + x = x >> 1; + if (x != 0) goto after_loop; else goto loop_body; + loop_body: + _1 = foo (x); + _2 = _1 * 2; + x = x + _2; + goto loop_cond; + after_loop: + D.3394 = sum; + return D.3394; +} +``` + +An alternative way to generate the GIMPLE is to replace: + +```c + gcc_jit_context_set_bool_option(ctxt, GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, 1); +``` + +with: + +```c + gcc_jit_context_add_command_line_option(ctxt, "-fdump-tree-gimple"); +``` + +(although you can have both at the same time too). Then you can compile it like previously. Only one difference: before executing it, I recommend to run: + +```console +rm -rf /tmp/libgccjit-* +``` + +to make it easier for you to know which folder to look into. + +Once the execution is done, you should now have a file with path looking like `/tmp/libgccjit-9OFqkD/fake.c.006t.gimple` which contains the GIMPLE format. diff --git a/compiler/rustc_codegen_gcc/doc/sending-gcc-patch.md b/compiler/rustc_codegen_gcc/doc/sending-gcc-patch.md new file mode 100644 index 00000000000..7a47ef29f3c --- /dev/null +++ b/compiler/rustc_codegen_gcc/doc/sending-gcc-patch.md @@ -0,0 +1,44 @@ +This guide explains what to do to send a GCC patch for review. + +All the commands are supposed to be run in the folder where you cloned GCC. + +```bash +./contrib/gcc-changelog/git_check_commit.py +``` + +You can provide a specific commit hash: + +```bash +./contrib/gcc-changelog/git_check_commit.py abdef78989 +``` + +a range: + +```bash +./contrib/gcc-changelog/git_check_commit.py HEAD~2 +``` + +or even a comparison with a remote branch: + +```bash +./contrib/gcc-changelog/git_check_commit.py upstream/master..HEAD +``` + +When there is no more errors, generate the git patch: + +```bash +git format-patch -1 `git rev-parse --short HEAD` +``` + +Then you can run the remaining checks using: + +```bash +contrib/check_GNU_style.sh 0001-your-patch.patch +``` + +When you have no more errors, you can send the `.patch` file to GCC by sending an +email to `gcc-patches@gcc.gnu.org` and to the relevant GCC mailing lists +depending on what your patch changes. You can find the list of the mailing lists +[here](https://gcc.gnu.org/lists.html). + +You can find more information about "contributing to GCC" [here](https://gcc.gnu.org/contribute.html). diff --git a/compiler/rustc_codegen_gcc/example/alloc_example.rs b/compiler/rustc_codegen_gcc/example/alloc_example.rs index 754e7931412..f1954a30cf8 100644 --- a/compiler/rustc_codegen_gcc/example/alloc_example.rs +++ b/compiler/rustc_codegen_gcc/example/alloc_example.rs @@ -1,5 +1,6 @@ #![feature(start, core_intrinsics, alloc_error_handler, lang_items)] #![no_std] +#![allow(internal_features)] extern crate alloc; extern crate alloc_system; diff --git a/compiler/rustc_codegen_gcc/example/alloc_system.rs b/compiler/rustc_codegen_gcc/example/alloc_system.rs index 3deef419f42..56ff84e4bdf 100644 --- a/compiler/rustc_codegen_gcc/example/alloc_system.rs +++ b/compiler/rustc_codegen_gcc/example/alloc_system.rs @@ -12,7 +12,7 @@ target_arch = "mips", target_arch = "mips32r6", target_arch = "powerpc", - target_arch = "csky" + target_arch = "csky", target_arch = "powerpc64"))] const MIN_ALIGN: usize = 8; #[cfg(any(target_arch = "x86_64", diff --git a/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs b/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs index 3af0ba09e0b..b299aa87974 100644 --- a/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs +++ b/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs @@ -2,6 +2,7 @@ #![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)] #![feature(rustc_attrs)] +#![allow(internal_features)] use std::{ ops::{Deref, CoerceUnsized, DispatchFromDyn}, diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index 0cd7e6047c2..34328520343 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -4,7 +4,7 @@ thread_local )] #![no_core] -#![allow(dead_code)] +#![allow(dead_code, internal_features)] #[no_mangle] unsafe extern "C" fn _Unwind_Resume() { @@ -429,6 +429,15 @@ fn panic_cannot_unwind() -> ! { } } +#[lang = "panic_in_cleanup"] +#[rustc_nounwind] +fn panic_in_cleanup() -> ! { + unsafe { + libc::printf("panic in a destructor during cleanup\n\0" as *const str as *const i8); + intrinsics::abort(); + } +} + #[lang = "panic_bounds_check"] #[track_caller] fn panic_bounds_check(index: usize, len: usize) -> ! { diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs index b93d6859706..c3aea571815 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs @@ -5,7 +5,7 @@ extern_types, thread_local )] #![no_core] -#![allow(dead_code, non_camel_case_types)] +#![allow(dead_code, internal_features, non_camel_case_types)] extern crate mini_core; diff --git a/compiler/rustc_codegen_gcc/example/mod_bench.rs b/compiler/rustc_codegen_gcc/example/mod_bench.rs index 5e2e7f25a2c..c60bc7fb724 100644 --- a/compiler/rustc_codegen_gcc/example/mod_bench.rs +++ b/compiler/rustc_codegen_gcc/example/mod_bench.rs @@ -1,5 +1,6 @@ #![feature(start, core_intrinsics, lang_items)] #![no_std] +#![allow(internal_features)] #[link(name = "c")] extern {} diff --git a/compiler/rustc_codegen_gcc/failing-lto-tests.txt b/compiler/rustc_codegen_gcc/failing-lto-tests.txt new file mode 100644 index 00000000000..2e0b6134070 --- /dev/null +++ b/compiler/rustc_codegen_gcc/failing-lto-tests.txt @@ -0,0 +1,23 @@ +tests/ui/lint/unsafe_code/forge_unsafe_block.rs +tests/ui/lint/unused-qualification-in-derive-expansion.rs +tests/ui/macro-quote-test.rs +tests/ui/macros/proc_macro.rs +tests/ui/panic-runtime/lto-unwind.rs +tests/ui/resolve/derive-macro-1.rs +tests/ui/resolve/derive-macro-2.rs +tests/ui/rfcs/rfc-2565-param-attrs/param-attrs-pretty.rs +tests/ui/rfcs/rfc-2565-param-attrs/issue-64682-dropping-first-attrs-in-impl-fns.rs +tests/ui/rfcs/rfc-3348-c-string-literals/edition-spans.rs +tests/ui/rust-2018/suggestions-not-always-applicable.rs +tests/ui/rust-2021/reserved-prefixes-via-macro.rs +tests/ui/underscore-imports/duplicate.rs +tests/ui/async-await/issues/issue-60674.rs +tests/ui/attributes/main-removed-2/main.rs +tests/ui/cfg/assume-incomplete-release/assume-incomplete.rs +tests/ui/crate-loading/cross-compiled-proc-macro.rs +tests/ui/derives/derive-marker-tricky.rs +tests/ui/diagnostic_namespace/existing_proc_macros.rs +tests/ui/fmt/format-args-capture-issue-106408.rs +tests/ui/fmt/indoc-issue-106408.rs +tests/ui/hygiene/issue-77523-def-site-async-await.rs +tests/ui/inherent-impls-overlap-check/no-overlap.rs diff --git a/compiler/rustc_codegen_gcc/failing-non-lto-tests.txt b/compiler/rustc_codegen_gcc/failing-non-lto-tests.txt new file mode 100644 index 00000000000..2f338f7d3c8 --- /dev/null +++ b/compiler/rustc_codegen_gcc/failing-non-lto-tests.txt @@ -0,0 +1,11 @@ +tests/ui/issues/issue-44056.rs +tests/ui/lto/fat-lto.rs +tests/ui/lto/debuginfo-lto.rs +tests/ui/lto/lto-many-codegen-units.rs +tests/ui/lto/issue-100772.rs +tests/ui/lto/lto-rustc-loads-linker-plugin.rs +tests/ui/panic-runtime/lto-unwind.rs +tests/ui/sanitize/issue-111184-generator-witness.rs +tests/ui/sepcomp/sepcomp-lib-lto.rs +tests/ui/lto/lto-opt-level-s.rs +tests/ui/lto/lto-opt-level-z.rs diff --git a/compiler/rustc_codegen_gcc/failing-ui-tests.txt b/compiler/rustc_codegen_gcc/failing-ui-tests.txt index 801464daae9..ed56a11a170 100644 --- a/compiler/rustc_codegen_gcc/failing-ui-tests.txt +++ b/compiler/rustc_codegen_gcc/failing-ui-tests.txt @@ -1,11 +1,5 @@ -tests/ui/allocator/custom-in-block.rs -tests/ui/allocator/custom-in-submodule.rs -tests/ui/allocator/custom.rs -tests/ui/allocator/hygiene.rs tests/ui/allocator/no_std-alloc-error-handler-custom.rs tests/ui/allocator/no_std-alloc-error-handler-default.rs -tests/ui/allocator/xcrate-use.rs -tests/ui/allocator/xcrate-use2.rs tests/ui/asm/may_unwind.rs tests/ui/asm/x86_64/multiple-clobber-abi.rs tests/ui/debuginfo/debuginfo-emit-llvm-ir-and-split-debuginfo.rs @@ -14,15 +8,12 @@ tests/ui/linkage-attr/linkage1.rs tests/ui/lto/dylib-works.rs tests/ui/numbers-arithmetic/saturating-float-casts.rs tests/ui/polymorphization/promoted-function.rs -tests/ui/process/nofile-limit.rs tests/ui/sepcomp/sepcomp-cci.rs tests/ui/sepcomp/sepcomp-extern.rs tests/ui/sepcomp/sepcomp-fns-backwards.rs tests/ui/sepcomp/sepcomp-fns.rs tests/ui/sepcomp/sepcomp-statics.rs tests/ui/simd/intrinsic/generic-arithmetic-pass.rs -tests/ui/sse2.rs -tests/ui/target-feature/missing-plusminus.rs tests/ui/asm/x86_64/may_unwind.rs tests/ui/backtrace.rs tests/ui/catch-unwind-bang.rs @@ -54,8 +45,8 @@ tests/ui/issues/issue-40883.rs tests/ui/issues/issue-43853.rs tests/ui/issues/issue-47364.rs tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs -tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs tests/ui/rfcs/rfc-1857-stabilize-drop-order/drop-order.rs +tests/ui/rfcs/rfc-2091-track-caller/std-panic-locations.rs tests/ui/simd/issue-17170.rs tests/ui/simd/issue-39720.rs tests/ui/simd/issue-89193.rs @@ -65,6 +56,18 @@ tests/ui/alloc-error/default-alloc-error-hook.rs tests/ui/generator/panic-safe.rs tests/ui/issues/issue-14875.rs tests/ui/issues/issue-29948.rs -tests/ui/panic-while-printing.rs -tests/ui/enum-discriminant/get_discr.rs tests/ui/panics/nested_panic_caught.rs +tests/ui/simd/intrinsic/generic-bswap-byte.rs +tests/ui/const_prop/ice-issue-111353.rs +tests/ui/process/println-with-broken-pipe.rs +tests/ui/panic-runtime/lto-abort.rs +tests/ui/lto/thin-lto-inlines2.rs +tests/ui/lto/weak-works.rs +tests/ui/lto/thin-lto-inlines.rs +tests/ui/lto/thin-lto-global-allocator.rs +tests/ui/lto/msvc-imp-present.rs +tests/ui/lto/lto-thin-rustc-loads-linker-plugin.rs +tests/ui/lto/all-crates.rs +tests/ui/async-await/deep-futures-are-freeze.rs +tests/ui/closures/capture-unsized-by-ref.rs +tests/ui/generator/resume-after-return.rs diff --git a/compiler/rustc_codegen_gcc/failing-ui-tests12.txt b/compiler/rustc_codegen_gcc/failing-ui-tests12.txt index 8c27bd8b8ca..0ac0a034af4 100644 --- a/compiler/rustc_codegen_gcc/failing-ui-tests12.txt +++ b/compiler/rustc_codegen_gcc/failing-ui-tests12.txt @@ -37,3 +37,4 @@ tests/ui/simd/intrinsic/generic-gather-pass.rs tests/ui/simd/issue-85915-simd-ptrs.rs tests/ui/issues/issue-68010-large-zst-consts.rs tests/ui/rust-2018/proc-macro-crate-in-paths.rs +tests/ui/target-feature/missing-plusminus.rs diff --git a/compiler/rustc_codegen_gcc/messages.ftl b/compiler/rustc_codegen_gcc/messages.ftl index 2fd0daee3e7..5ca0a2e1b6d 100644 --- a/compiler/rustc_codegen_gcc/messages.ftl +++ b/compiler/rustc_codegen_gcc/messages.ftl @@ -1,3 +1,7 @@ +codegen_gcc_unknown_ctarget_feature_prefix = + unknown feature specified for `-Ctarget-feature`: `{$feature}` + .note = features must begin with a `+` to enable or `-` to disable it + codegen_gcc_invalid_minimum_alignment = invalid minimum global alignment: {$err} @@ -9,3 +13,29 @@ codegen_gcc_tied_target_features = the target features {$features} must all be e codegen_gcc_unwinding_inline_asm = GCC backend does not support unwinding from inline asm + +codegen_gcc_copy_bitcode = failed to copy bitcode to object file: {$err} + +codegen_gcc_dynamic_linking_with_lto = + cannot prefer dynamic linking when performing LTO + .note = only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO + +codegen_gcc_load_bitcode = failed to load bitcode of module "{$name}" + +codegen_gcc_lto_disallowed = lto can only be run for executables, cdylibs and static library outputs + +codegen_gcc_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdylib-lto` + +codegen_gcc_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$gcc_err}) + +codegen_gcc_unknown_ctarget_feature = + unknown feature specified for `-Ctarget-feature`: `{$feature}` + .note = it is still passed through to the codegen backend + .possible_feature = you might have meant: `{$rust_feature}` + .consider_filing_feature_request = consider filing a feature request + +codegen_gcc_missing_features = + add the missing features in a `target_feature` attribute + +codegen_gcc_target_feature_disable_or_enable = + the target features {$features} must all be either enabled or disabled together diff --git a/compiler/rustc_codegen_gcc/patches/0001-Add-stdarch-Cargo.toml-for-testing.patch b/compiler/rustc_codegen_gcc/patches/0001-Add-stdarch-Cargo.toml-for-testing.patch index 93c63b5dcac..2a55f2cb796 100644 --- a/compiler/rustc_codegen_gcc/patches/0001-Add-stdarch-Cargo.toml-for-testing.patch +++ b/compiler/rustc_codegen_gcc/patches/0001-Add-stdarch-Cargo.toml-for-testing.patch @@ -1,25 +1,26 @@ -From c3821e02fbd6cb5ad6e06d759fccdc9073712375 Mon Sep 17 00:00:00 2001 +From b8f3eed3053c9333b5dfbeaeb2a6a65a4b3156df Mon Sep 17 00:00:00 2001 From: Antoni Boucher <bouanto@zoho.com> -Date: Tue, 7 Jun 2022 21:40:13 -0400 -Subject: [PATCH] Add stdarch Cargo.toml for testing +Date: Tue, 29 Aug 2023 13:06:34 -0400 +Subject: [PATCH] Patch 0001-Add-stdarch-Cargo.toml-for-testing.patch --- - library/stdarch/Cargo.toml | 20 ++++++++++++++++++++ - 1 file changed, 20 insertions(+) + library/stdarch/Cargo.toml | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) create mode 100644 library/stdarch/Cargo.toml diff --git a/library/stdarch/Cargo.toml b/library/stdarch/Cargo.toml new file mode 100644 -index 0000000..fbe0a95 +index 0000000..4c63700 --- /dev/null +++ b/library/stdarch/Cargo.toml -@@ -0,0 +1,20 @@ +@@ -0,0 +1,21 @@ +[workspace] ++resolver = "1" +members = [ + "crates/core_arch", + "crates/std_detect", + "crates/stdarch-gen", -+ "examples/" ++ #"examples/" +] +exclude = [ + "crates/wasm-assert-instr-tests" @@ -35,5 +36,5 @@ index 0000000..fbe0a95 +opt-level = 3 +incremental = true -- -2.26.2.7.g19db9cfb68.dirty +2.42.0 diff --git a/compiler/rustc_codegen_gcc/patches/0001-Disable-examples.patch b/compiler/rustc_codegen_gcc/patches/0001-Disable-examples.patch deleted file mode 100644 index 1b71df1ca8d..00000000000 --- a/compiler/rustc_codegen_gcc/patches/0001-Disable-examples.patch +++ /dev/null @@ -1,25 +0,0 @@ -From a2d53a324a02c04b76c0e9d39dc15cd443a3b8b2 Mon Sep 17 00:00:00 2001 -From: Antoni Boucher <bouanto@zoho.com> -Date: Fri, 25 Nov 2022 11:18:11 -0500 -Subject: [PATCH] Disable examples - ---- - library/stdarch/Cargo.toml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/library/stdarch/Cargo.toml b/library/stdarch/Cargo.toml -index fbe0a95..748d72d 100644 ---- a/library/stdarch/Cargo.toml -+++ b/library/stdarch/Cargo.toml -@@ -3,7 +3,7 @@ members = [ - "crates/core_arch", - "crates/std_detect", - "crates/stdarch-gen", -- "examples/" -+ #"examples/" - ] - exclude = [ - "crates/wasm-assert-instr-tests" --- -2.26.2.7.g19db9cfb68.dirty - diff --git a/compiler/rustc_codegen_gcc/prepare.sh b/compiler/rustc_codegen_gcc/prepare.sh deleted file mode 100755 index e98f24c6e12..00000000000 --- a/compiler/rustc_codegen_gcc/prepare.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash -set -e -set -v - -source prepare_build.sh - -cargo install hyperfine || echo "Skipping hyperfine install" - -git clone https://github.com/rust-random/rand.git || echo "rust-random/rand has already been cloned" -pushd rand -git checkout -- . -git checkout 0f933f9c7176e53b2a3c7952ded484e1783f0bf1 -git am ../crate_patches/*-rand-*.patch -popd - -git clone https://github.com/rust-lang/regex.git || echo "rust-lang/regex has already been cloned" -pushd regex -git checkout -- . -git checkout 341f207c1071f7290e3f228c710817c280c8dca1 -popd - -git clone https://github.com/ebobby/simple-raytracer || echo "ebobby/simple-raytracer has already been cloned" -pushd simple-raytracer -git checkout -- . -git checkout 804a7a21b9e673a482797aa289a18ed480e4d813 - -# build with cg_llvm for perf comparison -cargo build -mv target/debug/main raytracer_cg_llvm -popd diff --git a/compiler/rustc_codegen_gcc/prepare_build.sh b/compiler/rustc_codegen_gcc/prepare_build.sh deleted file mode 100755 index 8194360da4b..00000000000 --- a/compiler/rustc_codegen_gcc/prepare_build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash -set -e -set -v - -./build_sysroot/prepare_sysroot_src.sh diff --git a/compiler/rustc_codegen_gcc/rust-toolchain b/compiler/rustc_codegen_gcc/rust-toolchain index ebb04d0069c..25a1cea98cc 100644 --- a/compiler/rustc_codegen_gcc/rust-toolchain +++ b/compiler/rustc_codegen_gcc/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-06-19" +channel = "nightly-2023-10-08" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_gcc/rustup.sh b/compiler/rustc_codegen_gcc/rustup.sh index 041079bc9c6..a4f938e4b5b 100755 --- a/compiler/rustc_codegen_gcc/rustup.sh +++ b/compiler/rustc_codegen_gcc/rustup.sh @@ -16,7 +16,7 @@ case $1 in done ./clean_all.sh - ./prepare.sh + ./y.sh prepare ;; "commit") git add rust-toolchain diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index a49530ebb4c..35bb0b6e5f4 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -3,7 +3,9 @@ use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeMethods}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; use rustc_middle::ty::Ty; -use rustc_target::abi::call::{CastTarget, FnAbi, PassMode, Reg, RegKind}; +#[cfg(feature = "master")] +use rustc_session::config; +use rustc_target::abi::call::{ArgAttributes, CastTarget, FnAbi, PassMode, Reg, RegKind}; use crate::builder::Builder; use crate::context::CodegenCx; @@ -120,30 +122,50 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } }; + #[cfg(feature = "master")] + let apply_attrs = |ty: Type<'gcc>, attrs: &ArgAttributes| { + if cx.sess().opts.optimize != config::OptLevel::No + && attrs.regular.contains(rustc_target::abi::call::ArgAttribute::NoAlias) + { + ty.make_restrict() + } else { + ty + } + }; + #[cfg(not(feature = "master"))] + let apply_attrs = |ty: Type<'gcc>, _attrs: &ArgAttributes| { + ty + }; + for arg in self.args.iter() { let arg_ty = match arg.mode { PassMode::Ignore => continue, - PassMode::Direct(_) => arg.layout.immediate_gcc_type(cx), - PassMode::Pair(..) => { - argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 0)); - argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 1)); + PassMode::Pair(a, b) => { + argument_tys.push(apply_attrs(arg.layout.scalar_pair_element_gcc_type(cx, 0), &a)); + argument_tys.push(apply_attrs(arg.layout.scalar_pair_element_gcc_type(cx, 1), &b)); continue; } - PassMode::Indirect { meta_attrs: Some(_), .. } => { - unimplemented!(); - } PassMode::Cast { ref cast, pad_i32 } => { // add padding if pad_i32 { argument_tys.push(Reg::i32().gcc_type(cx)); } - cast.gcc_type(cx) + let ty = cast.gcc_type(cx); + apply_attrs(ty, &cast.attrs) } - PassMode::Indirect { meta_attrs: None, on_stack: true, .. } => { + PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: true } => { + // This is a "byval" argument, so we don't apply the `restrict` attribute on it. on_stack_param_indices.insert(argument_tys.len()); arg.memory_ty(cx) }, - PassMode::Indirect { meta_attrs: None, on_stack: false, .. } => cx.type_ptr_to(arg.memory_ty(cx)), + PassMode::Direct(attrs) => apply_attrs(arg.layout.immediate_gcc_type(cx), &attrs), + PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => { + apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs) + } + PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => { + assert!(!on_stack); + apply_attrs(apply_attrs(cx.type_ptr_to(arg.memory_ty(cx)), &attrs), &meta_attrs) + } }; argument_tys.push(arg_ty); } diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs index edd7ab722f6..c8c098e2973 100644 --- a/compiler/rustc_codegen_gcc/src/allocator.rs +++ b/compiler/rustc_codegen_gcc/src/allocator.rs @@ -1,6 +1,6 @@ #[cfg(feature="master")] use gccjit::FnAttribute; -use gccjit::{FunctionType, GlobalKind, ToRValue}; +use gccjit::{Context, FunctionType, GlobalKind, ToRValue, Type}; use rustc_ast::expand::allocator::{ alloc_error_handler_name, default_fn_name, global_fn_name, AllocatorKind, AllocatorTy, ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE, @@ -22,7 +22,6 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam }; let i8 = context.new_type::<i8>(); let i8p = i8.make_pointer(); - let void = context.new_type::<()>(); if kind == AllocatorKind::Default { for method in ALLOCATOR_METHODS { @@ -47,67 +46,62 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam panic!("invalid allocator output") } }; - let name = global_fn_name(method.name); + let from_name = global_fn_name(method.name); + let to_name = default_fn_name(method.name); - let args: Vec<_> = types.iter().enumerate() - .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) - .collect(); - let func = context.new_function(None, FunctionType::Exported, output.unwrap_or(void), &args, name, false); + create_wrapper_function(tcx, context, &from_name, &to_name, &types, output); + } + } - if tcx.sess.target.options.default_hidden_visibility { - #[cfg(feature="master")] - func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); - } - if tcx.sess.must_emit_unwind_tables() { - // TODO(antoyo): emit unwind tables. - } + // FIXME(bjorn3): Add noreturn attribute + create_wrapper_function( + tcx, + context, + "__rust_alloc_error_handler", + &alloc_error_handler_name(alloc_error_handler_kind), + &[usize, usize], + None, + ); - let callee = default_fn_name(method.name); - let args: Vec<_> = types.iter().enumerate() - .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) - .collect(); - let callee = context.new_function(None, FunctionType::Extern, output.unwrap_or(void), &args, callee, false); - #[cfg(feature="master")] - callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); - - let block = func.new_block("entry"); - - let args = args - .iter() - .enumerate() - .map(|(i, _)| func.get_param(i as i32).to_rvalue()) - .collect::<Vec<_>>(); - let ret = context.new_call(None, callee, &args); - //llvm::LLVMSetTailCall(ret, True); - if output.is_some() { - block.end_with_return(None, ret); - } - else { - block.end_with_void_return(None); - } + let name = OomStrategy::SYMBOL.to_string(); + let global = context.new_global(None, GlobalKind::Exported, i8, name); + let value = tcx.sess.opts.unstable_opts.oom.should_panic(); + let value = context.new_rvalue_from_int(i8, value as i32); + global.global_set_initializer_rvalue(value); - // TODO(@Commeownist): Check if we need to emit some extra debugging info in certain circumstances - // as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643 - } - } + let name = NO_ALLOC_SHIM_IS_UNSTABLE.to_string(); + let global = context.new_global(None, GlobalKind::Exported, i8, name); + let value = context.new_rvalue_from_int(i8, 0); + global.global_set_initializer_rvalue(value); +} + +fn create_wrapper_function( + tcx: TyCtxt<'_>, + context: &Context<'_>, + from_name: &str, + to_name: &str, + types: &[Type<'_>], + output: Option<Type<'_>>, +) { + let void = context.new_type::<()>(); - let types = [usize, usize]; - let name = "__rust_alloc_error_handler".to_string(); let args: Vec<_> = types.iter().enumerate() .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) .collect(); - let func = context.new_function(None, FunctionType::Exported, void, &args, name, false); + let func = context.new_function(None, FunctionType::Exported, output.unwrap_or(void), &args, from_name, false); - if tcx.sess.target.default_hidden_visibility { + if tcx.sess.target.options.default_hidden_visibility { #[cfg(feature="master")] func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); } + if tcx.sess.must_emit_unwind_tables() { + // TODO(antoyo): emit unwind tables. + } - let callee = alloc_error_handler_name(alloc_error_handler_kind); let args: Vec<_> = types.iter().enumerate() .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index))) .collect(); - let callee = context.new_function(None, FunctionType::Extern, void, &args, callee, false); + let callee = context.new_function(None, FunctionType::Extern, output.unwrap_or(void), &args, to_name, false); #[cfg(feature="master")] callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); @@ -118,18 +112,15 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam .enumerate() .map(|(i, _)| func.get_param(i as i32).to_rvalue()) .collect::<Vec<_>>(); - let _ret = context.new_call(None, callee, &args); + let ret = context.new_call(None, callee, &args); //llvm::LLVMSetTailCall(ret, True); - block.end_with_void_return(None); - - let name = OomStrategy::SYMBOL.to_string(); - let global = context.new_global(None, GlobalKind::Exported, i8, name); - let value = tcx.sess.opts.unstable_opts.oom.should_panic(); - let value = context.new_rvalue_from_int(i8, value as i32); - global.global_set_initializer_rvalue(value); + if output.is_some() { + block.end_with_return(None, ret); + } + else { + block.end_with_void_return(None); + } - let name = NO_ALLOC_SHIM_IS_UNSTABLE.to_string(); - let global = context.new_global(None, GlobalKind::Exported, i8, name); - let value = context.new_rvalue_from_int(i8, 0); - global.global_set_initializer_rvalue(value); + // TODO(@Commeownist): Check if we need to emit some extra debugging info in certain circumstances + // as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643 } diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 905fdac92e9..f3a9ca77a67 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -452,10 +452,6 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } InlineAsmOperandRef::Const { ref string } => { - // Const operands get injected directly into the template - if att_dialect { - template_str.push('$'); - } template_str.push_str(string); } } diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs index eb0cce19b85..971e019a4f6 100644 --- a/compiler/rustc_codegen_gcc/src/attributes.rs +++ b/compiler/rustc_codegen_gcc/src/attributes.rs @@ -4,72 +4,13 @@ use gccjit::Function; use rustc_attr::InstructionSetAttr; #[cfg(feature="master")] use rustc_attr::InlineAttr; -use rustc_codegen_ssa::target_features::tied_target_features; -use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty; #[cfg(feature="master")] use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_session::Session; use rustc_span::symbol::sym; -use smallvec::{smallvec, SmallVec}; use crate::{context::CodegenCx, errors::TiedTargetFeatures}; - -// Given a map from target_features to whether they are enabled or disabled, -// ensure only valid combinations are allowed. -pub fn check_tied_features(sess: &Session, features: &FxHashMap<&str, bool>) -> Option<&'static [&'static str]> { - for tied in tied_target_features(sess) { - // Tied features must be set to the same value, or not set at all - let mut tied_iter = tied.iter(); - let enabled = features.get(tied_iter.next().unwrap()); - if tied_iter.any(|feature| enabled != features.get(feature)) { - return Some(tied); - } - } - None -} - -// TODO(antoyo): maybe move to a new module gcc_util. -// To find a list of GCC's names, check https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html -fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> { - let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch }; - match (arch, s) { - ("x86", "sse4.2") => smallvec!["sse4.2", "crc32"], - ("x86", "pclmulqdq") => smallvec!["pclmul"], - ("x86", "rdrand") => smallvec!["rdrnd"], - ("x86", "bmi1") => smallvec!["bmi"], - ("x86", "cmpxchg16b") => smallvec!["cx16"], - ("x86", "avx512vaes") => smallvec!["vaes"], - ("x86", "avx512gfni") => smallvec!["gfni"], - ("x86", "avx512vpclmulqdq") => smallvec!["vpclmulqdq"], - // NOTE: seems like GCC requires 'avx512bw' for 'avx512vbmi2'. - ("x86", "avx512vbmi2") => smallvec!["avx512vbmi2", "avx512bw"], - // NOTE: seems like GCC requires 'avx512bw' for 'avx512bitalg'. - ("x86", "avx512bitalg") => smallvec!["avx512bitalg", "avx512bw"], - ("aarch64", "rcpc2") => smallvec!["rcpc-immo"], - ("aarch64", "dpb") => smallvec!["ccpp"], - ("aarch64", "dpb2") => smallvec!["ccdp"], - ("aarch64", "frintts") => smallvec!["fptoint"], - ("aarch64", "fcma") => smallvec!["complxnum"], - ("aarch64", "pmuv3") => smallvec!["perfmon"], - ("aarch64", "paca") => smallvec!["pauth"], - ("aarch64", "pacg") => smallvec!["pauth"], - // Rust ties fp and neon together. In LLVM neon implicitly enables fp, - // but we manually enable neon when a feature only implicitly enables fp - ("aarch64", "f32mm") => smallvec!["f32mm", "neon"], - ("aarch64", "f64mm") => smallvec!["f64mm", "neon"], - ("aarch64", "fhm") => smallvec!["fp16fml", "neon"], - ("aarch64", "fp16") => smallvec!["fullfp16", "neon"], - ("aarch64", "jsconv") => smallvec!["jsconv", "neon"], - ("aarch64", "sve") => smallvec!["sve", "neon"], - ("aarch64", "sve2") => smallvec!["sve2", "neon"], - ("aarch64", "sve2-aes") => smallvec!["sve2-aes", "neon"], - ("aarch64", "sve2-sm4") => smallvec!["sve2-sm4", "neon"], - ("aarch64", "sve2-sha3") => smallvec!["sve2-sha3", "neon"], - ("aarch64", "sve2-bitperm") => smallvec!["sve2-bitperm", "neon"], - (_, s) => smallvec![s], - } -} +use crate::gcc_util::{check_tied_features, to_gcc_features}; /// Get GCC attribute for the provided inline heuristic. #[cfg(feature="master")] @@ -114,6 +55,19 @@ pub fn from_fn_attrs<'gcc, 'tcx>( if let Some(attr) = inline_attr(cx, inline) { func.add_attribute(attr); } + + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) { + func.add_attribute(FnAttribute::Cold); + } + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_RETURNS_TWICE) { + func.add_attribute(FnAttribute::ReturnsTwice); + } + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_PURE) { + func.add_attribute(FnAttribute::Pure); + } + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_CONST) { + func.add_attribute(FnAttribute::Const); + } } let function_features = @@ -140,11 +94,33 @@ pub fn from_fn_attrs<'gcc, 'tcx>( })) .collect::<Vec<_>>(); - // TODO(antoyo): check if we really need global backend features. (Maybe they could be applied - // globally?) + // TODO(antoyo): cg_llvm adds global features to each function so that LTO keep them. + // Check if GCC requires the same. let mut global_features = cx.tcx.global_backend_features(()).iter().map(|s| s.as_str()); function_features.extend(&mut global_features); - let target_features = function_features.join(","); + let target_features = function_features + .iter() + .filter_map(|feature| { + // FIXME(antoyo): for some reasons, disabling SSE results in the following error when + // compiling Rust for Linux: + // SSE register return with SSE disabled + // TODO(antoyo): support soft-float and retpoline-external-thunk. + if feature.contains("soft-float") || feature.contains("retpoline-external-thunk") || *feature == "-sse" { + return None; + } + + if feature.starts_with('-') { + Some(format!("no{}", feature)) + } + else if feature.starts_with('+') { + Some(feature[1..].to_string()) + } + else { + Some(feature.to_string()) + } + }) + .collect::<Vec<_>>() + .join(","); if !target_features.is_empty() { #[cfg(feature="master")] func.add_attribute(FnAttribute::Target(&target_features)); diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs new file mode 100644 index 00000000000..529454b119e --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -0,0 +1,341 @@ +/// GCC requires to use the same toolchain for the whole compilation when doing LTO. +/// So, we need the same version/commit of the linker (gcc) and lto front-end binaries (lto1, +/// lto-wrapper, liblto_plugin.so). + +// FIXME(antoyo): the executables compiled with LTO are bigger than those compiled without LTO. +// Since it is the opposite for cg_llvm, check if this is normal. +// +// Maybe we embed the bitcode in the final binary? +// It doesn't look like we try to generate fat objects for the final binary. +// Check if the way we combine the object files make it keep the LTO sections on the final link. +// Maybe that's because the combined object files contain the IR (true) and the final link +// does not remove it? +// +// TODO(antoyo): for performance, check which optimizations the C++ frontend enables. +// +// Fix these warnings: +// /usr/bin/ld: warning: type of symbol `_RNvNvNvNtCs5JWOrf9uCus_5rayon11thread_pool19WORKER_THREAD_STATE7___getit5___KEY' changed from 1 to 6 in /tmp/ccKeUSiR.ltrans0.ltrans.o +// /usr/bin/ld: warning: type of symbol `_RNvNvNvNvNtNtNtCsAj5i4SGTR7_3std4sync4mpmc5waker17current_thread_id5DUMMY7___getit5___KEY' changed from 1 to 6 in /tmp/ccKeUSiR.ltrans0.ltrans.o +// /usr/bin/ld: warning: incremental linking of LTO and non-LTO objects; using -flinker-output=nolto-rel which will bypass whole program optimization + +use std::ffi::CString; +use std::fs::{self, File}; +use std::path::{Path, PathBuf}; + +use gccjit::OutputKind; +use object::read::archive::ArchiveFile; +use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule}; +use rustc_codegen_ssa::back::symbol_export; +use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput}; +use rustc_codegen_ssa::traits::*; +use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind}; +use rustc_data_structures::memmap::Mmap; +use rustc_errors::{FatalError, Handler}; +use rustc_hir::def_id::LOCAL_CRATE; +use rustc_middle::dep_graph::WorkProduct; +use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; +use rustc_session::config::{CrateType, Lto}; +use tempfile::{TempDir, tempdir}; + +use crate::back::write::save_temp_bitcode; +use crate::errors::{ + DynamicLinkingWithLTO, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib, +}; +use crate::{GccCodegenBackend, GccContext, to_gcc_opt_level}; + +/// We keep track of the computed LTO cache keys from the previous +/// session to determine which CGUs we can reuse. +//pub const THIN_LTO_KEYS_INCR_COMP_FILE_NAME: &str = "thin-lto-past-keys.bin"; + +pub fn crate_type_allows_lto(crate_type: CrateType) -> bool { + match crate_type { + CrateType::Executable | CrateType::Dylib | CrateType::Staticlib | CrateType::Cdylib => true, + CrateType::Rlib | CrateType::ProcMacro => false, + } +} + +struct LtoData { + // TODO(antoyo): use symbols_below_threshold. + //symbols_below_threshold: Vec<CString>, + upstream_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>, + tmp_path: TempDir, +} + +fn prepare_lto(cgcx: &CodegenContext<GccCodegenBackend>, diag_handler: &Handler) -> Result<LtoData, FatalError> { + let export_threshold = match cgcx.lto { + // We're just doing LTO for our one crate + Lto::ThinLocal => SymbolExportLevel::Rust, + + // We're doing LTO for the entire crate graph + Lto::Fat | Lto::Thin => symbol_export::crates_export_threshold(&cgcx.crate_types), + + Lto::No => panic!("didn't request LTO but we're doing LTO"), + }; + + let tmp_path = + match tempdir() { + Ok(tmp_path) => tmp_path, + Err(error) => { + eprintln!("Cannot create temporary directory: {}", error); + return Err(FatalError); + }, + }; + + let symbol_filter = &|&(ref name, info): &(String, SymbolExportInfo)| { + if info.level.is_below_threshold(export_threshold) || info.used { + Some(CString::new(name.as_str()).unwrap()) + } else { + None + } + }; + let exported_symbols = cgcx.exported_symbols.as_ref().expect("needs exported symbols for LTO"); + let mut symbols_below_threshold = { + let _timer = cgcx.prof.generic_activity("GCC_lto_generate_symbols_below_threshold"); + exported_symbols[&LOCAL_CRATE].iter().filter_map(symbol_filter).collect::<Vec<CString>>() + }; + info!("{} symbols to preserve in this crate", symbols_below_threshold.len()); + + // If we're performing LTO for the entire crate graph, then for each of our + // upstream dependencies, find the corresponding rlib and load the bitcode + // from the archive. + // + // We save off all the bytecode and GCC module file path for later processing + // with either fat or thin LTO + let mut upstream_modules = Vec::new(); + if cgcx.lto != Lto::ThinLocal { + // Make sure we actually can run LTO + for crate_type in cgcx.crate_types.iter() { + if !crate_type_allows_lto(*crate_type) { + diag_handler.emit_err(LtoDisallowed); + return Err(FatalError); + } else if *crate_type == CrateType::Dylib { + if !cgcx.opts.unstable_opts.dylib_lto { + diag_handler.emit_err(LtoDylib); + return Err(FatalError); + } + } + } + + if cgcx.opts.cg.prefer_dynamic && !cgcx.opts.unstable_opts.dylib_lto { + diag_handler.emit_err(DynamicLinkingWithLTO); + return Err(FatalError); + } + + for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() { + let exported_symbols = + cgcx.exported_symbols.as_ref().expect("needs exported symbols for LTO"); + { + let _timer = + cgcx.prof.generic_activity("GCC_lto_generate_symbols_below_threshold"); + symbols_below_threshold + .extend(exported_symbols[&cnum].iter().filter_map(symbol_filter)); + } + + let archive_data = unsafe { + Mmap::map(File::open(&path).expect("couldn't open rlib")) + .expect("couldn't map rlib") + }; + let archive = ArchiveFile::parse(&*archive_data).expect("wanted an rlib"); + let obj_files = archive + .members() + .filter_map(|child| { + child.ok().and_then(|c| { + std::str::from_utf8(c.name()).ok().map(|name| (name.trim(), c)) + }) + }) + .filter(|&(name, _)| looks_like_rust_object_file(name)); + for (name, child) in obj_files { + info!("adding bitcode from {}", name); + let path = tmp_path.path().join(name); + match save_as_file(child.data(&*archive_data).expect("corrupt rlib"), &path) { + Ok(()) => { + let buffer = ModuleBuffer::new(path); + let module = SerializedModule::Local(buffer); + upstream_modules.push((module, CString::new(name).unwrap())); + } + Err(e) => { + diag_handler.emit_err(e); + return Err(FatalError); + } + } + } + } + } + + Ok(LtoData { + //symbols_below_threshold, + upstream_modules, + tmp_path, + }) +} + +fn save_as_file(obj: &[u8], path: &Path) -> Result<(), LtoBitcodeFromRlib> { + fs::write(path, obj) + .map_err(|error| LtoBitcodeFromRlib { + gcc_err: format!("write object file to temp dir: {}", error) + }) +} + +/// Performs fat LTO by merging all modules into a single one and returning it +/// for further optimization. +pub(crate) fn run_fat( + cgcx: &CodegenContext<GccCodegenBackend>, + modules: Vec<FatLtoInput<GccCodegenBackend>>, + cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, +) -> Result<LtoModuleCodegen<GccCodegenBackend>, FatalError> { + let diag_handler = cgcx.create_diag_handler(); + let lto_data = prepare_lto(cgcx, &diag_handler)?; + /*let symbols_below_threshold = + lto_data.symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();*/ + fat_lto(cgcx, &diag_handler, modules, cached_modules, lto_data.upstream_modules, lto_data.tmp_path, + //&symbols_below_threshold, + ) +} + +fn fat_lto(cgcx: &CodegenContext<GccCodegenBackend>, _diag_handler: &Handler, modules: Vec<FatLtoInput<GccCodegenBackend>>, cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>, tmp_path: TempDir, + //symbols_below_threshold: &[*const libc::c_char], +) -> Result<LtoModuleCodegen<GccCodegenBackend>, FatalError> { + let _timer = cgcx.prof.generic_activity("GCC_fat_lto_build_monolithic_module"); + info!("going for a fat lto"); + + // Sort out all our lists of incoming modules into two lists. + // + // * `serialized_modules` (also and argument to this function) contains all + // modules that are serialized in-memory. + // * `in_memory` contains modules which are already parsed and in-memory, + // such as from multi-CGU builds. + // + // All of `cached_modules` (cached from previous incremental builds) can + // immediately go onto the `serialized_modules` modules list and then we can + // split the `modules` array into these two lists. + let mut in_memory = Vec::new(); + serialized_modules.extend(cached_modules.into_iter().map(|(buffer, wp)| { + info!("pushing cached module {:?}", wp.cgu_name); + (buffer, CString::new(wp.cgu_name).unwrap()) + })); + for module in modules { + match module { + FatLtoInput::InMemory(m) => in_memory.push(m), + FatLtoInput::Serialized { name, buffer } => { + info!("pushing serialized module {:?}", name); + let buffer = SerializedModule::Local(buffer); + serialized_modules.push((buffer, CString::new(name).unwrap())); + } + } + } + + // Find the "costliest" module and merge everything into that codegen unit. + // All the other modules will be serialized and reparsed into the new + // context, so this hopefully avoids serializing and parsing the largest + // codegen unit. + // + // Additionally use a regular module as the base here to ensure that various + // file copy operations in the backend work correctly. The only other kind + // of module here should be an allocator one, and if your crate is smaller + // than the allocator module then the size doesn't really matter anyway. + let costliest_module = in_memory + .iter() + .enumerate() + .filter(|&(_, module)| module.kind == ModuleKind::Regular) + .map(|(i, _module)| { + //let cost = unsafe { llvm::LLVMRustModuleCost(module.module_llvm.llmod()) }; + // TODO(antoyo): compute the cost of a module if GCC allows this. + (0, i) + }) + .max(); + + // If we found a costliest module, we're good to go. Otherwise all our + // inputs were serialized which could happen in the case, for example, that + // all our inputs were incrementally reread from the cache and we're just + // re-executing the LTO passes. If that's the case deserialize the first + // module and create a linker with it. + let mut module: ModuleCodegen<GccContext> = match costliest_module { + Some((_cost, i)) => in_memory.remove(i), + None => { + unimplemented!("Incremental"); + /*assert!(!serialized_modules.is_empty(), "must have at least one serialized module"); + let (buffer, name) = serialized_modules.remove(0); + info!("no in-memory regular modules to choose from, parsing {:?}", name); + ModuleCodegen { + module_llvm: GccContext::parse(cgcx, &name, buffer.data(), diag_handler)?, + name: name.into_string().unwrap(), + kind: ModuleKind::Regular, + }*/ + } + }; + let mut serialized_bitcode = Vec::new(); + { + info!("using {:?} as a base module", module.name); + + // We cannot load and merge GCC contexts in memory like cg_llvm is doing. + // Instead, we combine the object files into a single object file. + for module in in_memory { + let path = tmp_path.path().to_path_buf().join(&module.name); + let path = path.to_str().expect("path"); + let context = &module.module_llvm.context; + let config = cgcx.config(module.kind); + // NOTE: we need to set the optimization level here in order for LTO to do its job. + context.set_optimization_level(to_gcc_opt_level(config.opt_level)); + context.add_command_line_option("-flto=auto"); + context.add_command_line_option("-flto-partition=one"); + context.compile_to_file(OutputKind::ObjectFile, path); + let buffer = ModuleBuffer::new(PathBuf::from(path)); + let llmod_id = CString::new(&module.name[..]).unwrap(); + serialized_modules.push((SerializedModule::Local(buffer), llmod_id)); + } + // Sort the modules to ensure we produce deterministic results. + serialized_modules.sort_by(|module1, module2| module1.1.cmp(&module2.1)); + + // We add the object files and save in should_combine_object_files that we should combine + // them into a single object file when compiling later. + for (bc_decoded, name) in serialized_modules { + let _timer = cgcx + .prof + .generic_activity_with_arg_recorder("GCC_fat_lto_link_module", |recorder| { + recorder.record_arg(format!("{:?}", name)) + }); + info!("linking {:?}", name); + match bc_decoded { + SerializedModule::Local(ref module_buffer) => { + module.module_llvm.should_combine_object_files = true; + module.module_llvm.context.add_driver_option(module_buffer.0.to_str().expect("path")); + }, + SerializedModule::FromRlib(_) => unimplemented!("from rlib"), + SerializedModule::FromUncompressedFile(_) => unimplemented!("from uncompressed file"), + } + serialized_bitcode.push(bc_decoded); + } + save_temp_bitcode(cgcx, &module, "lto.input"); + + // Internalize everything below threshold to help strip out more modules and such. + /*unsafe { + let ptr = symbols_below_threshold.as_ptr(); + llvm::LLVMRustRunRestrictionPass( + llmod, + ptr as *const *const libc::c_char, + symbols_below_threshold.len() as libc::size_t, + );*/ + save_temp_bitcode(cgcx, &module, "lto.after-restriction"); + //} + } + + // NOTE: save the temporary directory used by LTO so that it gets deleted after linking instead + // of now. + module.module_llvm.temp_dir = Some(tmp_path); + + Ok(LtoModuleCodegen::Fat { module, _serialized_bitcode: serialized_bitcode }) +} + +pub struct ModuleBuffer(PathBuf); + +impl ModuleBuffer { + pub fn new(path: PathBuf) -> ModuleBuffer { + ModuleBuffer(path) + } +} + +impl ModuleBufferMethods for ModuleBuffer { + fn data(&self) -> &[u8] { + unimplemented!("data not needed for GCC codegen"); + } +} diff --git a/compiler/rustc_codegen_gcc/src/back/mod.rs b/compiler/rustc_codegen_gcc/src/back/mod.rs index d692799d764..10187eab0d7 100644 --- a/compiler/rustc_codegen_gcc/src/back/mod.rs +++ b/compiler/rustc_codegen_gcc/src/back/mod.rs @@ -1 +1,2 @@ +pub mod lto; pub mod write; diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index 5f54ac4ebc6..04772d7707a 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -2,27 +2,71 @@ use std::{env, fs}; use gccjit::OutputKind; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; -use rustc_codegen_ssa::back::write::{CodegenContext, EmitObj, ModuleConfig}; +use rustc_codegen_ssa::back::link::ensure_removed; +use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig}; use rustc_errors::Handler; +use rustc_fs_util::link_or_copy; use rustc_session::config::OutputType; use rustc_span::fatal_error::FatalError; use rustc_target::spec::SplitDebuginfo; use crate::{GccCodegenBackend, GccContext}; +use crate::errors::CopyBitcode; -pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, _diag_handler: &Handler, module: ModuleCodegen<GccContext>, config: &ModuleConfig) -> Result<CompiledModule, FatalError> { - let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen", &*module.name); +pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, diag_handler: &Handler, module: ModuleCodegen<GccContext>, config: &ModuleConfig) -> Result<CompiledModule, FatalError> { + let _timer = cgcx.prof.generic_activity_with_arg("GCC_module_codegen", &*module.name); { let context = &module.module_llvm.context; let module_name = module.name.clone(); + + let should_combine_object_files = module.module_llvm.should_combine_object_files; + let module_name = Some(&module_name[..]); - let _bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name); + // NOTE: Only generate object files with GIMPLE when this environment variable is set for + // now because this requires a particular setup (same gcc/lto1/lto-wrapper commit as libgccjit). + let fat_lto = env::var("EMBED_LTO_BITCODE").as_deref() == Ok("1"); + + let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name); let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name); - if config.bitcode_needed() { + if config.bitcode_needed() && fat_lto { + let _timer = cgcx + .prof + .generic_activity_with_arg("GCC_module_codegen_make_bitcode", &*module.name); + // TODO(antoyo) + /*if let Some(bitcode_filename) = bc_out.file_name() { + cgcx.prof.artifact_size( + "llvm_bitcode", + bitcode_filename.to_string_lossy(), + data.len() as u64, + ); + }*/ + + if config.emit_bc || config.emit_obj == EmitObj::Bitcode { + let _timer = cgcx + .prof + .generic_activity_with_arg("GCC_module_codegen_emit_bitcode", &*module.name); + context.add_command_line_option("-flto=auto"); + context.add_command_line_option("-flto-partition=one"); + context.compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str")); + } + + if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) { + let _timer = cgcx + .prof + .generic_activity_with_arg("GCC_module_codegen_embed_bitcode", &*module.name); + // TODO(antoyo): maybe we should call embed_bitcode to have the proper iOS fixes? + //embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data); + + context.add_command_line_option("-flto=auto"); + context.add_command_line_option("-flto-partition=one"); + context.add_command_line_option("-ffat-lto-objects"); + // TODO(antoyo): Send -plugin/usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/liblto_plugin.so to linker (this should be done when specifying the appropriate rustc cli argument). + context.compile_to_file(OutputKind::ObjectFile, bc_out.to_str().expect("path to str")); + } } if config.emit_ir { @@ -32,7 +76,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, _diag_han if config.emit_asm { let _timer = cgcx .prof - .generic_activity_with_arg("LLVM_module_codegen_emit_asm", &*module.name); + .generic_activity_with_arg("GCC_module_codegen_emit_asm", &*module.name); let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); context.compile_to_file(OutputKind::Assembler, path.to_str().expect("path to str")); } @@ -41,7 +85,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, _diag_han EmitObj::ObjectCode(_) => { let _timer = cgcx .prof - .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &*module.name); + .generic_activity_with_arg("GCC_module_codegen_emit_obj", &*module.name); if env::var("CG_GCCJIT_DUMP_MODULE_NAMES").as_deref() == Ok("1") { println!("Module {}", module.name); } @@ -60,11 +104,36 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, _diag_han context.set_debug_info(true); context.dump_to_file(path, true); } - context.compile_to_file(OutputKind::ObjectFile, obj_out.to_str().expect("path to str")); + if should_combine_object_files && fat_lto { + context.add_command_line_option("-flto=auto"); + context.add_command_line_option("-flto-partition=one"); + + context.add_driver_option("-Wl,-r"); + // NOTE: we need -nostdlib, otherwise, we get the following error: + // /usr/bin/ld: cannot find -lgcc_s: No such file or directory + context.add_driver_option("-nostdlib"); + // NOTE: without -fuse-linker-plugin, we get the following error: + // lto1: internal compiler error: decompressed stream: Destination buffer is too small + context.add_driver_option("-fuse-linker-plugin"); + + // NOTE: this doesn't actually generate an executable. With the above flags, it combines the .o files together in another .o. + context.compile_to_file(OutputKind::Executable, obj_out.to_str().expect("path to str")); + } + else { + context.compile_to_file(OutputKind::ObjectFile, obj_out.to_str().expect("path to str")); + } } EmitObj::Bitcode => { - // TODO(antoyo) + debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out); + if let Err(err) = link_or_copy(&bc_out, &obj_out) { + diag_handler.emit_err(CopyBitcode { err }); + } + + if !config.emit_bc { + debug!("removing_bitcode {:?}", bc_out); + ensure_removed(diag_handler, &bc_out); + } } EmitObj::None => {} @@ -82,3 +151,18 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, _diag_han pub(crate) fn link(_cgcx: &CodegenContext<GccCodegenBackend>, _diag_handler: &Handler, mut _modules: Vec<ModuleCodegen<GccContext>>) -> Result<ModuleCodegen<GccContext>, FatalError> { unimplemented!(); } + +pub(crate) fn save_temp_bitcode(cgcx: &CodegenContext<GccCodegenBackend>, _module: &ModuleCodegen<GccContext>, _name: &str) { + if !cgcx.save_temps { + return; + } + unimplemented!(); + /*unsafe { + let ext = format!("{}.bc", name); + let cgu = Some(&module.name[..]); + let path = cgcx.output_filenames.temp_path_ext(&ext, cgu); + let cstr = path_to_c_string(&path); + let llmod = module.module_llvm.llmod(); + llvm::LLVMWriteBitcodeToFile(llmod, cstr.as_ptr()); + }*/ +} diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs index 9e614ca4ace..b081e9ff2fd 100644 --- a/compiler/rustc_codegen_gcc/src/base.rs +++ b/compiler/rustc_codegen_gcc/src/base.rs @@ -1,3 +1,4 @@ +use std::collections::HashSet; use std::env; use std::time::Instant; @@ -18,6 +19,7 @@ use rustc_codegen_ssa::traits::DebugInfoMethods; use rustc_session::config::DebugInfo; use rustc_span::Symbol; +use crate::{LockedTargetInfo, gcc_util}; use crate::GccContext; use crate::builder::Builder; use crate::context::CodegenCx; @@ -50,6 +52,7 @@ pub fn global_linkage_to_gcc(linkage: Linkage) -> GlobalKind { pub fn linkage_to_gcc(linkage: Linkage) -> FunctionType { match linkage { Linkage::External => FunctionType::Exported, + // TODO(antoyo): set the attribute externally_visible. Linkage::AvailableExternally => FunctionType::Extern, Linkage::LinkOnceAny => unimplemented!(), Linkage::LinkOnceODR => unimplemented!(), @@ -63,7 +66,7 @@ pub fn linkage_to_gcc(linkage: Linkage) -> FunctionType { } } -pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_integers: bool) -> (ModuleCodegen<GccContext>, u64) { +pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: LockedTargetInfo) -> (ModuleCodegen<GccContext>, u64) { let prof_timer = tcx.prof.generic_activity("codegen_module"); let start_time = Instant::now(); @@ -71,7 +74,7 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_i let (module, _) = tcx.dep_graph.with_task( dep_node, tcx, - (cgu_name, supports_128bit_integers), + (cgu_name, target_info), module_codegen, Some(dep_graph::hash_result), ); @@ -82,38 +85,28 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_i // the time we needed for codegenning it. let cost = time_to_codegen.as_secs() * 1_000_000_000 + time_to_codegen.subsec_nanos() as u64; - fn module_codegen(tcx: TyCtxt<'_>, (cgu_name, supports_128bit_integers): (Symbol, bool)) -> ModuleCodegen<GccContext> { + fn module_codegen(tcx: TyCtxt<'_>, (cgu_name, target_info): (Symbol, LockedTargetInfo)) -> ModuleCodegen<GccContext> { let cgu = tcx.codegen_unit(cgu_name); // Instantiate monomorphizations without filling out definitions yet... - //let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str()); let context = Context::default(); context.add_command_line_option("-fexceptions"); context.add_driver_option("-fexceptions"); + let disabled_features: HashSet<_> = tcx.sess.opts.cg.target_feature.split(',') + .filter(|feature| feature.starts_with('-')) + .map(|string| &string[1..]) + .collect(); + // TODO(antoyo): only set on x86 platforms. context.add_command_line_option("-masm=intel"); - // TODO(antoyo): only add the following cli argument if the feature is supported. - context.add_command_line_option("-msse2"); - context.add_command_line_option("-mavx2"); - // FIXME(antoyo): the following causes an illegal instruction on vmovdqu64 in std_example on my CPU. - // Only add if the CPU supports it. - context.add_command_line_option("-msha"); - context.add_command_line_option("-mpclmul"); - context.add_command_line_option("-mfma"); - context.add_command_line_option("-mfma4"); - context.add_command_line_option("-m64"); - context.add_command_line_option("-mbmi"); - context.add_command_line_option("-mgfni"); - //context.add_command_line_option("-mavxvnni"); // The CI doesn't support this option. - context.add_command_line_option("-mf16c"); - context.add_command_line_option("-maes"); - context.add_command_line_option("-mxsavec"); - context.add_command_line_option("-mbmi2"); - context.add_command_line_option("-mrtm"); - context.add_command_line_option("-mvaes"); - context.add_command_line_option("-mvpclmulqdq"); - context.add_command_line_option("-mavx"); + + if !disabled_features.contains("avx") { + // NOTE: we always enable AVX because the equivalent of llvm.x86.sse2.cmp.pd in GCC for + // SSE2 is multiple builtins, so we use the AVX __builtin_ia32_cmppd instead. + // FIXME(antoyo): use the proper builtins for llvm.x86.sse2.cmp.pd and similar. + context.add_command_line_option("-mavx"); + } for arg in &tcx.sess.opts.cg.llvm_args { context.add_command_line_option(arg); @@ -127,6 +120,16 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_i // NOTE: Rust relies on LLVM doing wrapping on overflow. context.add_command_line_option("-fwrapv"); + if tcx.sess.relocation_model() == rustc_target::spec::RelocModel::Static { + context.add_command_line_option("-mcmodel=kernel"); + context.add_command_line_option("-fno-pie"); + } + + let target_cpu = gcc_util::target_cpu(tcx.sess); + if target_cpu != "generic" { + context.add_command_line_option(&format!("-march={}", target_cpu)); + } + if tcx.sess.opts.unstable_opts.function_sections.unwrap_or(tcx.sess.target.function_sections) { context.add_command_line_option("-ffunction-sections"); context.add_command_line_option("-fdata-sections"); @@ -135,8 +138,14 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_i if env::var("CG_GCCJIT_DUMP_RTL").as_deref() == Ok("1") { context.add_command_line_option("-fdump-rtl-vregs"); } + if env::var("CG_GCCJIT_DUMP_RTL_ALL").as_deref() == Ok("1") { + context.add_command_line_option("-fdump-rtl-all"); + } if env::var("CG_GCCJIT_DUMP_TREE_ALL").as_deref() == Ok("1") { - context.add_command_line_option("-fdump-tree-all"); + context.add_command_line_option("-fdump-tree-all-eh"); + } + if env::var("CG_GCCJIT_DUMP_IPA_ALL").as_deref() == Ok("1") { + context.add_command_line_option("-fdump-ipa-all-eh"); } if env::var("CG_GCCJIT_DUMP_CODE").as_deref() == Ok("1") { context.set_dump_code_on_compile(true); @@ -152,11 +161,15 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_i context.set_keep_intermediates(true); } + if env::var("CG_GCCJIT_VERBOSE").as_deref() == Ok("1") { + context.add_driver_option("-v"); + } + // NOTE: The codegen generates unrechable blocks. context.set_allow_unreachable_blocks(true); { - let cx = CodegenCx::new(&context, cgu, tcx, supports_128bit_integers); + let cx = CodegenCx::new(&context, cgu, tcx, target_info.supports_128bit_int()); let mono_items = cgu.items_in_deterministic_order(tcx); for &(mono_item, data) in &mono_items { @@ -181,7 +194,9 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_i ModuleCodegen { name: cgu_name.to_string(), module_llvm: GccContext { - context + context, + should_combine_object_files: false, + temp_dir: None, }, kind: ModuleKind::Regular, } diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index ecc293aee23..b7841808934 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -247,16 +247,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } fn check_store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> { - let dest_ptr_ty = self.cx.val_ty(ptr).make_pointer(); // TODO(antoyo): make sure make_pointer() is okay here. let stored_ty = self.cx.val_ty(val); let stored_ptr_ty = self.cx.type_ptr_to(stored_ty); - - if dest_ptr_ty == stored_ptr_ty { - ptr - } - else { - self.bitcast(ptr, stored_ptr_ty) - } + self.bitcast(ptr, stored_ptr_ty) } pub fn current_func(&self) -> Function<'gcc> { @@ -500,7 +493,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } #[cfg(not(feature="master"))] - fn invoke(&mut self, typ: Type<'gcc>, fn_attrs: &CodegenFnAttrs, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> { + fn invoke(&mut self, typ: Type<'gcc>, fn_attrs: Option<&CodegenFnAttrs>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> { let call_site = self.call(typ, fn_attrs, None, func, args, None); let condition = self.context.new_rvalue_from_int(self.bool_type, 1); self.llbb().end_with_conditional(None, condition, then, catch); @@ -663,7 +656,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn unchecked_sadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - a + b + self.gcc_add(a, b) } fn unchecked_uadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -671,7 +664,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn unchecked_ssub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - a - b + self.gcc_sub(a, b) } fn unchecked_usub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -680,11 +673,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn unchecked_smul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - a * b + self.gcc_mul(a, b) } fn unchecked_umul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - a * b + self.gcc_mul(a, b) } fn fadd_fast(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> { @@ -916,7 +909,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { .add_eval(None, self.context.new_call(None, atomic_store, &[ptr, value, ordering])); } - fn gep(&mut self, _typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> { + fn gep(&mut self, typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> { + // NOTE: due to opaque pointers now being used, we need to cast here. + let ptr = self.context.new_cast(None, ptr, typ.make_pointer()); let ptr_type = ptr.get_type(); let mut pointee_type = ptr.get_type(); // NOTE: we cannot use array indexing here like in inbounds_gep because array indexing is @@ -927,6 +922,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // require dereferencing the pointer. for index in indices { pointee_type = pointee_type.get_pointee().expect("pointee type"); + #[cfg(feature="master")] + let pointee_size = { + let size = self.cx.context.new_sizeof(pointee_type); + self.context.new_cast(None, size, index.get_type()) + }; + #[cfg(not(feature="master"))] let pointee_size = self.context.new_rvalue_from_int(index.get_type(), pointee_type.get_size() as i32); result = result + self.gcc_int_cast(*index * pointee_size, self.sizet_type); } diff --git a/compiler/rustc_codegen_gcc/src/declare.rs b/compiler/rustc_codegen_gcc/src/declare.rs index 493626c3cf5..e673d0af4c7 100644 --- a/compiler/rustc_codegen_gcc/src/declare.rs +++ b/compiler/rustc_codegen_gcc/src/declare.rs @@ -1,4 +1,6 @@ use gccjit::{Function, FunctionType, GlobalKind, LValue, RValue, Type}; +#[cfg(feature="master")] +use gccjit::{FnAttribute, ToRValue}; use rustc_codegen_ssa::traits::BaseTypeMethods; use rustc_middle::ty::Ty; use rustc_span::Symbol; @@ -114,6 +116,44 @@ fn declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () /*ll .collect(); let func = cx.context.new_function(None, cx.linkage.get(), return_type, ¶ms, mangle_name(name), variadic); cx.functions.borrow_mut().insert(name.to_string(), func); + + #[cfg(feature="master")] + if name == "rust_eh_personality" { + // NOTE: GCC will sometimes change the personality function set on a function from + // rust_eh_personality to __gcc_personality_v0 as an optimization. + // As such, we need to create a weak alias from __gcc_personality_v0 to + // rust_eh_personality in order to avoid a linker error. + // This needs to be weak in order to still allow using the standard + // __gcc_personality_v0 when the linking to it. + // Since aliases don't work (maybe because of a bug in LTO partitioning?), we + // create a wrapper function that calls rust_eh_personality. + + let params: Vec<_> = param_types.into_iter().enumerate() + .map(|(index, param)| cx.context.new_parameter(None, *param, &format!("param{}", index))) // TODO(antoyo): set name. + .collect(); + let gcc_func = cx.context.new_function(None, FunctionType::Exported, return_type, ¶ms, "__gcc_personality_v0", variadic); + + // We need a normal extern function for the crates that access rust_eh_personality + // without defining it, otherwise we'll get a compiler error. + // + // For the crate defining it, that needs to be a weak alias instead. + gcc_func.add_attribute(FnAttribute::Weak); + + let block = gcc_func.new_block("start"); + let mut args = vec![]; + for param in ¶ms { + args.push(param.to_rvalue()); + } + let call = cx.context.new_call(None, func, &args); + if return_type == cx.type_void() { + block.add_eval(None, call); + block.end_with_void_return(None); + } + else { + block.end_with_return(None, call); + } + } + func }; diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs index 693367192b1..4bf3b71f503 100644 --- a/compiler/rustc_codegen_gcc/src/errors.rs +++ b/compiler/rustc_codegen_gcc/src/errors.rs @@ -1,8 +1,36 @@ -use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; -use rustc_macros::Diagnostic; +use rustc_errors::{ + DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, IntoDiagnosticArg, +}; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; use std::borrow::Cow; +use crate::fluent_generated as fluent; + +#[derive(Diagnostic)] +#[diag(codegen_gcc_unknown_ctarget_feature_prefix)] +#[note] +pub(crate) struct UnknownCTargetFeaturePrefix<'a> { + pub feature: &'a str, +} + +#[derive(Diagnostic)] +#[diag(codegen_gcc_unknown_ctarget_feature)] +#[note] +pub(crate) struct UnknownCTargetFeature<'a> { + pub feature: &'a str, + #[subdiagnostic] + pub rust_feature: PossibleFeature<'a>, +} + +#[derive(Subdiagnostic)] +pub(crate) enum PossibleFeature<'a> { + #[help(codegen_gcc_possible_feature)] + Some { rust_feature: &'a str }, + #[help(codegen_gcc_consider_filing_feature_request)] + None, +} + struct ExitCode(Option<i32>); impl IntoDiagnosticArg for ExitCode { @@ -40,3 +68,58 @@ pub(crate) struct TiedTargetFeatures { pub span: Span, pub features: String, } + +#[derive(Diagnostic)] +#[diag(codegen_gcc_copy_bitcode)] +pub(crate) struct CopyBitcode { + pub err: std::io::Error, +} + +#[derive(Diagnostic)] +#[diag(codegen_gcc_dynamic_linking_with_lto)] +#[note] +pub(crate) struct DynamicLinkingWithLTO; + +#[derive(Diagnostic)] +#[diag(codegen_gcc_load_bitcode)] +pub(crate) struct LoadBitcode { + name: String, +} + +#[derive(Diagnostic)] +#[diag(codegen_gcc_lto_disallowed)] +pub(crate) struct LtoDisallowed; + +#[derive(Diagnostic)] +#[diag(codegen_gcc_lto_dylib)] +pub(crate) struct LtoDylib; + +#[derive(Diagnostic)] +#[diag(codegen_gcc_lto_bitcode_from_rlib)] +pub(crate) struct LtoBitcodeFromRlib { + pub gcc_err: String, +} + +pub(crate) struct TargetFeatureDisableOrEnable<'a> { + pub features: &'a [&'a str], + pub span: Option<Span>, + pub missing_features: Option<MissingFeatures>, +} + +#[derive(Subdiagnostic)] +#[help(codegen_gcc_missing_features)] +pub(crate) struct MissingFeatures; + +impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> { + fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = sess.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable); + if let Some(span) = self.span { + diag.set_span(span); + }; + if let Some(missing_features) = self.missing_features { + diag.subdiagnostic(missing_features); + } + diag.set_arg("features", self.features.join(", ")); + diag + } +} diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs new file mode 100644 index 00000000000..0514c9988e0 --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs @@ -0,0 +1,223 @@ +#[cfg(feature="master")] +use gccjit::Context; +use smallvec::{smallvec, SmallVec}; + +use rustc_codegen_ssa::target_features::{ + supported_target_features, tied_target_features, RUSTC_SPECIFIC_FEATURES, +}; +use rustc_data_structures::fx::FxHashMap; +use rustc_middle::bug; +use rustc_session::Session; + +use crate::errors::{PossibleFeature, TargetFeatureDisableOrEnable, UnknownCTargetFeature, UnknownCTargetFeaturePrefix}; + +/// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, +/// `--target` and similar). +pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<String> { + // Features that come earlier are overridden by conflicting features later in the string. + // Typically we'll want more explicit settings to override the implicit ones, so: + // + // * Features from -Ctarget-cpu=*; are overridden by [^1] + // * Features implied by --target; are overridden by + // * Features from -Ctarget-feature; are overridden by + // * function specific features. + // + // [^1]: target-cpu=native is handled here, other target-cpu values are handled implicitly + // through GCC march implementation. + // + // FIXME(nagisa): it isn't clear what's the best interaction between features implied by + // `-Ctarget-cpu` and `--target` are. On one hand, you'd expect CLI arguments to always + // override anything that's implicit, so e.g. when there's no `--target` flag, features implied + // the host target are overridden by `-Ctarget-cpu=*`. On the other hand, what about when both + // `--target` and `-Ctarget-cpu=*` are specified? Both then imply some target features and both + // flags are specified by the user on the CLI. It isn't as clear-cut which order of precedence + // should be taken in cases like these. + let mut features = vec![]; + + // Features implied by an implicit or explicit `--target`. + features.extend( + sess.target + .features + .split(',') + .filter(|v| !v.is_empty() && backend_feature_name(v).is_some()) + .map(String::from), + ); + + // -Ctarget-features + let supported_features = supported_target_features(sess); + let mut featsmap = FxHashMap::default(); + let feats = sess.opts.cg.target_feature + .split(',') + .filter_map(|s| { + let enable_disable = match s.chars().next() { + None => return None, + Some(c @ ('+' | '-')) => c, + Some(_) => { + if diagnostics { + sess.emit_warning(UnknownCTargetFeaturePrefix { feature: s }); + } + return None; + } + }; + + let feature = backend_feature_name(s)?; + // Warn against use of GCC specific feature names on the CLI. + if diagnostics && !supported_features.iter().any(|&(v, _)| v == feature) { + let rust_feature = supported_features.iter().find_map(|&(rust_feature, _)| { + let gcc_features = to_gcc_features(sess, rust_feature); + if gcc_features.contains(&feature) && !gcc_features.contains(&rust_feature) { + Some(rust_feature) + } else { + None + } + }); + let unknown_feature = + if let Some(rust_feature) = rust_feature { + UnknownCTargetFeature { + feature, + rust_feature: PossibleFeature::Some { rust_feature }, + } + } + else { + UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None } + }; + sess.emit_warning(unknown_feature); + } + + if diagnostics { + // FIXME(nagisa): figure out how to not allocate a full hashset here. + featsmap.insert(feature, enable_disable == '+'); + } + + // rustc-specific features do not get passed down to GCC… + if RUSTC_SPECIFIC_FEATURES.contains(&feature) { + return None; + } + // ... otherwise though we run through `to_gcc_features` when + // passing requests down to GCC. This means that all in-language + // features also work on the command line instead of having two + // different names when the GCC name and the Rust name differ. + Some(to_gcc_features(sess, feature) + .iter() + .flat_map(|feat| to_gcc_features(sess, feat).into_iter()) + .map(|feature| { + if enable_disable == '-' { + format!("-{}", feature) + } + else { + feature.to_string() + } + }) + .collect::<Vec<_>>(), + ) + }) + .flatten(); + features.extend(feats); + + if diagnostics { + if let Some(f) = check_tied_features(sess, &featsmap) { + sess.emit_err(TargetFeatureDisableOrEnable { + features: f, + span: None, + missing_features: None, + }); + } + } + + features +} + +/// Returns a feature name for the given `+feature` or `-feature` string. +/// +/// Only allows features that are backend specific (i.e. not [`RUSTC_SPECIFIC_FEATURES`].) +fn backend_feature_name(s: &str) -> Option<&str> { + // features must start with a `+` or `-`. + let feature = s.strip_prefix(&['+', '-'][..]).unwrap_or_else(|| { + bug!("target feature `{}` must begin with a `+` or `-`", s); + }); + // Rustc-specific feature requests like `+crt-static` or `-crt-static` + // are not passed down to GCC. + if RUSTC_SPECIFIC_FEATURES.contains(&feature) { + return None; + } + Some(feature) +} + +// To find a list of GCC's names, check https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html +pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> { + let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch }; + match (arch, s) { + ("x86", "sse4.2") => smallvec!["sse4.2", "crc32"], + ("x86", "pclmulqdq") => smallvec!["pclmul"], + ("x86", "rdrand") => smallvec!["rdrnd"], + ("x86", "bmi1") => smallvec!["bmi"], + ("x86", "cmpxchg16b") => smallvec!["cx16"], + ("x86", "avx512vaes") => smallvec!["vaes"], + ("x86", "avx512gfni") => smallvec!["gfni"], + ("x86", "avx512vpclmulqdq") => smallvec!["vpclmulqdq"], + // NOTE: seems like GCC requires 'avx512bw' for 'avx512vbmi2'. + ("x86", "avx512vbmi2") => smallvec!["avx512vbmi2", "avx512bw"], + // NOTE: seems like GCC requires 'avx512bw' for 'avx512bitalg'. + ("x86", "avx512bitalg") => smallvec!["avx512bitalg", "avx512bw"], + ("aarch64", "rcpc2") => smallvec!["rcpc-immo"], + ("aarch64", "dpb") => smallvec!["ccpp"], + ("aarch64", "dpb2") => smallvec!["ccdp"], + ("aarch64", "frintts") => smallvec!["fptoint"], + ("aarch64", "fcma") => smallvec!["complxnum"], + ("aarch64", "pmuv3") => smallvec!["perfmon"], + ("aarch64", "paca") => smallvec!["pauth"], + ("aarch64", "pacg") => smallvec!["pauth"], + // Rust ties fp and neon together. In GCC neon implicitly enables fp, + // but we manually enable neon when a feature only implicitly enables fp + ("aarch64", "f32mm") => smallvec!["f32mm", "neon"], + ("aarch64", "f64mm") => smallvec!["f64mm", "neon"], + ("aarch64", "fhm") => smallvec!["fp16fml", "neon"], + ("aarch64", "fp16") => smallvec!["fullfp16", "neon"], + ("aarch64", "jsconv") => smallvec!["jsconv", "neon"], + ("aarch64", "sve") => smallvec!["sve", "neon"], + ("aarch64", "sve2") => smallvec!["sve2", "neon"], + ("aarch64", "sve2-aes") => smallvec!["sve2-aes", "neon"], + ("aarch64", "sve2-sm4") => smallvec!["sve2-sm4", "neon"], + ("aarch64", "sve2-sha3") => smallvec!["sve2-sha3", "neon"], + ("aarch64", "sve2-bitperm") => smallvec!["sve2-bitperm", "neon"], + (_, s) => smallvec![s], + } +} + +// Given a map from target_features to whether they are enabled or disabled, +// ensure only valid combinations are allowed. +pub fn check_tied_features(sess: &Session, features: &FxHashMap<&str, bool>) -> Option<&'static [&'static str]> { + for tied in tied_target_features(sess) { + // Tied features must be set to the same value, or not set at all + let mut tied_iter = tied.iter(); + let enabled = features.get(tied_iter.next().unwrap()); + if tied_iter.any(|feature| enabled != features.get(feature)) { + return Some(tied); + } + } + None +} + +fn handle_native(name: &str) -> &str { + if name != "native" { + return name; + } + + #[cfg(feature="master")] + { + // Get the native arch. + let context = Context::default(); + context.get_target_info().arch().unwrap() + .to_str() + .unwrap() + } + #[cfg(not(feature="master"))] + unimplemented!(); +} + +pub fn target_cpu(sess: &Session) -> &str { + match sess.opts.cg.target_cpu { + Some(ref name) => handle_native(name), + None => handle_native(sess.target.cpu.as_ref()), + } +} diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs index 0cf1204791d..58e0dd56f38 100644 --- a/compiler/rustc_codegen_gcc/src/int.rs +++ b/compiler/rustc_codegen_gcc/src/int.rs @@ -36,7 +36,6 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { self.cx.context.new_unary_op(None, operation, typ, a) } else { - // TODO(antoyo): use __negdi2 and __negti2 instead? let element_type = typ.dyncast_array().expect("element type"); let values = [ self.cx.context.new_unary_op(None, UnaryOp::BitwiseNegate, element_type, self.low(a)), @@ -52,9 +51,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { self.cx.context.new_unary_op(None, UnaryOp::Minus, a.get_type(), a) } else { - let param_a = self.context.new_parameter(None, a_type, "a"); - let func = self.context.new_function(None, FunctionType::Extern, a_type, &[param_a], "__negti2", false); - self.context.new_call(None, func, &[a]) + self.gcc_add(self.gcc_not(a), self.gcc_int(a_type, 1)) } } @@ -353,23 +350,63 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { (res.dereference(None).to_rvalue(), overflow) } - pub fn gcc_icmp(&self, op: IntPredicate, mut lhs: RValue<'gcc>, mut rhs: RValue<'gcc>) -> RValue<'gcc> { + pub fn gcc_icmp(&mut self, op: IntPredicate, mut lhs: RValue<'gcc>, mut rhs: RValue<'gcc>) -> RValue<'gcc> { let a_type = lhs.get_type(); let b_type = rhs.get_type(); if self.is_non_native_int_type(a_type) || self.is_non_native_int_type(b_type) { - let signed = a_type.is_compatible_with(self.i128_type); - let sign = - if signed { - "" - } - else { - "u" - }; - let func_name = format!("__{}cmpti2", sign); - let param_a = self.context.new_parameter(None, a_type, "a"); - let param_b = self.context.new_parameter(None, b_type, "b"); - let func = self.context.new_function(None, FunctionType::Extern, self.int_type, &[param_a, param_b], func_name, false); - let cmp = self.context.new_call(None, func, &[lhs, rhs]); + // This algorithm is based on compiler-rt's __cmpti2: + // https://github.com/llvm-mirror/compiler-rt/blob/f0745e8476f069296a7c71accedd061dce4cdf79/lib/builtins/cmpti2.c#L21 + let result = self.current_func().new_local(None, self.int_type, "icmp_result"); + let block1 = self.current_func().new_block("block1"); + let block2 = self.current_func().new_block("block2"); + let block3 = self.current_func().new_block("block3"); + let block4 = self.current_func().new_block("block4"); + let block5 = self.current_func().new_block("block5"); + let block6 = self.current_func().new_block("block6"); + let block7 = self.current_func().new_block("block7"); + let block8 = self.current_func().new_block("block8"); + let after = self.current_func().new_block("after"); + + let native_int_type = a_type.dyncast_array().expect("get element type"); + // NOTE: cast low to its unsigned type in order to perform a comparison correctly (e.g. + // the sign is only on high). + let unsigned_type = native_int_type.to_unsigned(&self.cx); + + let lhs_low = self.context.new_cast(None, self.low(lhs), unsigned_type); + let rhs_low = self.context.new_cast(None, self.low(rhs), unsigned_type); + + let condition = self.context.new_comparison(None, ComparisonOp::LessThan, self.high(lhs), self.high(rhs)); + self.llbb().end_with_conditional(None, condition, block1, block2); + + block1.add_assignment(None, result, self.context.new_rvalue_zero(self.int_type)); + block1.end_with_jump(None, after); + + let condition = self.context.new_comparison(None, ComparisonOp::GreaterThan, self.high(lhs), self.high(rhs)); + block2.end_with_conditional(None, condition, block3, block4); + + block3.add_assignment(None, result, self.context.new_rvalue_from_int(self.int_type, 2)); + block3.end_with_jump(None, after); + + let condition = self.context.new_comparison(None, ComparisonOp::LessThan, lhs_low, rhs_low); + block4.end_with_conditional(None, condition, block5, block6); + + block5.add_assignment(None, result, self.context.new_rvalue_zero(self.int_type)); + block5.end_with_jump(None, after); + + let condition = self.context.new_comparison(None, ComparisonOp::GreaterThan, lhs_low, rhs_low); + block6.end_with_conditional(None, condition, block7, block8); + + block7.add_assignment(None, result, self.context.new_rvalue_from_int(self.int_type, 2)); + block7.end_with_jump(None, after); + + block8.add_assignment(None, result, self.context.new_rvalue_one(self.int_type)); + block8.end_with_jump(None, after); + + // NOTE: since jumps were added in a place rustc does not expect, the current block in the + // state need to be updated. + self.switch_to_block(after); + + let cmp = result.to_rvalue(); let (op, limit) = match op { IntPredicate::IntEQ => { @@ -546,7 +583,12 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } pub fn gcc_uint(&self, typ: Type<'gcc>, int: u64) -> RValue<'gcc> { - if self.is_native_int_type_or_bool(typ) { + if typ.is_u128(self) { + // FIXME(antoyo): libgccjit cannot create 128-bit values yet. + let num = self.context.new_rvalue_from_long(self.u64_type, int as i64); + self.gcc_int_cast(num, typ) + } + else if self.is_native_int_type_or_bool(typ) { self.context.new_rvalue_from_long(typ, u64::try_from(int).expect("u64::try_from") as i64) } else { @@ -572,6 +614,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } } else if typ.is_i128(self) { + // FIXME(antoyo): libgccjit cannot create 128-bit values yet. let num = self.context.new_rvalue_from_long(self.u64_type, num as u64 as i64); self.gcc_int_cast(num, typ) } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs b/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs index 438eab78943..e01299d32fd 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs @@ -2254,6 +2254,42 @@ match name { "llvm.hexagon.prefetch" => "__builtin_HEXAGON_prefetch", "llvm.hexagon.vmemcpy" => "__builtin_hexagon_vmemcpy", "llvm.hexagon.vmemset" => "__builtin_hexagon_vmemset", + // loongarch + "llvm.loongarch.asrtgt.d" => "__builtin_loongarch_asrtgt_d", + "llvm.loongarch.asrtle.d" => "__builtin_loongarch_asrtle_d", + "llvm.loongarch.break" => "__builtin_loongarch_break", + "llvm.loongarch.cacop.d" => "__builtin_loongarch_cacop_d", + "llvm.loongarch.cacop.w" => "__builtin_loongarch_cacop_w", + "llvm.loongarch.cpucfg" => "__builtin_loongarch_cpucfg", + "llvm.loongarch.crc.w.b.w" => "__builtin_loongarch_crc_w_b_w", + "llvm.loongarch.crc.w.d.w" => "__builtin_loongarch_crc_w_d_w", + "llvm.loongarch.crc.w.h.w" => "__builtin_loongarch_crc_w_h_w", + "llvm.loongarch.crc.w.w.w" => "__builtin_loongarch_crc_w_w_w", + "llvm.loongarch.crcc.w.b.w" => "__builtin_loongarch_crcc_w_b_w", + "llvm.loongarch.crcc.w.d.w" => "__builtin_loongarch_crcc_w_d_w", + "llvm.loongarch.crcc.w.h.w" => "__builtin_loongarch_crcc_w_h_w", + "llvm.loongarch.crcc.w.w.w" => "__builtin_loongarch_crcc_w_w_w", + "llvm.loongarch.csrrd.d" => "__builtin_loongarch_csrrd_d", + "llvm.loongarch.csrrd.w" => "__builtin_loongarch_csrrd_w", + "llvm.loongarch.csrwr.d" => "__builtin_loongarch_csrwr_d", + "llvm.loongarch.csrwr.w" => "__builtin_loongarch_csrwr_w", + "llvm.loongarch.csrxchg.d" => "__builtin_loongarch_csrxchg_d", + "llvm.loongarch.csrxchg.w" => "__builtin_loongarch_csrxchg_w", + "llvm.loongarch.dbar" => "__builtin_loongarch_dbar", + "llvm.loongarch.ibar" => "__builtin_loongarch_ibar", + "llvm.loongarch.iocsrrd.b" => "__builtin_loongarch_iocsrrd_b", + "llvm.loongarch.iocsrrd.d" => "__builtin_loongarch_iocsrrd_d", + "llvm.loongarch.iocsrrd.h" => "__builtin_loongarch_iocsrrd_h", + "llvm.loongarch.iocsrrd.w" => "__builtin_loongarch_iocsrrd_w", + "llvm.loongarch.iocsrwr.b" => "__builtin_loongarch_iocsrwr_b", + "llvm.loongarch.iocsrwr.d" => "__builtin_loongarch_iocsrwr_d", + "llvm.loongarch.iocsrwr.h" => "__builtin_loongarch_iocsrwr_h", + "llvm.loongarch.iocsrwr.w" => "__builtin_loongarch_iocsrwr_w", + "llvm.loongarch.lddir.d" => "__builtin_loongarch_lddir_d", + "llvm.loongarch.ldpte.d" => "__builtin_loongarch_ldpte_d", + "llvm.loongarch.movfcsr2gr" => "__builtin_loongarch_movfcsr2gr", + "llvm.loongarch.movgr2fcsr" => "__builtin_loongarch_movgr2fcsr", + "llvm.loongarch.syscall" => "__builtin_loongarch_syscall", // mips "llvm.mips.absq.s.ph" => "__builtin_mips_absq_s_ph", "llvm.mips.absq.s.qb" => "__builtin_mips_absq_s_qb", @@ -2954,6 +2990,8 @@ match name { "llvm.nvvm.barrier0.and" => "__nvvm_bar0_and", "llvm.nvvm.barrier0.or" => "__nvvm_bar0_or", "llvm.nvvm.barrier0.popc" => "__nvvm_bar0_popc", + "llvm.nvvm.bf2h.rn" => "__nvvm_bf2h_rn", + "llvm.nvvm.bf2h.rn.ftz" => "__nvvm_bf2h_rn_ftz", "llvm.nvvm.bitcast.d2ll" => "__nvvm_bitcast_d2ll", "llvm.nvvm.bitcast.f2i" => "__nvvm_bitcast_f2i", "llvm.nvvm.bitcast.i2f" => "__nvvm_bitcast_i2f", @@ -3016,8 +3054,6 @@ match name { "llvm.nvvm.div.rz.ftz.f" => "__nvvm_div_rz_ftz_f", "llvm.nvvm.ex2.approx.d" => "__nvvm_ex2_approx_d", "llvm.nvvm.ex2.approx.f" => "__nvvm_ex2_approx_f", - "llvm.nvvm.ex2.approx.f16" => "__nvvm_ex2_approx_f16", - "llvm.nvvm.ex2.approx.f16x2" => "__nvvm_ex2_approx_f16x2", "llvm.nvvm.ex2.approx.ftz.f" => "__nvvm_ex2_approx_ftz_f", "llvm.nvvm.f2bf16.rn" => "__nvvm_f2bf16_rn", "llvm.nvvm.f2bf16.rn.relu" => "__nvvm_f2bf16_rn_relu", @@ -3079,11 +3115,17 @@ match name { "llvm.nvvm.fma.rn.bf16x2" => "__nvvm_fma_rn_bf16x2", "llvm.nvvm.fma.rn.d" => "__nvvm_fma_rn_d", "llvm.nvvm.fma.rn.f" => "__nvvm_fma_rn_f", - "llvm.nvvm.fma.rn.f16" => "__nvvm_fma_rn_f16", - "llvm.nvvm.fma.rn.f16x2" => "__nvvm_fma_rn_f16x2", + "llvm.nvvm.fma.rn.ftz.bf16" => "__nvvm_fma_rn_ftz_bf16", + "llvm.nvvm.fma.rn.ftz.bf16x2" => "__nvvm_fma_rn_ftz_bf16x2", "llvm.nvvm.fma.rn.ftz.f" => "__nvvm_fma_rn_ftz_f", + "llvm.nvvm.fma.rn.ftz.relu.bf16" => "__nvvm_fma_rn_ftz_relu_bf16", + "llvm.nvvm.fma.rn.ftz.relu.bf16x2" => "__nvvm_fma_rn_ftz_relu_bf16x2", + "llvm.nvvm.fma.rn.ftz.sat.bf16" => "__nvvm_fma_rn_ftz_sat_bf16", + "llvm.nvvm.fma.rn.ftz.sat.bf16x2" => "__nvvm_fma_rn_ftz_sat_bf16x2", "llvm.nvvm.fma.rn.relu.bf16" => "__nvvm_fma_rn_relu_bf16", "llvm.nvvm.fma.rn.relu.bf16x2" => "__nvvm_fma_rn_relu_bf16x2", + "llvm.nvvm.fma.rn.sat.bf16" => "__nvvm_fma_rn_sat_bf16", + "llvm.nvvm.fma.rn.sat.bf16x2" => "__nvvm_fma_rn_sat_bf16x2", "llvm.nvvm.fma.rp.d" => "__nvvm_fma_rp_d", "llvm.nvvm.fma.rp.f" => "__nvvm_fma_rp_f", "llvm.nvvm.fma.rp.ftz.f" => "__nvvm_fma_rp_ftz_f", @@ -3094,11 +3136,17 @@ match name { "llvm.nvvm.fmax.bf16x2" => "__nvvm_fmax_bf16x2", "llvm.nvvm.fmax.d" => "__nvvm_fmax_d", "llvm.nvvm.fmax.f" => "__nvvm_fmax_f", - "llvm.nvvm.fmax.f16" => "__nvvm_fmax_f16", - "llvm.nvvm.fmax.f16x2" => "__nvvm_fmax_f16x2", + "llvm.nvvm.fmax.ftz.bf16" => "__nvvm_fmax_ftz_bf16", + "llvm.nvvm.fmax.ftz.bf16x2" => "__nvvm_fmax_ftz_bf16x2", "llvm.nvvm.fmax.ftz.f" => "__nvvm_fmax_ftz_f", + "llvm.nvvm.fmax.ftz.nan.bf16" => "__nvvm_fmax_ftz_nan_bf16", + "llvm.nvvm.fmax.ftz.nan.bf16x2" => "__nvvm_fmax_ftz_nan_bf16x2", "llvm.nvvm.fmax.ftz.nan.f" => "__nvvm_fmax_ftz_nan_f", + "llvm.nvvm.fmax.ftz.nan.xorsign.abs.bf16" => "__nvvm_fmax_ftz_nan_xorsign_abs_bf16", + "llvm.nvvm.fmax.ftz.nan.xorsign.abs.bf16x2" => "__nvvm_fmax_ftz_nan_xorsign_abs_bf16x2", "llvm.nvvm.fmax.ftz.nan.xorsign.abs.f" => "__nvvm_fmax_ftz_nan_xorsign_abs_f", + "llvm.nvvm.fmax.ftz.xorsign.abs.bf16" => "__nvvm_fmax_ftz_xorsign_abs_bf16", + "llvm.nvvm.fmax.ftz.xorsign.abs.bf16x2" => "__nvvm_fmax_ftz_xorsign_abs_bf16x2", "llvm.nvvm.fmax.ftz.xorsign.abs.f" => "__nvvm_fmax_ftz_xorsign_abs_f", "llvm.nvvm.fmax.nan.bf16" => "__nvvm_fmax_nan_bf16", "llvm.nvvm.fmax.nan.bf16x2" => "__nvvm_fmax_nan_bf16x2", @@ -3113,11 +3161,17 @@ match name { "llvm.nvvm.fmin.bf16x2" => "__nvvm_fmin_bf16x2", "llvm.nvvm.fmin.d" => "__nvvm_fmin_d", "llvm.nvvm.fmin.f" => "__nvvm_fmin_f", - "llvm.nvvm.fmin.f16" => "__nvvm_fmin_f16", - "llvm.nvvm.fmin.f16x2" => "__nvvm_fmin_f16x2", + "llvm.nvvm.fmin.ftz.bf16" => "__nvvm_fmin_ftz_bf16", + "llvm.nvvm.fmin.ftz.bf16x2" => "__nvvm_fmin_ftz_bf16x2", "llvm.nvvm.fmin.ftz.f" => "__nvvm_fmin_ftz_f", + "llvm.nvvm.fmin.ftz.nan.bf16" => "__nvvm_fmin_ftz_nan_bf16", + "llvm.nvvm.fmin.ftz.nan.bf16x2" => "__nvvm_fmin_ftz_nan_bf16x2", "llvm.nvvm.fmin.ftz.nan.f" => "__nvvm_fmin_ftz_nan_f", + "llvm.nvvm.fmin.ftz.nan.xorsign.abs.bf16" => "__nvvm_fmin_ftz_nan_xorsign_abs_bf16", + "llvm.nvvm.fmin.ftz.nan.xorsign.abs.bf16x2" => "__nvvm_fmin_ftz_nan_xorsign_abs_bf16x2", "llvm.nvvm.fmin.ftz.nan.xorsign.abs.f" => "__nvvm_fmin_ftz_nan_xorsign_abs_f", + "llvm.nvvm.fmin.ftz.xorsign.abs.bf16" => "__nvvm_fmin_ftz_xorsign_abs_bf16", + "llvm.nvvm.fmin.ftz.xorsign.abs.bf16x2" => "__nvvm_fmin_ftz_xorsign_abs_bf16x2", "llvm.nvvm.fmin.ftz.xorsign.abs.f" => "__nvvm_fmin_ftz_xorsign_abs_f", "llvm.nvvm.fmin.nan.bf16" => "__nvvm_fmin_nan_bf16", "llvm.nvvm.fmin.nan.bf16x2" => "__nvvm_fmin_nan_bf16x2", @@ -4213,6 +4267,28 @@ match name { "llvm.r600.read.tgid.x" => "__builtin_r600_read_tgid_x", "llvm.r600.read.tgid.y" => "__builtin_r600_read_tgid_y", "llvm.r600.read.tgid.z" => "__builtin_r600_read_tgid_z", + // riscv + "llvm.riscv.aes32dsi" => "__builtin_riscv_aes32dsi", + "llvm.riscv.aes32dsmi" => "__builtin_riscv_aes32dsmi", + "llvm.riscv.aes32esi" => "__builtin_riscv_aes32esi", + "llvm.riscv.aes32esmi" => "__builtin_riscv_aes32esmi", + "llvm.riscv.aes64ds" => "__builtin_riscv_aes64ds", + "llvm.riscv.aes64dsm" => "__builtin_riscv_aes64dsm", + "llvm.riscv.aes64es" => "__builtin_riscv_aes64es", + "llvm.riscv.aes64esm" => "__builtin_riscv_aes64esm", + "llvm.riscv.aes64im" => "__builtin_riscv_aes64im", + "llvm.riscv.aes64ks1i" => "__builtin_riscv_aes64ks1i", + "llvm.riscv.aes64ks2" => "__builtin_riscv_aes64ks2", + "llvm.riscv.sha512sig0" => "__builtin_riscv_sha512sig0", + "llvm.riscv.sha512sig0h" => "__builtin_riscv_sha512sig0h", + "llvm.riscv.sha512sig0l" => "__builtin_riscv_sha512sig0l", + "llvm.riscv.sha512sig1" => "__builtin_riscv_sha512sig1", + "llvm.riscv.sha512sig1h" => "__builtin_riscv_sha512sig1h", + "llvm.riscv.sha512sig1l" => "__builtin_riscv_sha512sig1l", + "llvm.riscv.sha512sum0" => "__builtin_riscv_sha512sum0", + "llvm.riscv.sha512sum0r" => "__builtin_riscv_sha512sum0r", + "llvm.riscv.sha512sum1" => "__builtin_riscv_sha512sum1", + "llvm.riscv.sha512sum1r" => "__builtin_riscv_sha512sum1r", // s390 "llvm.s390.efpc" => "__builtin_s390_efpc", "llvm.s390.etnd" => "__builtin_tx_nesting_depth", @@ -5912,6 +5988,18 @@ match name { "llvm.x86.avx2.vpdpbuud.256" => "__builtin_ia32_vpdpbuud256", "llvm.x86.avx2.vpdpbuuds.128" => "__builtin_ia32_vpdpbuuds128", "llvm.x86.avx2.vpdpbuuds.256" => "__builtin_ia32_vpdpbuuds256", + "llvm.x86.avx2.vpdpwsud.128" => "__builtin_ia32_vpdpwsud128", + "llvm.x86.avx2.vpdpwsud.256" => "__builtin_ia32_vpdpwsud256", + "llvm.x86.avx2.vpdpwsuds.128" => "__builtin_ia32_vpdpwsuds128", + "llvm.x86.avx2.vpdpwsuds.256" => "__builtin_ia32_vpdpwsuds256", + "llvm.x86.avx2.vpdpwusd.128" => "__builtin_ia32_vpdpwusd128", + "llvm.x86.avx2.vpdpwusd.256" => "__builtin_ia32_vpdpwusd256", + "llvm.x86.avx2.vpdpwusds.128" => "__builtin_ia32_vpdpwusds128", + "llvm.x86.avx2.vpdpwusds.256" => "__builtin_ia32_vpdpwusds256", + "llvm.x86.avx2.vpdpwuud.128" => "__builtin_ia32_vpdpwuud128", + "llvm.x86.avx2.vpdpwuud.256" => "__builtin_ia32_vpdpwuud256", + "llvm.x86.avx2.vpdpwuuds.128" => "__builtin_ia32_vpdpwuuds128", + "llvm.x86.avx2.vpdpwuuds.256" => "__builtin_ia32_vpdpwuuds256", "llvm.x86.avx2.vperm2i128" => "__builtin_ia32_permti256", "llvm.x86.avx512.add.pd.512" => "__builtin_ia32_addpd512", "llvm.x86.avx512.add.ps.512" => "__builtin_ia32_addps512", @@ -7909,6 +7997,16 @@ match name { "llvm.x86.vgf2p8mulb.128" => "__builtin_ia32_vgf2p8mulb_v16qi", "llvm.x86.vgf2p8mulb.256" => "__builtin_ia32_vgf2p8mulb_v32qi", "llvm.x86.vgf2p8mulb.512" => "__builtin_ia32_vgf2p8mulb_v64qi", + "llvm.x86.vsha512msg1" => "__builtin_ia32_vsha512msg1", + "llvm.x86.vsha512msg2" => "__builtin_ia32_vsha512msg2", + "llvm.x86.vsha512rnds2" => "__builtin_ia32_vsha512rnds2", + "llvm.x86.vsm3msg1" => "__builtin_ia32_vsm3msg1", + "llvm.x86.vsm3msg2" => "__builtin_ia32_vsm3msg2", + "llvm.x86.vsm3rnds2" => "__builtin_ia32_vsm3rnds2", + "llvm.x86.vsm4key4128" => "__builtin_ia32_vsm4key4128", + "llvm.x86.vsm4key4256" => "__builtin_ia32_vsm4key4256", + "llvm.x86.vsm4rnds4128" => "__builtin_ia32_vsm4rnds4128", + "llvm.x86.vsm4rnds4256" => "__builtin_ia32_vsm4rnds4256", "llvm.x86.wbinvd" => "__builtin_ia32_wbinvd", "llvm.x86.wbnoinvd" => "__builtin_ia32_wbnoinvd", "llvm.x86.wrfsbase.32" => "__builtin_ia32_wrfsbase32", diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs index f28348380d7..5996623bdc5 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs @@ -236,11 +236,17 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc let arg2 = builder.context.new_cast(None, arg2, arg2_type); args = vec![new_args[0], arg2].into(); }, + // These builtins are sent one more argument than needed. "__builtin_prefetch" => { let mut new_args = args.to_vec(); new_args.pop(); args = new_args.into(); }, + // The GCC version returns one value of the tuple through a pointer. + "__builtin_ia32_rdrand64_step" => { + let arg = builder.current_func().new_local(None, builder.ulonglong_type, "return_rdrand_arg"); + args = vec![arg.get_address(None)].into(); + }, _ => (), } } @@ -361,6 +367,19 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(builder: &Builder<'a, 'gcc, // builtin twice, we overwrite the return value with a dummy value. return_value = builder.context.new_rvalue_zero(builder.int_type); }, + "__builtin_ia32_rdrand64_step" => { + let random_number = args[0].dereference(None).to_rvalue(); + let success_variable = builder.current_func().new_local(None, return_value.get_type(), "success"); + builder.llbb().add_assignment(None, success_variable, return_value); + + let field1 = builder.context.new_field(None, random_number.get_type(), "random_number"); + let field2 = builder.context.new_field(None, return_value.get_type(), "success"); + let struct_type = builder.context.new_struct_type(None, "rdrand_result", &[field1, field2]); + return_value = builder.context.new_struct_constructor(None, struct_type.as_type(), None, &[ + random_number, + success_variable.to_rvalue(), + ]); + }, _ => (), } @@ -613,6 +632,7 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.fshr.v8i16" => "__builtin_ia32_vpshrdv_v8hi", "llvm.x86.fma.vfmadd.sd" => "__builtin_ia32_vfmaddsd3", "llvm.x86.fma.vfmadd.ss" => "__builtin_ia32_vfmaddss3", + "llvm.x86.rdrand.64" => "__builtin_ia32_rdrand64_step", // The above doc points to unknown builtins for the following, so override them: "llvm.x86.avx2.gather.d.d" => "__builtin_ia32_gathersiv4si", diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 68a087a1d7f..9caed459a29 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -10,9 +10,9 @@ use rustc_codegen_ssa::base::wants_msvc_seh; use rustc_codegen_ssa::common::IntPredicate; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; -use rustc_codegen_ssa::traits::{ArgAbiMethods, BaseTypeMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods}; +use rustc_codegen_ssa::traits::{ArgAbiMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods}; #[cfg(feature="master")] -use rustc_codegen_ssa::traits::MiscMethods; +use rustc_codegen_ssa::traits::{BaseTypeMethods, MiscMethods}; use rustc_codegen_ssa::errors::InvalidMonomorphization; use rustc_middle::bug; use rustc_middle::ty::{self, Instance, Ty}; diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index ce7e31682f1..6aa5b6bd1ff 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -2,10 +2,18 @@ * TODO(antoyo): implement equality in libgccjit based on https://zpz.github.io/blog/overloading-equality-operator-in-cpp-class-hierarchy/ (for type equality?) * TODO(antoyo): support #[inline] attributes. * TODO(antoyo): support LTO (gcc's equivalent to Full LTO is -flto -flto-partition=one — https://documentation.suse.com/sbp/all/html/SBP-GCC-10/index.html). + * For Thin LTO, this might be helpful: + * In gcc 4.6 -fwhopr was removed and became default with -flto. The non-whopr path can still be executed via -flto-partition=none. + * + * Maybe some missing optizations enabled by rustc's LTO is in there: https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html + * Like -fipa-icf (should be already enabled) and maybe -fdevirtualize-at-ltrans. + * TODO: disable debug info always being emitted. Perhaps this slows down things? * * TODO(antoyo): remove the patches. */ +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![feature( rustc_private, decl_macro, @@ -28,6 +36,7 @@ extern crate rustc_codegen_ssa; extern crate rustc_data_structures; extern crate rustc_errors; extern crate rustc_fluent_macro; +extern crate rustc_fs_util; extern crate rustc_hir; extern crate rustc_macros; extern crate rustc_metadata; @@ -35,7 +44,8 @@ extern crate rustc_middle; extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; -extern crate tempfile; +#[macro_use] +extern crate tracing; // This prevents duplicating functions and statics that are already part of the host rustc process. #[allow(unused_extern_crates)] @@ -57,6 +67,7 @@ mod coverageinfo; mod debuginfo; mod declare; mod errors; +mod gcc_util; mod int; mod intrinsic; mod mono_item; @@ -64,18 +75,29 @@ mod type_; mod type_of; use std::any::Any; -use std::sync::{Arc, Mutex}; - -use crate::errors::LTONotSupported; -use gccjit::{Context, OptimizationLevel, CType}; +use std::fmt::Debug; +use std::sync::Arc; +use std::sync::Mutex; +#[cfg(not(feature="master"))] +use std::sync::atomic::AtomicBool; +#[cfg(not(feature="master"))] +use std::sync::atomic::Ordering; + +use gccjit::{Context, OptimizationLevel}; +#[cfg(feature="master")] +use gccjit::TargetInfo; +#[cfg(not(feature="master"))] +use gccjit::CType; +use errors::LTONotSupported; use rustc_ast::expand::allocator::AllocatorKind; use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen}; use rustc_codegen_ssa::base::codegen_crate; use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn}; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; use rustc_codegen_ssa::target_features::supported_target_features; -use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods}; use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::sync::IntoDynSyncSend; +use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ThinBufferMethods, WriteBackendMethods}; use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, Handler, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_metadata::EncodedMetadata; @@ -88,6 +110,9 @@ use rustc_span::Symbol; use rustc_span::fatal_error::FatalError; use tempfile::TempDir; +use crate::back::lto::ModuleBuffer; +use crate::gcc_util::target_cpu; + fluent_messages! { "../messages.ftl" } pub struct PrintOnPanic<F: Fn() -> String>(pub F); @@ -100,9 +125,47 @@ impl<F: Fn() -> String> Drop for PrintOnPanic<F> { } } +#[cfg(not(feature="master"))] +#[derive(Debug)] +pub struct TargetInfo { + supports_128bit_integers: AtomicBool, +} + +#[cfg(not(feature="master"))] +impl TargetInfo { + fn cpu_supports(&self, _feature: &str) -> bool { + false + } + + fn supports_128bit_int(&self) -> bool { + self.supports_128bit_integers.load(Ordering::SeqCst) + } +} + +#[derive(Clone)] +pub struct LockedTargetInfo { + info: Arc<Mutex<IntoDynSyncSend<TargetInfo>>>, +} + +impl Debug for LockedTargetInfo { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.info.lock().expect("lock").fmt(formatter) + } +} + +impl LockedTargetInfo { + fn cpu_supports(&self, feature: &str) -> bool { + self.info.lock().expect("lock").cpu_supports(feature) + } + + fn supports_128bit_int(&self) -> bool { + self.info.lock().expect("lock").supports_128bit_int() + } +} + #[derive(Clone)] pub struct GccCodegenBackend { - supports_128bit_integers: Arc<Mutex<bool>>, + target_info: LockedTargetInfo, } impl CodegenBackend for GccCodegenBackend { @@ -112,24 +175,40 @@ impl CodegenBackend for GccCodegenBackend { fn init(&self, sess: &Session) { #[cfg(feature="master")] + { + let target_cpu = target_cpu(sess); + + // Get the second TargetInfo with the correct CPU features by setting the arch. + let context = Context::default(); + if target_cpu != "generic" { + context.add_command_line_option(&format!("-march={}", target_cpu)); + } + + **self.target_info.info.lock().expect("lock") = context.get_target_info(); + } + + #[cfg(feature="master")] gccjit::set_global_personality_function_name(b"rust_eh_personality\0"); - if sess.lto() != Lto::No { + if sess.lto() == Lto::Thin { sess.emit_warning(LTONotSupported {}); } - let temp_dir = TempDir::new().expect("cannot create temporary directory"); - let temp_file = temp_dir.into_path().join("result.asm"); - let check_context = Context::default(); - check_context.set_print_errors_to_stderr(false); - let _int128_ty = check_context.new_c_type(CType::UInt128t); - // NOTE: we cannot just call compile() as this would require other files than libgccjit.so. - check_context.compile_to_file(gccjit::OutputKind::Assembler, temp_file.to_str().expect("path to str")); - *self.supports_128bit_integers.lock().expect("lock") = check_context.get_last_error() == Ok(None); + #[cfg(not(feature="master"))] + { + let temp_dir = TempDir::new().expect("cannot create temporary directory"); + let temp_file = temp_dir.into_path().join("result.asm"); + let check_context = Context::default(); + check_context.set_print_errors_to_stderr(false); + let _int128_ty = check_context.new_c_type(CType::UInt128t); + // NOTE: we cannot just call compile() as this would require other files than libgccjit.so. + check_context.compile_to_file(gccjit::OutputKind::Assembler, temp_file.to_str().expect("path to str")); + self.target_info.info.lock().expect("lock").supports_128bit_integers.store(check_context.get_last_error() == Ok(None), Ordering::SeqCst); + } } fn provide(&self, providers: &mut Providers) { - // FIXME(antoyo) compute list of enabled features from cli flags - providers.global_backend_features = |_tcx, ()| vec![]; + providers.global_backend_features = + |tcx, ()| gcc_util::global_gcc_features(tcx.sess, true) } fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>, metadata: EncodedMetadata, need_metadata_module: bool) -> Box<dyn Any> { @@ -160,7 +239,7 @@ impl CodegenBackend for GccCodegenBackend { } fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> { - target_features(sess, allow_unstable) + target_features(sess, allow_unstable, &self.target_info) } } @@ -168,13 +247,18 @@ impl ExtraBackendMethods for GccCodegenBackend { fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) -> Self::Module { let mut mods = GccContext { context: Context::default(), + should_combine_object_files: false, + temp_dir: None, }; + + // TODO(antoyo): only set for x86. + mods.context.add_command_line_option("-masm=intel"); unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); } mods } fn compile_codegen_unit(&self, tcx: TyCtxt<'_>, cgu_name: Symbol) -> (ModuleCodegen<Self::Module>, u64) { - base::compile_codegen_unit(tcx, cgu_name, *self.supports_128bit_integers.lock().expect("lock")) + base::compile_codegen_unit(tcx, cgu_name, self.target_info.clone()) } fn target_machine_factory(&self, _sess: &Session, _opt_level: OptLevel, _features: &[String]) -> TargetMachineFactoryFn<Self> { @@ -185,14 +269,6 @@ impl ExtraBackendMethods for GccCodegenBackend { } } -pub struct ModuleBuffer; - -impl ModuleBufferMethods for ModuleBuffer { - fn data(&self) -> &[u8] { - unimplemented!(); - } -} - pub struct ThinBuffer; impl ThinBufferMethods for ThinBuffer { @@ -203,6 +279,9 @@ impl ThinBufferMethods for ThinBuffer { pub struct GccContext { context: Context<'static>, + should_combine_object_files: bool, + // Temporary directory used by LTO. We keep it here so that it's not removed before linking. + temp_dir: Option<TempDir>, } unsafe impl Send for GccContext {} @@ -217,18 +296,8 @@ impl WriteBackendMethods for GccCodegenBackend { type ThinData = (); type ThinBuffer = ThinBuffer; - fn run_fat_lto(_cgcx: &CodegenContext<Self>, mut modules: Vec<FatLtoInput<Self>>, _cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<LtoModuleCodegen<Self>, FatalError> { - // TODO(antoyo): implement LTO by sending -flto to libgccjit and adding the appropriate gcc linker plugins. - // NOTE: implemented elsewhere. - // TODO(antoyo): what is implemented elsewhere ^ ? - let module = - match modules.remove(0) { - FatLtoInput::InMemory(module) => module, - FatLtoInput::Serialized { .. } => { - unimplemented!(); - } - }; - Ok(LtoModuleCodegen::Fat { module, _serialized_bitcode: vec![] }) + fn run_fat_lto(cgcx: &CodegenContext<Self>, modules: Vec<FatLtoInput<Self>>, cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<LtoModuleCodegen<Self>, FatalError> { + back::lto::run_fat(cgcx, modules, cached_modules) } fn run_thin_lto(_cgcx: &CodegenContext<Self>, _modules: Vec<(String, Self::ThinBuffer)>, _cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> { @@ -277,8 +346,19 @@ impl WriteBackendMethods for GccCodegenBackend { /// This is the entrypoint for a hot plugged rustc_codegen_gccjit #[no_mangle] pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> { + #[cfg(feature="master")] + let info = { + // Check whether the target supports 128-bit integers. + let context = Context::default(); + Arc::new(Mutex::new(IntoDynSyncSend(context.get_target_info()))) + }; + #[cfg(not(feature="master"))] + let info = Arc::new(Mutex::new(IntoDynSyncSend(TargetInfo { + supports_128bit_integers: AtomicBool::new(false), + }))); + Box::new(GccCodegenBackend { - supports_128bit_integers: Arc::new(Mutex::new(false)), + target_info: LockedTargetInfo { info }, }) } @@ -297,22 +377,7 @@ fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel { } } -fn handle_native(name: &str) -> &str { - if name != "native" { - return name; - } - - unimplemented!(); -} - -pub fn target_cpu(sess: &Session) -> &str { - match sess.opts.cg.target_cpu { - Some(ref name) => handle_native(name), - None => handle_native(sess.target.cpu.as_ref()), - } -} - -pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> { +pub fn target_features(sess: &Session, allow_unstable: bool, target_info: &LockedTargetInfo) -> Vec<Symbol> { supported_target_features(sess) .iter() .filter_map( @@ -321,26 +386,13 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> { }, ) .filter(|_feature| { - // TODO(antoyo): implement a way to get enabled feature in libgccjit. - // Probably using the equivalent of __builtin_cpu_supports. - // TODO(antoyo): maybe use whatever outputs the following command: - // gcc -march=native -Q --help=target - #[cfg(feature="master")] - { - // NOTE: the CPU in the CI doesn't support sse4a, so disable it to make the stdarch tests pass in the CI. - (_feature.contains("sse") || _feature.contains("avx")) && !_feature.contains("avx512") && !_feature.contains("sse4a") - } - #[cfg(not(feature="master"))] - { - false - } + target_info.cpu_supports(_feature) /* adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512ifma, avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq, bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm, sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves */ - //false }) .map(|feature| Symbol::intern(feature)) .collect() diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index cc467801beb..c2eab295acd 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -182,6 +182,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { /// of that field's type - this is useful for taking the address of /// that field and ensuring the struct has the right alignment. fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { + use crate::rustc_middle::ty::layout::FnAbiOf; // This must produce the same result for `repr(transparent)` wrappers as for the inner type! // In other words, this should generally not look at the type at all, but only at the // layout. @@ -191,7 +192,14 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) { return ty; } - let ty = self.scalar_gcc_type_at(cx, scalar, Size::ZERO); + let ty = + match *self.ty.kind() { + // NOTE: we cannot remove this match like in the LLVM codegen because the call + // to fn_ptr_backend_type handle the on-stack attribute. + // TODO(antoyo): find a less hackish way to hande the on-stack attribute. + ty::FnPtr(sig) => cx.fn_ptr_backend_type(&cx.fn_abi_of_fn_ptr(sig, ty::List::empty())), + _ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO), + }; cx.scalar_types.borrow_mut().insert(self.ty, ty); return ty; } diff --git a/compiler/rustc_codegen_gcc/test.sh b/compiler/rustc_codegen_gcc/test.sh index b462e5d156b..e4cbd6fbcaf 100755 --- a/compiler/rustc_codegen_gcc/test.sh +++ b/compiler/rustc_codegen_gcc/test.sh @@ -3,6 +3,7 @@ # TODO(antoyo): rewrite to cargo-make (or just) or something like that to only rebuild the sysroot when needed? set -e +#set -x if [ -f ./gcc_path ]; then export GCC_PATH=$(cat gcc_path) @@ -219,6 +220,7 @@ change-id = 115898 [rust] codegen-backends = [] deny-warnings = false +verbose-tests = true [build] cargo = "$(rustup which cargo)" @@ -345,15 +347,19 @@ function test_rustc() { git checkout -- tests/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed - rm -r tests/ui/{abi*,extern/,unsized-locals/,proc-macro/,threads-sendsync/,thinlto/,borrowck/,chalkify/bugs/,test*,*lto*.rs,consts/const-float-bits-reject-conv.rs,consts/issue-miri-1910.rs} || true - rm tests/ui/mir/mir_heavy_promoted.rs # this tests is oom-killed in the CI. - for test in $(rg --files-with-matches "thread|lto" tests/ui); do + rm -r tests/ui/{abi*,extern/,unsized-locals/,proc-macro/,threads-sendsync/,thinlto/,borrowck/,chalkify/bugs/,test*,consts/const-float-bits-reject-conv.rs,consts/issue-miri-1910.rs} || true + rm tests/ui/mir/mir_heavy_promoted.rs # this test is oom-killed in the CI. + # Tests generating errors. + rm tests/ui/consts/const-eval/nonnull_as_ref_ub.rs tests/ui/consts/issue-94675.rs + for test in $(rg --files-with-matches "thread" tests/ui); do rm $test done - git checkout tests/ui/lto/auxiliary/dylib.rs git checkout tests/ui/type-alias-impl-trait/auxiliary/cross_crate_ice.rs git checkout tests/ui/type-alias-impl-trait/auxiliary/cross_crate_ice2.rs git checkout tests/ui/macros/rfc-2011-nicer-assert-messages/auxiliary/common.rs + git checkout tests/ui/imports/ambiguous-1.rs + git checkout tests/ui/imports/ambiguous-4-extern.rs + git checkout tests/ui/entry-point/auxiliary/bad_main_functions.rs RUSTC_ARGS="$TEST_FLAGS -Csymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot "$(pwd)"/../build_sysroot/sysroot" diff --git a/compiler/rustc_codegen_gcc/tests/run/abort1.rs b/compiler/rustc_codegen_gcc/tests/run/abort1.rs index 25041d93e74..44297e12779 100644 --- a/compiler/rustc_codegen_gcc/tests/run/abort1.rs +++ b/compiler/rustc_codegen_gcc/tests/run/abort1.rs @@ -3,7 +3,8 @@ // Run-time: // status: signal -#![feature(auto_traits, lang_items, no_core, start, intrinsics)] +#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)] +#![allow(internal_features)] #![no_std] #![no_core] diff --git a/compiler/rustc_codegen_gcc/tests/run/abort2.rs b/compiler/rustc_codegen_gcc/tests/run/abort2.rs index e7443c8dbe5..ce816927123 100644 --- a/compiler/rustc_codegen_gcc/tests/run/abort2.rs +++ b/compiler/rustc_codegen_gcc/tests/run/abort2.rs @@ -3,7 +3,8 @@ // Run-time: // status: signal -#![feature(auto_traits, lang_items, no_core, start, intrinsics)] +#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)] +#![allow(internal_features)] #![no_std] #![no_core] diff --git a/compiler/rustc_codegen_gcc/tests/run/array.rs b/compiler/rustc_codegen_gcc/tests/run/array.rs index 49b28d98f2f..afd0eed8200 100644 --- a/compiler/rustc_codegen_gcc/tests/run/array.rs +++ b/compiler/rustc_codegen_gcc/tests/run/array.rs @@ -7,7 +7,8 @@ // 5 // 10 -#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)] +#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)] +#![allow(internal_features)] #![no_std] #![no_core] diff --git a/compiler/rustc_codegen_gcc/tests/run/asm.rs b/compiler/rustc_codegen_gcc/tests/run/asm.rs index 38c1eac7adf..507b65ca049 100644 --- a/compiler/rustc_codegen_gcc/tests/run/asm.rs +++ b/compiler/rustc_codegen_gcc/tests/run/asm.rs @@ -124,7 +124,7 @@ fn main() { // check const (ATT syntax) let mut x: u64 = 42; unsafe { - asm!("add {}, {}", + asm!("add ${}, {}", const 1, inout(reg) x, options(att_syntax) diff --git a/compiler/rustc_codegen_gcc/tests/run/assign.rs b/compiler/rustc_codegen_gcc/tests/run/assign.rs index 427c1a25033..5b0db2da294 100644 --- a/compiler/rustc_codegen_gcc/tests/run/assign.rs +++ b/compiler/rustc_codegen_gcc/tests/run/assign.rs @@ -5,8 +5,8 @@ // 7 8 // 10 -#![allow(unused_attributes)] -#![feature(auto_traits, lang_items, no_core, start, intrinsics, track_caller)] +#![allow(internal_features, unused_attributes)] +#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs, track_caller)] #![no_std] #![no_core] diff --git a/compiler/rustc_codegen_gcc/tests/run/closure.rs b/compiler/rustc_codegen_gcc/tests/run/closure.rs index 8daa681abf7..4ce528f8680 100644 --- a/compiler/rustc_codegen_gcc/tests/run/closure.rs +++ b/compiler/rustc_codegen_gcc/tests/run/closure.rs @@ -9,7 +9,8 @@ // Both args: 11 #![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, - unboxed_closures)] + unboxed_closures, rustc_attrs)] +#![allow(internal_features)] #![no_std] #![no_core] diff --git a/compiler/rustc_codegen_gcc/tests/run/condition.rs b/compiler/rustc_codegen_gcc/tests/run/condition.rs index b7a13081dea..1b3ae6dc004 100644 --- a/compiler/rustc_codegen_gcc/tests/run/condition.rs +++ b/compiler/rustc_codegen_gcc/tests/run/condition.rs @@ -5,7 +5,8 @@ // stdout: true // 1 -#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)] +#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)] +#![allow(internal_features)] #![no_std] #![no_core] diff --git a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs index c02cfd2a85f..2d78ef12aa7 100644 --- a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs +++ b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs @@ -4,6 +4,7 @@ // status: 0 #![feature(auto_traits, lang_items, no_core, start)] +#![allow(internal_features)] #![no_std] #![no_core] diff --git a/compiler/rustc_codegen_gcc/tests/run/exit.rs b/compiler/rustc_codegen_gcc/tests/run/exit.rs index 956e53dd4aa..bf1cbeef302 100644 --- a/compiler/rustc_codegen_gcc/tests/run/exit.rs +++ b/compiler/rustc_codegen_gcc/tests/run/exit.rs @@ -4,6 +4,7 @@ // status: 2 #![feature(auto_traits, lang_items, no_core, start, intrinsics)] +#![allow(internal_features)] #![no_std] #![no_core] diff --git a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs index eeab3520951..be7a233efda 100644 --- a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs +++ b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs @@ -4,6 +4,7 @@ // status: 1 #![feature(auto_traits, lang_items, no_core, start)] +#![allow(internal_features)] #![no_std] #![no_core] diff --git a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs index 8a196f774c8..96030359772 100644 --- a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs +++ b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs @@ -4,7 +4,8 @@ // status: 0 // stdout: 1 -#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)] +#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)] +#![allow(internal_features)] #![no_std] #![no_core] diff --git a/compiler/rustc_codegen_gcc/tests/run/gep.rs b/compiler/rustc_codegen_gcc/tests/run/gep.rs new file mode 100644 index 00000000000..c3d1672cff5 --- /dev/null +++ b/compiler/rustc_codegen_gcc/tests/run/gep.rs @@ -0,0 +1,10 @@ +// Compiler: +// +// Run-time: +// status: 0 + +fn main() { + let mut value = (1, 1); + let ptr = &mut value as *mut (i32, i32); + println!("{:?}", ptr.wrapping_offset(10)); +} diff --git a/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs b/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs index c3fcb3c0a2a..08fa087fccd 100644 --- a/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs +++ b/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs @@ -4,8 +4,8 @@ // stdout: Success // status: signal -#![allow(unused_attributes)] -#![feature(auto_traits, lang_items, no_core, start, intrinsics)] +#![allow(internal_features, unused_attributes)] +#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)] #![no_std] #![no_core] diff --git a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs index 2a2ea8b8bf0..194e55a3dea 100644 --- a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs +++ b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs @@ -7,8 +7,8 @@ // 6 // 11 -#![allow(unused_attributes)] -#![feature(auto_traits, lang_items, no_core, start, intrinsics, track_caller)] +#![allow(internal_features, unused_attributes)] +#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs, track_caller)] #![no_std] #![no_core] diff --git a/compiler/rustc_codegen_gcc/tests/run/operations.rs b/compiler/rustc_codegen_gcc/tests/run/operations.rs index 67b9f241dbb..2d781670873 100644 --- a/compiler/rustc_codegen_gcc/tests/run/operations.rs +++ b/compiler/rustc_codegen_gcc/tests/run/operations.rs @@ -5,8 +5,8 @@ // 39 // 10 -#![allow(unused_attributes)] -#![feature(auto_traits, lang_items, no_core, start, intrinsics, arbitrary_self_types)] +#![allow(internal_features, unused_attributes)] +#![feature(auto_traits, lang_items, no_core, start, intrinsics, arbitrary_self_types, rustc_attrs)] #![no_std] #![no_core] diff --git a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs index da8a8295d56..09d77abe27c 100644 --- a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs +++ b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs @@ -4,7 +4,8 @@ // status: 0 // stdout: 1 -#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)] +#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)] +#![allow(internal_features)] #![no_std] #![no_core] diff --git a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs index 6fa10dca06f..8d40deb8c85 100644 --- a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs +++ b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs @@ -7,6 +7,7 @@ // 42 #![feature(auto_traits, lang_items, no_core, start, intrinsics)] +#![allow(internal_features)] #![no_std] #![no_core] diff --git a/compiler/rustc_codegen_gcc/tests/run/slice.rs b/compiler/rustc_codegen_gcc/tests/run/slice.rs index 96f1c4792e5..1262c86c810 100644 --- a/compiler/rustc_codegen_gcc/tests/run/slice.rs +++ b/compiler/rustc_codegen_gcc/tests/run/slice.rs @@ -4,7 +4,8 @@ // status: 0 // stdout: 5 -#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)] +#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)] +#![allow(internal_features)] #![no_std] #![no_core] diff --git a/compiler/rustc_codegen_gcc/tests/run/static.rs b/compiler/rustc_codegen_gcc/tests/run/static.rs index 19201f1df26..0b933754c29 100644 --- a/compiler/rustc_codegen_gcc/tests/run/static.rs +++ b/compiler/rustc_codegen_gcc/tests/run/static.rs @@ -9,7 +9,8 @@ // 12 // 1 -#![feature(auto_traits, lang_items, no_core, start, intrinsics)] +#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)] +#![allow(internal_features)] #![no_std] #![no_core] diff --git a/compiler/rustc_codegen_gcc/tests/run/structs.rs b/compiler/rustc_codegen_gcc/tests/run/structs.rs index 6c8884855ac..d6455667400 100644 --- a/compiler/rustc_codegen_gcc/tests/run/structs.rs +++ b/compiler/rustc_codegen_gcc/tests/run/structs.rs @@ -6,6 +6,7 @@ // 2 #![feature(auto_traits, lang_items, no_core, start, intrinsics)] +#![allow(internal_features)] #![no_std] #![no_core] diff --git a/compiler/rustc_codegen_gcc/tests/run/tuple.rs b/compiler/rustc_codegen_gcc/tests/run/tuple.rs index 0b670bf2674..8a7d85ae867 100644 --- a/compiler/rustc_codegen_gcc/tests/run/tuple.rs +++ b/compiler/rustc_codegen_gcc/tests/run/tuple.rs @@ -5,6 +5,7 @@ // stdout: 3 #![feature(auto_traits, lang_items, no_core, start, intrinsics)] +#![allow(internal_features)] #![no_std] #![no_core] diff --git a/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py b/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py index 83abe145e64..90fb7bfad27 100644 --- a/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py +++ b/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py @@ -46,10 +46,10 @@ def convert_to_string(content): def extract_instrinsics_from_llvm(llvm_path, intrinsics): - p = subprocess.Popen( - ["llvm-tblgen", "llvm/IR/Intrinsics.td"], - cwd=os.path.join(llvm_path, "llvm/include"), - stdout=subprocess.PIPE) + command = ["llvm-tblgen", "llvm/IR/Intrinsics.td"] + cwd = os.path.join(llvm_path, "llvm/include") + print("=> Running command `{}` from `{}`".format(command, cwd)) + p = subprocess.Popen(command, cwd=cwd, stdout=subprocess.PIPE) output, err = p.communicate() lines = convert_to_string(output).splitlines() pos = 0 diff --git a/compiler/rustc_codegen_gcc/y.sh b/compiler/rustc_codegen_gcc/y.sh new file mode 100755 index 00000000000..188109743e3 --- /dev/null +++ b/compiler/rustc_codegen_gcc/y.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -e +echo "[BUILD] build system" 1>&2 +cd build_system +cargo build --release +cd .. +./build_system/target/release/y $@ diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index cb5acf79135..8655aeec13d 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -19,7 +19,6 @@ use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; -use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{self, CrateType, Lto}; use std::ffi::{CStr, CString}; @@ -584,7 +583,6 @@ fn thin_lto( copy_jobs.push(work_product); info!(" - {}: re-used", module_name); assert!(cgcx.incr_comp_session_dir.is_some()); - cgcx.cgu_reuse_tracker.set_actual_reuse(module_name, CguReuse::PostLto); continue; } } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 4f9b86ec20a..7b259055d40 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1521,8 +1521,13 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { llfn: &'ll Value, ) { let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) }; - if self.tcx.sess.is_sanitizer_cfi_enabled() && let Some(fn_abi) = fn_abi && is_indirect_call { - if let Some(fn_attrs) = fn_attrs && fn_attrs.no_sanitize.contains(SanitizerSet::CFI) { + if self.tcx.sess.is_sanitizer_cfi_enabled() + && let Some(fn_abi) = fn_abi + && is_indirect_call + { + if let Some(fn_attrs) = fn_attrs + && fn_attrs.no_sanitize.contains(SanitizerSet::CFI) + { return; } @@ -1559,25 +1564,29 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { llfn: &'ll Value, ) -> Option<llvm::OperandBundleDef<'ll>> { let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) }; - let kcfi_bundle = - if self.tcx.sess.is_sanitizer_kcfi_enabled() && let Some(fn_abi) = fn_abi && is_indirect_call { - if let Some(fn_attrs) = fn_attrs && fn_attrs.no_sanitize.contains(SanitizerSet::KCFI) { - return None; - } + let kcfi_bundle = if self.tcx.sess.is_sanitizer_kcfi_enabled() + && let Some(fn_abi) = fn_abi + && is_indirect_call + { + if let Some(fn_attrs) = fn_attrs + && fn_attrs.no_sanitize.contains(SanitizerSet::KCFI) + { + return None; + } - let mut options = TypeIdOptions::empty(); - if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() { - options.insert(TypeIdOptions::GENERALIZE_POINTERS); - } - if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() { - options.insert(TypeIdOptions::NORMALIZE_INTEGERS); - } + let mut options = TypeIdOptions::empty(); + if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() { + options.insert(TypeIdOptions::GENERALIZE_POINTERS); + } + if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() { + options.insert(TypeIdOptions::NORMALIZE_INTEGERS); + } - let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options); - Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)])) - } else { - None - }; + let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options); + Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)])) + } else { + None + }; kcfi_bundle } } diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index 5254c3f9c9a..d5778757caa 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -46,8 +46,8 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> llfn } else { let instance_def_id = instance.def_id(); - let llfn = if tcx.sess.target.arch == "x86" && - let Some(dllimport) = common::get_dllimport(tcx, instance_def_id, sym) + let llfn = if tcx.sess.target.arch == "x86" + && let Some(dllimport) = common::get_dllimport(tcx, instance_def_id, sym) { // Fix for https://github.com/rust-lang/rust/issues/104453 // On x86 Windows, LLVM uses 'L' as the prefix for any private @@ -60,8 +60,18 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> // LLVM will prefix the name with `__imp_`. Ideally, we'd like the // existing logic below to set the Storage Class, but it has an // exemption for MinGW for backwards compatability. - let llfn = cx.declare_fn(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&tcx.sess.target), true), fn_abi, Some(instance)); - unsafe { llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); } + let llfn = cx.declare_fn( + &common::i686_decorated_name( + &dllimport, + common::is_mingw_gnu_toolchain(&tcx.sess.target), + true, + ), + fn_abi, + Some(instance), + ); + unsafe { + llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); + } llfn } else { cx.declare_fn(sym, fn_abi, Some(instance)) diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 95af2f8ef4a..73821b1685d 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -182,10 +182,17 @@ fn check_and_apply_linkage<'ll, 'tcx>( llvm::LLVMSetInitializer(g2, g1); g2 } - } else if cx.tcx.sess.target.arch == "x86" && - let Some(dllimport) = common::get_dllimport(cx.tcx, def_id, sym) + } else if cx.tcx.sess.target.arch == "x86" + && let Some(dllimport) = common::get_dllimport(cx.tcx, def_id, sym) { - cx.declare_global(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&cx.tcx.sess.target), true), llty) + cx.declare_global( + &common::i686_decorated_name( + &dllimport, + common::is_mingw_gnu_toolchain(&cx.tcx.sess.target), + true, + ), + llty, + ) } else { // Generate an external declaration. // FIXME(nagisa): investigate whether it can be changed into define_global diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs index 763186a58bf..7ad2d03a5ed 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs @@ -1,4 +1,4 @@ -use rustc_middle::mir::coverage::{CounterId, ExpressionId, Operand}; +use rustc_middle::mir::coverage::{CounterId, CovTerm, ExpressionId}; /// Must match the layout of `LLVMRustCounterKind`. #[derive(Copy, Clone, Debug)] @@ -43,11 +43,11 @@ impl Counter { Self { kind: CounterKind::Expression, id: expression_id.as_u32() } } - pub(crate) fn from_operand(operand: Operand) -> Self { - match operand { - Operand::Zero => Self::ZERO, - Operand::Counter(id) => Self::counter_value_reference(id), - Operand::Expression(id) => Self::expression(id), + pub(crate) fn from_term(term: CovTerm) -> Self { + match term { + CovTerm::Zero => Self::ZERO, + CovTerm::Counter(id) => Self::counter_value_reference(id), + CovTerm::Expression(id) => Self::expression(id), } } } @@ -73,17 +73,6 @@ pub struct CounterExpression { pub rhs: Counter, } -impl CounterExpression { - /// The dummy expression `(0 - 0)` has a representation of all zeroes, - /// making it marginally more efficient to initialize than `(0 + 0)`. - pub(crate) const DUMMY: Self = - Self { lhs: Counter::ZERO, kind: ExprKind::Subtract, rhs: Counter::ZERO }; - - pub fn new(lhs: Counter, kind: ExprKind, rhs: Counter) -> Self { - Self { kind, lhs, rhs } - } -} - /// Corresponds to enum `llvm::coverage::CounterMappingRegion::RegionKind`. /// /// Must match the layout of `LLVMRustCounterMappingRegionKind`. diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs index 55f43aa5341..84319b4ba2d 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs @@ -1,64 +1,78 @@ use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind}; use rustc_data_structures::fx::FxIndexSet; -use rustc_index::IndexVec; -use rustc_middle::mir::coverage::{CodeRegion, CounterId, ExpressionId, Op, Operand}; +use rustc_index::bit_set::BitSet; +use rustc_middle::mir::coverage::{ + CodeRegion, CounterId, CovTerm, Expression, ExpressionId, FunctionCoverageInfo, Mapping, Op, +}; use rustc_middle::ty::Instance; -use rustc_middle::ty::TyCtxt; -#[derive(Clone, Debug, PartialEq)] -pub struct Expression { - lhs: Operand, - op: Op, - rhs: Operand, - code_regions: Vec<CodeRegion>, -} - -/// Collects all of the coverage regions associated with (a) injected counters, (b) counter -/// expressions (additions or subtraction), and (c) unreachable regions (always counted as zero), -/// for a given Function. This struct also stores the `function_source_hash`, -/// computed during instrumentation, and forwarded with counters. -/// -/// Note, it may be important to understand LLVM's definitions of `unreachable` regions versus "gap -/// regions" (or "gap areas"). A gap region is a code region within a counted region (either counter -/// or expression), but the line or lines in the gap region are not executable (such as lines with -/// only whitespace or comments). According to LLVM Code Coverage Mapping documentation, "A count -/// for a gap area is only used as the line execution count if there are no other regions on a -/// line." +/// Holds all of the coverage mapping data associated with a function instance, +/// collected during traversal of `Coverage` statements in the function's MIR. #[derive(Debug)] pub struct FunctionCoverage<'tcx> { - instance: Instance<'tcx>, - source_hash: u64, + /// Coverage info that was attached to this function by the instrumentor. + function_coverage_info: &'tcx FunctionCoverageInfo, is_used: bool, - counters: IndexVec<CounterId, Option<Vec<CodeRegion>>>, - expressions: IndexVec<ExpressionId, Option<Expression>>, - unreachable_regions: Vec<CodeRegion>, + + /// Tracks which counters have been seen, so that we can identify mappings + /// to counters that were optimized out, and set them to zero. + counters_seen: BitSet<CounterId>, + /// Contains all expression IDs that have been seen in an `ExpressionUsed` + /// coverage statement, plus all expression IDs that aren't directly used + /// by any mappings (and therefore do not have expression-used statements). + /// After MIR traversal is finished, we can conclude that any IDs missing + /// from this set must have had their statements deleted by MIR opts. + expressions_seen: BitSet<ExpressionId>, } impl<'tcx> FunctionCoverage<'tcx> { /// Creates a new set of coverage data for a used (called) function. - pub fn new(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self { - Self::create(tcx, instance, true) + pub fn new( + instance: Instance<'tcx>, + function_coverage_info: &'tcx FunctionCoverageInfo, + ) -> Self { + Self::create(instance, function_coverage_info, true) } /// Creates a new set of coverage data for an unused (never called) function. - pub fn unused(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self { - Self::create(tcx, instance, false) + pub fn unused( + instance: Instance<'tcx>, + function_coverage_info: &'tcx FunctionCoverageInfo, + ) -> Self { + Self::create(instance, function_coverage_info, false) } - fn create(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, is_used: bool) -> Self { - let coverageinfo = tcx.coverageinfo(instance.def); + fn create( + instance: Instance<'tcx>, + function_coverage_info: &'tcx FunctionCoverageInfo, + is_used: bool, + ) -> Self { + let num_counters = function_coverage_info.num_counters; + let num_expressions = function_coverage_info.expressions.len(); debug!( - "FunctionCoverage::create(instance={:?}) has coverageinfo={:?}. is_used={}", - instance, coverageinfo, is_used + "FunctionCoverage::create(instance={instance:?}) has \ + num_counters={num_counters}, num_expressions={num_expressions}, is_used={is_used}" ); + + // Create a filled set of expression IDs, so that expressions not + // directly used by mappings will be treated as "seen". + // (If they end up being unused, LLVM will delete them for us.) + let mut expressions_seen = BitSet::new_filled(num_expressions); + // For each expression ID that is directly used by one or more mappings, + // mark it as not-yet-seen. This indicates that we expect to see a + // corresponding `ExpressionUsed` statement during MIR traversal. + for Mapping { term, .. } in &function_coverage_info.mappings { + if let &CovTerm::Expression(id) = term { + expressions_seen.remove(id); + } + } + Self { - instance, - source_hash: 0, // will be set with the first `add_counter()` + function_coverage_info, is_used, - counters: IndexVec::from_elem_n(None, coverageinfo.num_counters as usize), - expressions: IndexVec::from_elem_n(None, coverageinfo.num_expressions as usize), - unreachable_regions: Vec::new(), + counters_seen: BitSet::new_empty(num_counters), + expressions_seen, } } @@ -67,135 +81,94 @@ impl<'tcx> FunctionCoverage<'tcx> { self.is_used } - /// Sets the function source hash value. If called multiple times for the same function, all - /// calls should have the same hash value. - pub fn set_function_source_hash(&mut self, source_hash: u64) { - if self.source_hash == 0 { - self.source_hash = source_hash; - } else { - debug_assert_eq!(source_hash, self.source_hash); - } - } - - /// Adds code regions to be counted by an injected counter intrinsic. + /// Marks a counter ID as having been seen in a counter-increment statement. #[instrument(level = "debug", skip(self))] - pub(crate) fn add_counter(&mut self, id: CounterId, code_regions: &[CodeRegion]) { - if code_regions.is_empty() { - return; - } - - let slot = &mut self.counters[id]; - match slot { - None => *slot = Some(code_regions.to_owned()), - // If this counter ID slot has already been filled, it should - // contain identical information. - Some(ref previous_regions) => assert_eq!( - previous_regions, code_regions, - "add_counter: code regions for id changed" - ), - } - } - - /// Adds information about a coverage expression, along with zero or more - /// code regions mapped to that expression. - /// - /// Both counters and "counter expressions" (or simply, "expressions") can be operands in other - /// expressions. These are tracked as separate variants of `Operand`, so there is no ambiguity - /// between operands that are counter IDs and operands that are expression IDs. - #[instrument(level = "debug", skip(self))] - pub(crate) fn add_counter_expression( - &mut self, - expression_id: ExpressionId, - lhs: Operand, - op: Op, - rhs: Operand, - code_regions: &[CodeRegion], - ) { - debug_assert!( - expression_id.as_usize() < self.expressions.len(), - "expression_id {} is out of range for expressions.len() = {} - for {:?}", - expression_id.as_usize(), - self.expressions.len(), - self, - ); - - let expression = Expression { lhs, op, rhs, code_regions: code_regions.to_owned() }; - let slot = &mut self.expressions[expression_id]; - match slot { - None => *slot = Some(expression), - // If this expression ID slot has already been filled, it should - // contain identical information. - Some(ref previous_expression) => assert_eq!( - previous_expression, &expression, - "add_counter_expression: expression for id changed" - ), - } + pub(crate) fn mark_counter_id_seen(&mut self, id: CounterId) { + self.counters_seen.insert(id); } - /// Adds regions that will be marked as "unreachable", with a constant "zero counter". + /// Marks an expression ID as having been seen in an expression-used statement. #[instrument(level = "debug", skip(self))] - pub(crate) fn add_unreachable_regions(&mut self, code_regions: &[CodeRegion]) { - assert!(!code_regions.is_empty(), "unreachable regions always have code regions"); - self.unreachable_regions.extend_from_slice(code_regions); + pub(crate) fn mark_expression_id_seen(&mut self, id: ExpressionId) { + self.expressions_seen.insert(id); } - /// Perform some simplifications to make the final coverage mappings - /// slightly smaller. + /// Identify expressions that will always have a value of zero, and note + /// their IDs in [`ZeroExpressions`]. Mappings that refer to a zero expression + /// can instead become mappings to a constant zero value. /// /// This method mainly exists to preserve the simplifications that were /// already being performed by the Rust-side expression renumbering, so that /// the resulting coverage mappings don't get worse. - pub(crate) fn simplify_expressions(&mut self) { + fn identify_zero_expressions(&self) -> ZeroExpressions { // The set of expressions that either were optimized out entirely, or // have zero as both of their operands, and will therefore always have // a value of zero. Other expressions that refer to these as operands - // can have those operands replaced with `Operand::Zero`. + // can have those operands replaced with `CovTerm::Zero`. let mut zero_expressions = FxIndexSet::default(); - // For each expression, perform simplifications based on lower-numbered - // expressions, and then update the set of always-zero expressions if - // necessary. + // Simplify a copy of each expression based on lower-numbered expressions, + // and then update the set of always-zero expressions if necessary. // (By construction, expressions can only refer to other expressions - // that have lower IDs, so one simplification pass is sufficient.) - for (id, maybe_expression) in self.expressions.iter_enumerated_mut() { - let Some(expression) = maybe_expression else { - // If an expression is missing, it must have been optimized away, + // that have lower IDs, so one pass is sufficient.) + for (id, expression) in self.function_coverage_info.expressions.iter_enumerated() { + if !self.expressions_seen.contains(id) { + // If an expression was not seen, it must have been optimized away, // so any operand that refers to it can be replaced with zero. zero_expressions.insert(id); continue; + } + + // We don't need to simplify the actual expression data in the + // expressions list; we can just simplify a temporary copy and then + // use that to update the set of always-zero expressions. + let Expression { mut lhs, op, mut rhs } = *expression; + + // If an expression has an operand that is also an expression, the + // operand's ID must be strictly lower. This is what lets us find + // all zero expressions in one pass. + let assert_operand_expression_is_lower = |operand_id: ExpressionId| { + assert!( + operand_id < id, + "Operand {operand_id:?} should be less than {id:?} in {expression:?}", + ) }; // If an operand refers to an expression that is always zero, then - // that operand can be replaced with `Operand::Zero`. - let maybe_set_operand_to_zero = |operand: &mut Operand| match &*operand { - Operand::Expression(id) if zero_expressions.contains(id) => { - *operand = Operand::Zero; + // that operand can be replaced with `CovTerm::Zero`. + let maybe_set_operand_to_zero = |operand: &mut CovTerm| match *operand { + CovTerm::Expression(id) => { + assert_operand_expression_is_lower(id); + if zero_expressions.contains(&id) { + *operand = CovTerm::Zero; + } } _ => (), }; - maybe_set_operand_to_zero(&mut expression.lhs); - maybe_set_operand_to_zero(&mut expression.rhs); + maybe_set_operand_to_zero(&mut lhs); + maybe_set_operand_to_zero(&mut rhs); // Coverage counter values cannot be negative, so if an expression // involves subtraction from zero, assume that its RHS must also be zero. // (Do this after simplifications that could set the LHS to zero.) - if let Expression { lhs: Operand::Zero, op: Op::Subtract, .. } = expression { - expression.rhs = Operand::Zero; + if lhs == CovTerm::Zero && op == Op::Subtract { + rhs = CovTerm::Zero; } // After the above simplifications, if both operands are zero, then // we know that this expression is always zero too. - if let Expression { lhs: Operand::Zero, rhs: Operand::Zero, .. } = expression { + if lhs == CovTerm::Zero && rhs == CovTerm::Zero { zero_expressions.insert(id); } } + + ZeroExpressions(zero_expressions) } /// Return the source hash, generated from the HIR node structure, and used to indicate whether /// or not the source code structure changed between different compilations. pub fn source_hash(&self) -> u64 { - self.source_hash + if self.is_used { self.function_coverage_info.function_source_hash } else { 0 } } /// Generate an array of CounterExpressions, and an iterator over all `Counter`s and their @@ -204,91 +177,80 @@ impl<'tcx> FunctionCoverage<'tcx> { pub fn get_expressions_and_counter_regions( &self, ) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &CodeRegion)>) { - assert!( - self.source_hash != 0 || !self.is_used, - "No counters provided the source_hash for used function: {:?}", - self.instance - ); + let zero_expressions = self.identify_zero_expressions(); - let counter_expressions = self.counter_expressions(); + let counter_expressions = self.counter_expressions(&zero_expressions); // Expression IDs are indices into `self.expressions`, and on the LLVM // side they will be treated as indices into `counter_expressions`, so // the two vectors should correspond 1:1. - assert_eq!(self.expressions.len(), counter_expressions.len()); + assert_eq!(self.function_coverage_info.expressions.len(), counter_expressions.len()); - let counter_regions = self.counter_regions(); - let expression_regions = self.expression_regions(); - let unreachable_regions = self.unreachable_regions(); + let counter_regions = self.counter_regions(zero_expressions); - let counter_regions = - counter_regions.chain(expression_regions.into_iter().chain(unreachable_regions)); (counter_expressions, counter_regions) } - fn counter_regions(&self) -> impl Iterator<Item = (Counter, &CodeRegion)> { - self.counters - .iter_enumerated() - // Filter out counter IDs that we never saw during MIR traversal. - // This can happen if a counter was optimized out by MIR transforms - // (and replaced with `CoverageKind::Unreachable` instead). - .filter_map(|(id, maybe_code_regions)| Some((id, maybe_code_regions.as_ref()?))) - .flat_map(|(id, code_regions)| { - let counter = Counter::counter_value_reference(id); - code_regions.iter().map(move |region| (counter, region)) - }) - } - /// Convert this function's coverage expression data into a form that can be /// passed through FFI to LLVM. - fn counter_expressions(&self) -> Vec<CounterExpression> { + fn counter_expressions(&self, zero_expressions: &ZeroExpressions) -> Vec<CounterExpression> { // We know that LLVM will optimize out any unused expressions before // producing the final coverage map, so there's no need to do the same // thing on the Rust side unless we're confident we can do much better. // (See `CounterExpressionsMinimizer` in `CoverageMappingWriter.cpp`.) - self.expressions + let counter_from_operand = |operand: CovTerm| match operand { + CovTerm::Expression(id) if zero_expressions.contains(id) => Counter::ZERO, + _ => Counter::from_term(operand), + }; + + self.function_coverage_info + .expressions .iter() - .map(|expression| match expression { - None => { - // This expression ID was allocated, but we never saw the - // actual expression, so it must have been optimized out. - // Replace it with a dummy expression, and let LLVM take - // care of omitting it from the expression list. - CounterExpression::DUMMY - } - &Some(Expression { lhs, op, rhs, .. }) => { - // Convert the operands and operator as normal. - CounterExpression::new( - Counter::from_operand(lhs), - match op { - Op::Add => ExprKind::Add, - Op::Subtract => ExprKind::Subtract, - }, - Counter::from_operand(rhs), - ) - } + .map(|&Expression { lhs, op, rhs }| CounterExpression { + lhs: counter_from_operand(lhs), + kind: match op { + Op::Add => ExprKind::Add, + Op::Subtract => ExprKind::Subtract, + }, + rhs: counter_from_operand(rhs), }) .collect::<Vec<_>>() } - fn expression_regions(&self) -> Vec<(Counter, &CodeRegion)> { - // Find all of the expression IDs that weren't optimized out AND have - // one or more attached code regions, and return the corresponding - // mappings as counter/region pairs. - self.expressions - .iter_enumerated() - .filter_map(|(id, maybe_expression)| { - let code_regions = &maybe_expression.as_ref()?.code_regions; - Some((id, code_regions)) - }) - .flat_map(|(id, code_regions)| { - let counter = Counter::expression(id); - code_regions.iter().map(move |code_region| (counter, code_region)) - }) - .collect::<Vec<_>>() + /// Converts this function's coverage mappings into an intermediate form + /// that will be used by `mapgen` when preparing for FFI. + fn counter_regions( + &self, + zero_expressions: ZeroExpressions, + ) -> impl Iterator<Item = (Counter, &CodeRegion)> { + // Historically, mappings were stored directly in counter/expression + // statements in MIR, and MIR optimizations would sometimes remove them. + // That's mostly no longer true, so now we detect cases where that would + // have happened, and zero out the corresponding mappings here instead. + let counter_for_term = move |term: CovTerm| { + let force_to_zero = match term { + CovTerm::Counter(id) => !self.counters_seen.contains(id), + CovTerm::Expression(id) => zero_expressions.contains(id), + CovTerm::Zero => false, + }; + if force_to_zero { Counter::ZERO } else { Counter::from_term(term) } + }; + + self.function_coverage_info.mappings.iter().map(move |mapping| { + let &Mapping { term, ref code_region } = mapping; + let counter = counter_for_term(term); + (counter, code_region) + }) } +} + +/// Set of expression IDs that are known to always evaluate to zero. +/// Any mapping or expression operand that refers to these expressions can have +/// that reference replaced with a constant zero value. +struct ZeroExpressions(FxIndexSet<ExpressionId>); - fn unreachable_regions(&self) -> impl Iterator<Item = (Counter, &CodeRegion)> { - self.unreachable_regions.iter().map(|region| (Counter::ZERO, region)) +impl ZeroExpressions { + fn contains(&self, id: ExpressionId) -> bool { + self.0.contains(&id) } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index d4e77525698..ef3647efd88 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -10,9 +10,8 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_index::IndexVec; use rustc_middle::bug; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::coverage::CodeRegion; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Symbol; /// Generates and exports the Coverage Map. @@ -60,10 +59,8 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) { // Encode coverage mappings and generate function records let mut function_data = Vec::new(); - for (instance, mut function_coverage) in function_coverage_map { + for (instance, function_coverage) in function_coverage_map { debug!("Generate function coverage for {}, {:?}", cx.codegen_unit.name(), instance); - function_coverage.simplify_expressions(); - let function_coverage = function_coverage; let mangled_function_name = tcx.symbol_name(instance).name; let source_hash = function_coverage.source_hash(); @@ -170,10 +167,11 @@ fn encode_mappings_for_function( let mut virtual_file_mapping = IndexVec::<u32, u32>::new(); let mut mapping_regions = Vec::with_capacity(counter_regions.len()); - // Sort the list of (counter, region) mapping pairs by region, so that they - // can be grouped by filename. Prepare file IDs for each filename, and - // prepare the mapping data so that we can pass it through FFI to LLVM. - counter_regions.sort_by_key(|(_counter, region)| *region); + // Sort and group the list of (counter, region) mapping pairs by filename. + // (Preserve any further ordering imposed by `FunctionCoverage`.) + // Prepare file IDs for each filename, and prepare the mapping data so that + // we can pass it through FFI to LLVM. + counter_regions.sort_by_key(|(_counter, region)| region.file_name); for counter_regions_for_file in counter_regions.group_by(|(_, a), (_, b)| a.file_name == b.file_name) { @@ -331,16 +329,14 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) { for non_codegenned_def_id in eligible_def_ids.into_iter().filter(|id| !codegenned_def_ids.contains(id)) { - let codegen_fn_attrs = tcx.codegen_fn_attrs(non_codegenned_def_id); - - // If a function is marked `#[coverage(off)]`, then skip generating a - // dead code stub for it. - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_COVERAGE) { - debug!("skipping unused fn marked #[coverage(off)]: {:?}", non_codegenned_def_id); + // Skip any function that didn't have coverage data added to it by the + // coverage instrumentor. + let body = tcx.instance_mir(ty::InstanceDef::Item(non_codegenned_def_id)); + let Some(function_coverage_info) = body.function_coverage_info.as_deref() else { continue; - } + }; debug!("generating unused fn: {:?}", non_codegenned_def_id); - cx.define_unused_fn(non_codegenned_def_id); + cx.define_unused_fn(non_codegenned_def_id, function_coverage_info); } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index dd2ce9b525b..204a73b788a 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -16,7 +16,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_llvm::RustString; use rustc_middle::bug; -use rustc_middle::mir::coverage::{CounterId, CoverageKind}; +use rustc_middle::mir::coverage::{CounterId, CoverageKind, FunctionCoverageInfo}; use rustc_middle::mir::Coverage; use rustc_middle::ty; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; @@ -88,44 +88,63 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { /// For used/called functions, the coverageinfo was already added to the /// `function_coverage_map` (keyed by function `Instance`) during codegen. /// But in this case, since the unused function was _not_ previously - /// codegenned, collect the coverage `CodeRegion`s from the MIR and add - /// them. Since the function is never called, all of its `CodeRegion`s can be - /// added as `unreachable_region`s. - fn define_unused_fn(&self, def_id: DefId) { + /// codegenned, collect the function coverage info from MIR and add an + /// "unused" entry to the function coverage map. + fn define_unused_fn(&self, def_id: DefId, function_coverage_info: &'tcx FunctionCoverageInfo) { let instance = declare_unused_fn(self, def_id); codegen_unused_fn_and_counter(self, instance); - add_unused_function_coverage(self, instance, def_id); + add_unused_function_coverage(self, instance, function_coverage_info); } } impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { + #[instrument(level = "debug", skip(self))] fn add_coverage(&mut self, instance: Instance<'tcx>, coverage: &Coverage) { + // Our caller should have already taken care of inlining subtleties, + // so we can assume that counter/expression IDs in this coverage + // statement are meaningful for the given instance. + // + // (Either the statement was not inlined and directly belongs to this + // instance, or it was inlined *from* this instance.) + let bx = self; + let Some(function_coverage_info) = + bx.tcx.instance_mir(instance.def).function_coverage_info.as_deref() + else { + debug!("function has a coverage statement but no coverage info"); + return; + }; + let Some(coverage_context) = bx.coverage_context() else { return }; let mut coverage_map = coverage_context.function_coverage_map.borrow_mut(); let func_coverage = coverage_map .entry(instance) - .or_insert_with(|| FunctionCoverage::new(bx.tcx(), instance)); + .or_insert_with(|| FunctionCoverage::new(instance, function_coverage_info)); - let Coverage { kind, code_regions } = coverage; + let Coverage { kind } = coverage; match *kind { - CoverageKind::Counter { function_source_hash, id } => { - debug!( - "ensuring function source hash is set for instance={:?}; function_source_hash={}", - instance, function_source_hash, - ); - func_coverage.set_function_source_hash(function_source_hash); - func_coverage.add_counter(id, code_regions); + CoverageKind::CounterIncrement { id } => { + func_coverage.mark_counter_id_seen(id); // We need to explicitly drop the `RefMut` before calling into `instrprof_increment`, // as that needs an exclusive borrow. drop(coverage_map); - let coverageinfo = bx.tcx().coverageinfo(instance.def); + // The number of counters passed to `llvm.instrprof.increment` might + // be smaller than the number originally inserted by the instrumentor, + // if some high-numbered counters were removed by MIR optimizations. + // If so, LLVM's profiler runtime will use fewer physical counters. + let num_counters = + bx.tcx().coverage_ids_info(instance.def).max_counter_id.as_u32() + 1; + assert!( + num_counters as usize <= function_coverage_info.num_counters, + "num_counters disagreement: query says {num_counters} but function info only has {}", + function_coverage_info.num_counters + ); let fn_name = bx.get_pgo_func_name_var(instance); - let hash = bx.const_u64(function_source_hash); - let num_counters = bx.const_u32(coverageinfo.num_counters); + let hash = bx.const_u64(function_coverage_info.function_source_hash); + let num_counters = bx.const_u32(num_counters); let index = bx.const_u32(id.as_u32()); debug!( "codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})", @@ -133,11 +152,8 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { ); bx.instrprof_increment(fn_name, hash, num_counters, index); } - CoverageKind::Expression { id, lhs, op, rhs } => { - func_coverage.add_counter_expression(id, lhs, op, rhs, code_regions); - } - CoverageKind::Unreachable => { - func_coverage.add_unreachable_regions(code_regions); + CoverageKind::ExpressionUsed { id } => { + func_coverage.mark_expression_id_seen(id); } } } @@ -200,15 +216,11 @@ fn codegen_unused_fn_and_counter<'tcx>(cx: &CodegenCx<'_, 'tcx>, instance: Insta fn add_unused_function_coverage<'tcx>( cx: &CodegenCx<'_, 'tcx>, instance: Instance<'tcx>, - def_id: DefId, + function_coverage_info: &'tcx FunctionCoverageInfo, ) { - let tcx = cx.tcx; - - let mut function_coverage = FunctionCoverage::unused(tcx, instance); - for &code_region in tcx.covered_code_regions(def_id) { - let code_region = std::slice::from_ref(code_region); - function_coverage.add_unreachable_regions(code_region); - } + // An unused function's mappings will automatically be rewritten to map to + // zero, because none of its counters/expressions are marked as seen. + let function_coverage = FunctionCoverage::unused(instance, function_coverage_info); if let Some(coverage_context) = cx.coverage_context() { coverage_context.function_coverage_map.borrow_mut().insert(instance, function_coverage); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs index aff764f0224..6a63eda4b99 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -75,7 +75,10 @@ fn make_mir_scope<'ll, 'tcx>( return; }; - if let Some(vars) = variables && !vars.contains(scope) && scope_data.inlined.is_none() { + if let Some(vars) = variables + && !vars.contains(scope) + && scope_data.inlined.is_none() + { // Do not create a DIScope if there are no variables defined in this // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat. debug_context.scopes[scope] = parent_scope; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 30cc9ea9b82..d874b3ab99d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -537,7 +537,9 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { // Only "class" methods are generally understood by LLVM, // so avoid methods on other types (e.g., `<*mut T>::null`). - if let ty::Adt(def, ..) = impl_self_ty.kind() && !def.is_box() { + if let ty::Adt(def, ..) = impl_self_ty.kind() + && !def.is_box() + { // Again, only create type information if full debuginfo is enabled if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param() { diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 59d1ea05d8a..7a390d35a2b 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -4,6 +4,9 @@ //! //! This API is completely unstable and subject to change. +#![cfg_attr(not(bootstrap), allow(internal_features))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), doc(rust_logo))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(extern_types)] #![feature(hash_raw_entry)] diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index dcc62d314ff..fd4c9572af2 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -397,7 +397,12 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { // extracts all the individual values. let ety = element.llvm_type(cx); - return Some(cx.type_vector(ety, *count)); + if *count == 1 { + // Emitting `<1 x T>` would be silly; just use the scalar. + return Some(ety); + } else { + return Some(cx.type_vector(ety, *count)); + } } // FIXME: The above only handled integer arrays; surely more things diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 34d0e2d1df6..454e2f80676 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -16,6 +16,7 @@ pathdiff = "0.2.0" serde_json = "1.0.59" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } regex = "1.4" +thin-vec = "0.2.12" rustc_serialize = { path = "../rustc_serialize" } rustc_arena = { path = "../rustc_arena" } diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 66482667336..5881c6236ec 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -11,6 +11,9 @@ codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing codegen_ssa_binary_output_to_tty = option `-o` or `--emit` is used to write binary output type `{$shorthand}` to stdout, but stdout is a tty +codegen_ssa_cgu_not_recorded = + CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded + codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option. codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error} @@ -39,6 +42,8 @@ codegen_ssa_failed_to_get_layout = failed to get layout for {$ty}: {$err} codegen_ssa_failed_to_write = failed to write {$path}: {$error} +codegen_ssa_field_associated_value_expected = associated value expected for `{$name}` + codegen_ssa_ignoring_emit_path = ignoring emit path because multiple .{$extension} files were produced codegen_ssa_ignoring_output = ignoring -o because multiple .{$extension} files were produced @@ -46,6 +51,12 @@ codegen_ssa_ignoring_output = ignoring -o because multiple .{$extension} files w codegen_ssa_illegal_link_ordinal_format = illegal ordinal format in `link_ordinal` .note = an unsuffixed integer value, e.g., `1`, is expected +codegen_ssa_incorrect_cgu_reuse_type = + CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least -> + [one] {"at least "} + *[other] {""} + }`{$expected_reuse}` + codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient. codegen_ssa_invalid_link_ordinal_nargs = incorrect number of arguments to `#[link_ordinal]` @@ -153,12 +164,18 @@ codegen_ssa_linker_unsupported_modifier = `as-needed` modifier not supported for codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status} +codegen_ssa_malformed_cgu_name = + found malformed codegen unit name `{$user_path}`. codegen units names must always start with the name of the crate (`{$crate_name}` in this case). + codegen_ssa_metadata_object_file_write = error writing metadata object file: {$error} codegen_ssa_missing_cpp_build_tool_component = or a necessary component may be missing from the "C++ build tools" workload codegen_ssa_missing_memory_ordering = Atomic intrinsic missing memory ordering +codegen_ssa_missing_query_depgraph = + found CGU-reuse attribute but `-Zquery-dep-graph` was not specified + codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but `link.exe` was not found codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions @@ -166,6 +183,11 @@ codegen_ssa_multiple_external_func_decl = multiple declarations of external func codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple times .help = did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead +codegen_ssa_no_field = no field `{$name}` + +codegen_ssa_no_module_named = + no module named `{$user_path}` (mangled: {$cgu_name}). available modules: {$cgu_names} + codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error} codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status} @@ -297,6 +319,8 @@ codegen_ssa_unknown_atomic_operation = unknown atomic operation codegen_ssa_unknown_atomic_ordering = unknown ordering in atomic intrinsic +codegen_ssa_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified + codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}` codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target diff --git a/compiler/rustc_incremental/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs index 8e22ab4083e..16bb7b12bd3 100644 --- a/compiler/rustc_incremental/src/assert_module_sources.rs +++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs @@ -25,16 +25,21 @@ use crate::errors; use rustc_ast as ast; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unord::UnordSet; +use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::mir::mono::CodegenUnitNameBuilder; use rustc_middle::ty::TyCtxt; -use rustc_session::cgu_reuse_tracker::*; -use rustc_span::symbol::{sym, Symbol}; +use rustc_session::Session; +use rustc_span::symbol::sym; +use rustc_span::{Span, Symbol}; +use std::borrow::Cow; +use std::fmt; use thin_vec::ThinVec; #[allow(missing_docs)] -pub fn assert_module_sources(tcx: TyCtxt<'_>) { +pub fn assert_module_sources(tcx: TyCtxt<'_>, set_reuse: &dyn Fn(&mut CguReuseTracker)) { tcx.dep_graph.with_ignore(|| { if tcx.sess.opts.incremental.is_none() { return; @@ -43,21 +48,34 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>) { let available_cgus = tcx.collect_and_partition_mono_items(()).1.iter().map(|cgu| cgu.name()).collect(); - let ams = AssertModuleSource { tcx, available_cgus }; + let mut ams = AssertModuleSource { + tcx, + available_cgus, + cgu_reuse_tracker: if tcx.sess.opts.unstable_opts.query_dep_graph { + CguReuseTracker::new() + } else { + CguReuseTracker::new_disabled() + }, + }; for attr in tcx.hir().attrs(rustc_hir::CRATE_HIR_ID) { ams.check_attr(attr); } - }) + + set_reuse(&mut ams.cgu_reuse_tracker); + + ams.cgu_reuse_tracker.check_expected_reuse(tcx.sess); + }); } struct AssertModuleSource<'tcx> { tcx: TyCtxt<'tcx>, available_cgus: UnordSet<Symbol>, + cgu_reuse_tracker: CguReuseTracker, } impl<'tcx> AssertModuleSource<'tcx> { - fn check_attr(&self, attr: &ast::Attribute) { + fn check_attr(&mut self, attr: &ast::Attribute) { let (expected_reuse, comp_kind) = if attr.has_name(sym::rustc_partition_reused) { (CguReuse::PreLto, ComparisonKind::AtLeast) } else if attr.has_name(sym::rustc_partition_codegened) { @@ -129,7 +147,7 @@ impl<'tcx> AssertModuleSource<'tcx> { }); } - self.tcx.sess.cgu_reuse_tracker.set_expectation( + self.cgu_reuse_tracker.set_expectation( cgu_name, &user_path, attr.span, @@ -169,3 +187,109 @@ impl<'tcx> AssertModuleSource<'tcx> { false } } + +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] +pub enum CguReuse { + No, + PreLto, + PostLto, +} + +impl fmt::Display for CguReuse { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + CguReuse::No => write!(f, "No"), + CguReuse::PreLto => write!(f, "PreLto "), + CguReuse::PostLto => write!(f, "PostLto "), + } + } +} + +impl IntoDiagnosticArg for CguReuse { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.to_string())) + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum ComparisonKind { + Exact, + AtLeast, +} + +struct TrackerData { + actual_reuse: FxHashMap<String, CguReuse>, + expected_reuse: FxHashMap<String, (String, Span, CguReuse, ComparisonKind)>, +} + +pub struct CguReuseTracker { + data: Option<TrackerData>, +} + +impl CguReuseTracker { + fn new() -> CguReuseTracker { + let data = + TrackerData { actual_reuse: Default::default(), expected_reuse: Default::default() }; + + CguReuseTracker { data: Some(data) } + } + + fn new_disabled() -> CguReuseTracker { + CguReuseTracker { data: None } + } + + pub fn set_actual_reuse(&mut self, cgu_name: &str, kind: CguReuse) { + if let Some(data) = &mut self.data { + debug!("set_actual_reuse({cgu_name:?}, {kind:?})"); + + let prev_reuse = data.actual_reuse.insert(cgu_name.to_string(), kind); + assert!(prev_reuse.is_none()); + } + } + + fn set_expectation( + &mut self, + cgu_name: Symbol, + cgu_user_name: &str, + error_span: Span, + expected_reuse: CguReuse, + comparison_kind: ComparisonKind, + ) { + if let Some(data) = &mut self.data { + debug!("set_expectation({cgu_name:?}, {expected_reuse:?}, {comparison_kind:?})"); + + data.expected_reuse.insert( + cgu_name.to_string(), + (cgu_user_name.to_string(), error_span, expected_reuse, comparison_kind), + ); + } + } + + fn check_expected_reuse(&self, sess: &Session) { + if let Some(ref data) = self.data { + for (cgu_name, &(ref cgu_user_name, ref error_span, expected_reuse, comparison_kind)) in + &data.expected_reuse + { + if let Some(&actual_reuse) = data.actual_reuse.get(cgu_name) { + let (error, at_least) = match comparison_kind { + ComparisonKind::Exact => (expected_reuse != actual_reuse, false), + ComparisonKind::AtLeast => (actual_reuse < expected_reuse, true), + }; + + if error { + let at_least = if at_least { 1 } else { 0 }; + errors::IncorrectCguReuseType { + span: *error_span, + cgu_user_name, + actual_reuse, + expected_reuse, + at_least, + }; + } + } else { + sess.emit_fatal(errors::CguNotRecorded { cgu_user_name, cgu_name }); + } + } + } + } +} diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 464424409c7..f16fe372a92 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -368,17 +368,25 @@ fn link_rlib<'a>( let NativeLibKind::Static { bundle: None | Some(true), .. } = lib.kind else { continue; }; - if flavor == RlibFlavor::Normal && let Some(filename) = lib.filename { + if flavor == RlibFlavor::Normal + && let Some(filename) = lib.filename + { let path = find_native_static_library(filename.as_str(), true, &lib_search_paths, sess); - let src = read(path).map_err(|e| sess.emit_fatal(errors::ReadFileError {message: e }))?; + let src = + read(path).map_err(|e| sess.emit_fatal(errors::ReadFileError { message: e }))?; let (data, _) = create_wrapper_file(sess, b".bundled_lib".to_vec(), &src); let wrapper_file = emit_wrapper_file(sess, &data, tmpdir, filename.as_str()); packed_bundled_libs.push(wrapper_file); } else { - let path = - find_native_static_library(lib.name.as_str(), lib.verbatim, &lib_search_paths, sess); + let path = find_native_static_library( + lib.name.as_str(), + lib.verbatim, + &lib_search_paths, + sess, + ); ab.add_archive(&path, Box::new(|_| false)).unwrap_or_else(|error| { - sess.emit_fatal(errors::AddNativeLibrary { library_path: path, error })}); + sess.emit_fatal(errors::AddNativeLibrary { library_path: path, error }) + }); } } @@ -2978,8 +2986,9 @@ fn add_lld_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { } // 1. Implement the "self-contained" part of this feature by adding rustc distribution - // directories to the tool's search path. - if sess.opts.cg.link_self_contained.linker() { + // directories to the tool's search path: + // - if the self-contained linker is enabled on the CLI. + if sess.opts.cg.link_self_contained.is_linker_enabled() { for path in sess.get_tools_search_paths(false) { cmd.arg({ let mut arg = OsString::from("-B"); @@ -2990,7 +2999,7 @@ fn add_lld_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { } // 2. Implement the "linker flavor" part of this feature by asking `cc` to use some kind of - // `lld` as the linker. + // `lld` as the linker. cmd.arg("-fuse-ld=lld"); if !flavor.is_gnu() { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 11afe0fbc3c..09434513e31 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -626,6 +626,15 @@ impl<'a> Linker for GccLinker<'a> { self.linker_arg("--strip-all"); } } + match self.sess.opts.unstable_opts.debuginfo_compression { + config::DebugInfoCompression::None => {} + config::DebugInfoCompression::Zlib => { + self.linker_arg("--compress-debug-sections=zlib"); + } + config::DebugInfoCompression::Zstd => { + self.linker_arg("--compress-debug-sections=zstd"); + } + } } fn no_crt_objects(&mut self) { diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index f192747c8ab..3d6a2124334 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -26,7 +26,6 @@ use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::middle::exported_symbols::SymbolExportInfo; use rustc_middle::ty::TyCtxt; -use rustc_session::cgu_reuse_tracker::CguReuseTracker; use rustc_session::config::{self, CrateType, Lto, OutFileName, OutputFilenames, OutputType}; use rustc_session::config::{Passes, SwitchWithOptPath}; use rustc_session::Session; @@ -366,8 +365,6 @@ pub struct CodegenContext<B: WriteBackendMethods> { /// The incremental compilation session directory, or None if we are not /// compiling incrementally pub incr_comp_session_dir: Option<PathBuf>, - /// Used to update CGU re-use information during the thinlto phase. - pub cgu_reuse_tracker: CguReuseTracker, /// Channel back to the main control thread to send messages to pub coordinator_send: Sender<Box<dyn Any + Send>>, } @@ -1119,7 +1116,6 @@ fn start_executing_work<B: ExtraBackendMethods>( remark: sess.opts.cg.remark.clone(), remark_dir, incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()), - cgu_reuse_tracker: sess.cgu_reuse_tracker.clone(), coordinator_send, expanded_args: tcx.sess.expanded_args.clone(), diag_emitter: shared_emitter.clone(), @@ -1969,8 +1965,6 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> { } }); - sess.cgu_reuse_tracker.check_expected_reuse(sess); - sess.abort_if_errors(); let work_products = diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 1e4ea73a172..198e5696357 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -1,3 +1,4 @@ +use crate::assert_module_sources::CguReuse; use crate::back::link::are_upstream_rust_objects_already_included; use crate::back::metadata::create_compressed_metadata_file; use crate::back::write::{ @@ -31,7 +32,6 @@ use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; use rustc_middle::query::Providers; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; -use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{self, CrateType, EntryFnType, OutputType}; use rustc_session::Session; use rustc_span::symbol::sym; @@ -683,6 +683,13 @@ pub fn codegen_crate<B: ExtraBackendMethods>( codegen_units.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect::<Vec<_>>() }); + crate::assert_module_sources::assert_module_sources(tcx, &|cgu_reuse_tracker| { + for (i, cgu) in codegen_units.iter().enumerate() { + let cgu_reuse = cgu_reuse[i]; + cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse); + } + }); + let mut total_codegen_time = Duration::new(0, 0); let start_rss = tcx.sess.opts.unstable_opts.time_passes.then(|| get_resident_set_size()); @@ -727,7 +734,6 @@ pub fn codegen_crate<B: ExtraBackendMethods>( ongoing_codegen.check_for_errors(tcx.sess); let cgu_reuse = cgu_reuse[i]; - tcx.sess.cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse); match cgu_reuse { CguReuse::No => { @@ -994,7 +1000,7 @@ pub fn provide(providers: &mut Providers) { }; } -fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse { +pub fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse { if !tcx.dep_graph.is_fully_enabled() { return CguReuse::No; } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 59efe4cd3cc..2e0840f2d1b 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -238,8 +238,13 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { && let Some(fn_sig) = fn_sig() && fn_sig.skip_binder().abi() != abi::Abi::Rust { - struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI") - .emit(); + struct_span_err!( + tcx.sess, + attr.span, + E0737, + "`#[track_caller]` requires Rust ABI" + ) + .emit(); } if is_closure && !tcx.features().closure_track_caller @@ -435,17 +440,18 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { && let [item] = items.as_slice() && let Some((sym::align, literal)) = item.name_value_literal() { - rustc_attr::parse_alignment(&literal.kind).map_err(|msg| { - struct_span_err!( - tcx.sess.diagnostic(), - attr.span, - E0589, - "invalid `repr(align)` attribute: {}", - msg - ) - .emit(); - }) - .ok() + rustc_attr::parse_alignment(&literal.kind) + .map_err(|msg| { + struct_span_err!( + tcx.sess.diagnostic(), + attr.span, + E0589, + "invalid `repr(align)` attribute: {}", + msg + ) + .emit(); + }) + .ok() } else { None }; @@ -626,10 +632,7 @@ fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool { && let ty::AssocItemContainer::ImplContainer = impl_item.container && let Some(trait_item) = impl_item.trait_item_def_id { - return tcx - .codegen_fn_attrs(trait_item) - .flags - .intersects(CodegenFnAttrFlags::TRACK_CALLER); + return tcx.codegen_fn_attrs(trait_item).flags.intersects(CodegenFnAttrFlags::TRACK_CALLER); } false diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 39b2fa37fbf..ed6ac9f9c5d 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1,5 +1,6 @@ //! Errors emitted by codegen_ssa +use crate::assert_module_sources::CguReuse; use crate::back::command::Command; use crate::fluent_generated as fluent; use rustc_errors::{ @@ -17,6 +18,74 @@ use std::path::{Path, PathBuf}; use std::process::ExitStatus; #[derive(Diagnostic)] +#[diag(codegen_ssa_incorrect_cgu_reuse_type)] +pub struct IncorrectCguReuseType<'a> { + #[primary_span] + pub span: Span, + pub cgu_user_name: &'a str, + pub actual_reuse: CguReuse, + pub expected_reuse: CguReuse, + pub at_least: u8, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_cgu_not_recorded)] +pub struct CguNotRecorded<'a> { + pub cgu_user_name: &'a str, + pub cgu_name: &'a str, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_unknown_reuse_kind)] +pub struct UnknownReuseKind { + #[primary_span] + pub span: Span, + pub kind: Symbol, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_missing_query_depgraph)] +pub struct MissingQueryDepGraph { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_malformed_cgu_name)] +pub struct MalformedCguName { + #[primary_span] + pub span: Span, + pub user_path: String, + pub crate_name: String, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_no_module_named)] +pub struct NoModuleNamed<'a> { + #[primary_span] + pub span: Span, + pub user_path: &'a str, + pub cgu_name: Symbol, + pub cgu_names: String, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_field_associated_value_expected)] +pub struct FieldAssociatedValueExpected { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_no_field)] +pub struct NoField { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(Diagnostic)] #[diag(codegen_ssa_lib_def_write_failure)] pub struct LibDefWriteFailure { pub error: Error, diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index f6186a290f8..156c2904f40 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -1,4 +1,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), allow(internal_features))] #![feature(associated_type_bounds)] #![feature(box_patterns)] #![feature(if_let_guard)] @@ -43,6 +46,7 @@ use std::collections::BTreeSet; use std::io; use std::path::{Path, PathBuf}; +pub mod assert_module_sources; pub mod back; pub mod base; pub mod codegen_attrs; diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index a0cb97d51a0..60620f26bbb 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1555,7 +1555,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } fn terminate_block(&mut self, reason: UnwindTerminateReason) -> Bx::BasicBlock { - if let Some((cached_bb, cached_reason)) = self.terminate_block && reason == cached_reason { + if let Some((cached_bb, cached_reason)) = self.terminate_block + && reason == cached_reason + { return cached_bb; } diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 8efef440522..136d06d561a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -117,9 +117,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { sym::vtable_size => { let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128; bx.range_metadata(value, WrappingRange { start: 0, end: size_bound }); - }, + } // Alignment is always nonzero. - sym::vtable_align => bx.range_metadata(value, WrappingRange { start: 1, end: !0 }), + sym::vtable_align => { + bx.range_metadata(value, WrappingRange { start: 1, end: !0 }) + } _ => {} } value @@ -220,9 +222,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } else { bx.exactudiv(args[0].immediate(), args[1].immediate()) } - }, + } None => { - bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty }); + bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType { + span, + name, + ty, + }); return; } } @@ -238,7 +244,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => bug!(), }, None => { - bx.tcx().sess.emit_err(InvalidMonomorphization::BasicFloatType { span, name, ty: arg_tys[0] }); + bx.tcx().sess.emit_err(InvalidMonomorphization::BasicFloatType { + span, + name, + ty: arg_tys[0], + }); return; } } @@ -246,11 +256,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { sym::float_to_int_unchecked => { if float_type_width(arg_tys[0]).is_none() { - bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked { span, ty: arg_tys[0] }); + bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked { + span, + ty: arg_tys[0], + }); return; } let Some((_width, signed)) = int_type_width_signed(ret_ty, bx.tcx()) else { - bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked { span, ty: ret_ty }); + bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked { + span, + ty: ret_ty, + }); return; }; if signed { @@ -299,7 +315,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; let invalid_monomorphization = |ty| { - bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty }); + bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType { + span, + name, + ty, + }); }; match instruction { @@ -319,7 +339,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { cmp = bx.ptrtoint(cmp, bx.type_isize()); src = bx.ptrtoint(src, bx.type_isize()); } - let pair = bx.atomic_cmpxchg(dst, cmp, src, parse_ordering(bx, success), parse_ordering(bx, failure), weak); + let pair = bx.atomic_cmpxchg( + dst, + cmp, + src, + parse_ordering(bx, success), + parse_ordering(bx, failure), + weak, + ); let val = bx.extract_value(pair, 0); let success = bx.extract_value(pair, 1); let val = bx.from_immediate(val); @@ -345,11 +372,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Some platforms do not support atomic operations on pointers, // so we cast to integer first... let llty = bx.type_isize(); - let result = bx.atomic_load(llty, source, parse_ordering(bx, ordering), size); + let result = bx.atomic_load( + llty, + source, + parse_ordering(bx, ordering), + size, + ); // ... and then cast the result back to a pointer bx.inttoptr(result, bx.backend_type(layout)) } else { - bx.atomic_load(bx.backend_type(layout), source, parse_ordering(bx, ordering), size) + bx.atomic_load( + bx.backend_type(layout), + source, + parse_ordering(bx, ordering), + size, + ) } } else { return invalid_monomorphization(ty); @@ -375,12 +412,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } "fence" => { - bx.atomic_fence(parse_ordering(bx, ordering), SynchronizationScope::CrossThread); + bx.atomic_fence( + parse_ordering(bx, ordering), + SynchronizationScope::CrossThread, + ); return; } "singlethreadfence" => { - bx.atomic_fence(parse_ordering(bx, ordering), SynchronizationScope::SingleThread); + bx.atomic_fence( + parse_ordering(bx, ordering), + SynchronizationScope::SingleThread, + ); return; } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index fc8d3389102..f591afaaaf4 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -239,17 +239,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; if let OperandValueKind::Immediate(out_scalar) = cast_kind && in_scalar.size(self.cx) == out_scalar.size(self.cx) - { - let operand_bty = bx.backend_type(operand.layout); - let cast_bty = bx.backend_type(cast); - Some(OperandValue::Immediate(self.transmute_immediate( - bx, - imm, - in_scalar, - operand_bty, - out_scalar, - cast_bty, - ))) + { + let operand_bty = bx.backend_type(operand.layout); + let cast_bty = bx.backend_type(cast); + Some(OperandValue::Immediate(self.transmute_immediate( + bx, + imm, + in_scalar, + operand_bty, + out_scalar, + cast_bty, + ))) } else { None } diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index d23e2a9f3e4..f926da464e1 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -1,11 +1,15 @@ const_eval_address_space_full = there are no more free addresses in the address space -const_eval_align_check_failed = accessing memory with alignment {$has}, but alignment {$required} is required + const_eval_align_offset_invalid_align = `align_offset` called with non-power-of-two align: {$target_align} const_eval_alignment_check_failed = - accessing memory with alignment {$has}, but alignment {$required} is required + {$msg -> + [AccessedPtr] accessing memory + *[other] accessing memory based on pointer + } with alignment {$has}, but alignment {$required} is required + const_eval_already_reported = an error has already been reported elsewhere (this should not usually be printed) const_eval_assume_false = @@ -61,7 +65,6 @@ const_eval_deref_coercion_non_const = .target_note = deref defined here const_eval_deref_function_pointer = accessing {$allocation} which contains a function -const_eval_deref_test = dereferencing pointer failed const_eval_deref_vtable_pointer = accessing {$allocation} which contains a vtable const_eval_different_allocations = diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 3d758cd01d3..6b612c34837 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -1,5 +1,4 @@ -use crate::const_eval::CheckAlignment; -use crate::errors::ConstEvalError; +use std::mem; use either::{Left, Right}; @@ -15,7 +14,9 @@ use rustc_span::source_map::Span; use rustc_target::abi::{self, Abi}; use super::{CanAccessStatics, CompileTimeEvalContext, CompileTimeInterpreter}; +use crate::const_eval::CheckAlignment; use crate::errors; +use crate::errors::ConstEvalError; use crate::interpret::eval_nullary_intrinsic; use crate::interpret::{ intern_const_alloc_recursive, CtfeValidationMode, GlobalId, Immediate, InternKind, InterpCx, @@ -74,9 +75,9 @@ fn eval_body_using_ecx<'mir, 'tcx>( None => InternKind::Constant, } }; - ecx.machine.check_alignment = CheckAlignment::No; // interning doesn't need to respect alignment + let check_alignment = mem::replace(&mut ecx.machine.check_alignment, CheckAlignment::No); // interning doesn't need to respect alignment intern_const_alloc_recursive(ecx, intern_kind, &ret)?; - // we leave alignment checks off, since this `ecx` will not be used for further evaluation anyway + ecx.machine.check_alignment = check_alignment; debug!("eval_body_using_ecx done: {:?}", ret); Ok(ret) @@ -290,14 +291,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>( key.param_env, // Statics (and promoteds inside statics) may access other statics, because unlike consts // they do not have to behave "as if" they were evaluated at runtime. - CompileTimeInterpreter::new( - CanAccessStatics::from(is_static), - if tcx.sess.opts.unstable_opts.extra_const_ub_checks { - CheckAlignment::Error - } else { - CheckAlignment::FutureIncompat - }, - ), + CompileTimeInterpreter::new(CanAccessStatics::from(is_static), CheckAlignment::Error), ); let res = ecx.load_mir(cid.instance.def, cid.promoted); diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index 4ee4ebbb9e4..9e992637f46 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -39,8 +39,13 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness { hir::Node::Ctor(_) | hir::Node::AnonConst(_) | hir::Node::ConstBlock(_) - | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => hir::Constness::Const, - hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => tcx.generics_of(def_id).host_effect_index.map_or(hir::Constness::NotConst, |_| hir::Constness::Const), + | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => { + hir::Constness::Const + } + hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => tcx + .generics_of(def_id) + .host_effect_index + .map_or(hir::Constness::NotConst, |_| hir::Constness::Const), hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => { // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other // foreign items cannot be evaluated at compile-time. diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 865e01d0aee..166d3d45e79 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -1,10 +1,9 @@ use rustc_hir::def::DefKind; -use rustc_hir::{LangItem, CRATE_HIR_ID}; +use rustc_hir::LangItem; use rustc_middle::mir; use rustc_middle::mir::interpret::PointerArithmetic; use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout}; use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::lint::builtin::INVALID_ALIGNMENT; use std::borrow::Borrow; use std::hash::Hash; use std::ops::ControlFlow; @@ -21,11 +20,11 @@ use rustc_target::abi::{Align, Size}; use rustc_target::spec::abi::Abi as CallAbi; use crate::errors::{LongRunning, LongRunningWarn}; +use crate::fluent_generated as fluent; use crate::interpret::{ self, compile_time_machine, AllocId, ConstAllocation, FnArg, FnVal, Frame, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, Scalar, }; -use crate::{errors, fluent_generated as fluent}; use super::error::*; @@ -65,22 +64,11 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> { #[derive(Copy, Clone)] pub enum CheckAlignment { - /// Ignore alignment when following relocations. + /// Ignore all alignment requirements. /// This is mainly used in interning. No, /// Hard error when dereferencing a misaligned pointer. Error, - /// Emit a future incompat lint when dereferencing a misaligned pointer. - FutureIncompat, -} - -impl CheckAlignment { - pub fn should_check(&self) -> bool { - match self { - CheckAlignment::No => false, - CheckAlignment::Error | CheckAlignment::FutureIncompat => true, - } - } } #[derive(Copy, Clone, PartialEq)] @@ -358,8 +346,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error #[inline(always)] - fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment { - ecx.machine.check_alignment + fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + matches!(ecx.machine.check_alignment, CheckAlignment::Error) } #[inline(always)] @@ -367,39 +355,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks || layout.abi.is_uninhabited() } - fn alignment_check_failed( - ecx: &InterpCx<'mir, 'tcx, Self>, - has: Align, - required: Align, - check: CheckAlignment, - ) -> InterpResult<'tcx, ()> { - let err = err_ub!(AlignmentCheckFailed { has, required }).into(); - match check { - CheckAlignment::Error => Err(err), - CheckAlignment::No => span_bug!( - ecx.cur_span(), - "`alignment_check_failed` called when no alignment check requested" - ), - CheckAlignment::FutureIncompat => { - let (_, backtrace) = err.into_parts(); - backtrace.print_backtrace(); - let (span, frames) = super::get_span_and_frames(&ecx); - - ecx.tcx.emit_spanned_lint( - INVALID_ALIGNMENT, - ecx.stack().iter().find_map(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID), - span, - errors::AlignmentCheckFailed { - has: has.bytes(), - required: required.bytes(), - frames, - }, - ); - Ok(()) - } - } - } - fn load_mir( ecx: &InterpCx<'mir, 'tcx, Self>, instance: ty::InstanceDef<'tcx>, diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index b1599dd6894..cc8f3387238 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -5,8 +5,9 @@ use rustc_errors::{ use rustc_hir::ConstContext; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::mir::interpret::{ - CheckInAllocMsg, ExpectedKind, InterpError, InvalidMetaKind, InvalidProgramInfo, PointerKind, - ResourceExhaustionInfo, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, + CheckInAllocMsg, ExpectedKind, InterpError, InvalidMetaKind, InvalidProgramInfo, Misalignment, + PointerKind, ResourceExhaustionInfo, UndefinedBehaviorInfo, UnsupportedOpInfo, + ValidationErrorInfo, }; use rustc_middle::ty::{self, Ty}; use rustc_span::Span; @@ -389,15 +390,6 @@ pub struct LiveDrop<'tcx> { pub dropped_at: Option<Span>, } -#[derive(LintDiagnostic)] -#[diag(const_eval_align_check_failed)] -pub struct AlignmentCheckFailed { - pub has: u64, - pub required: u64, - #[subdiagnostic] - pub frames: Vec<FrameNote>, -} - #[derive(Diagnostic)] #[diag(const_eval_error, code = "E0080")] pub struct ConstEvalError { @@ -459,7 +451,6 @@ fn bad_pointer_message(msg: CheckInAllocMsg, handler: &Handler) -> String { use crate::fluent_generated::*; let msg = match msg { - CheckInAllocMsg::DerefTest => const_eval_deref_test, CheckInAllocMsg::MemoryAccessTest => const_eval_memory_access_test, CheckInAllocMsg::PointerArithmeticTest => const_eval_pointer_arithmetic_test, CheckInAllocMsg::OffsetFromTest => const_eval_offset_from_test, @@ -568,9 +559,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { builder.set_arg("bad_pointer_message", bad_pointer_message(msg, handler)); } - AlignmentCheckFailed { required, has } => { + AlignmentCheckFailed(Misalignment { required, has }, msg) => { builder.set_arg("required", required.bytes()); builder.set_arg("has", has.bytes()); + builder.set_arg("msg", format!("{msg:?}")); } WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => { builder.set_arg("allocation", alloc); diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index b9f88cf6352..b9557eaf6ab 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -311,6 +311,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { F: Float + Into<Scalar<M::Provenance>> + FloatConvert<Single> + FloatConvert<Double>, { use rustc_type_ir::sty::TyKind::*; + + fn adjust_nan< + 'mir, + 'tcx: 'mir, + M: Machine<'mir, 'tcx>, + F1: rustc_apfloat::Float + FloatConvert<F2>, + F2: rustc_apfloat::Float, + >( + ecx: &InterpCx<'mir, 'tcx, M>, + f1: F1, + f2: F2, + ) -> F2 { + if f2.is_nan() { M::generate_nan(ecx, &[f1]) } else { f2 } + } + match *dest_ty.kind() { // float -> uint Uint(t) => { @@ -330,9 +345,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Scalar::from_int(v, size) } // float -> f32 - Float(FloatTy::F32) => Scalar::from_f32(f.convert(&mut false).value), + Float(FloatTy::F32) => { + Scalar::from_f32(adjust_nan(self, f, f.convert(&mut false).value)) + } // float -> f64 - Float(FloatTy::F64) => Scalar::from_f64(f.convert(&mut false).value), + Float(FloatTy::F64) => { + Scalar::from_f64(adjust_nan(self, f, f.convert(&mut false).value)) + } // That's it. _ => span_bug!(self.cur_span(), "invalid float to {} cast", dest_ty), } diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 8c0009cfdfd..fd89e34204f 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -161,7 +161,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory #[inline(always)] fn ecx(&self) -> &InterpCx<'mir, 'tcx, M> { - &self.ecx + self.ecx } fn visit_value(&mut self, mplace: &MPlaceTy<'tcx>) -> InterpResult<'tcx> { @@ -259,7 +259,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory // to avoid could be expensive: on the potentially larger types, arrays and slices, // rather than on all aggregates unconditionally. if matches!(mplace.layout.ty.kind(), ty::Array(..) | ty::Slice(..)) { - let Some((size, align)) = self.ecx.size_and_align_of_mplace(&mplace)? else { + let Some((size, _align)) = self.ecx.size_and_align_of_mplace(&mplace)? else { // We do the walk if we can't determine the size of the mplace: we may be // dealing with extern types here in the future. return Ok(true); @@ -267,7 +267,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory // If there is no provenance in this allocation, it does not contain references // that point to another allocation, and we can avoid the interning walk. - if let Some(alloc) = self.ecx.get_ptr_alloc(mplace.ptr(), size, align)? { + if let Some(alloc) = self.ecx.get_ptr_alloc(mplace.ptr(), size)? { if !alloc.has_provenance() { return Ok(false); } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 2c6a4de456d..b7106c37c7b 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::layout::{LayoutOf as _, ValidityRequirement}; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; -use rustc_target::abi::{Abi, Align, Primitive, Size}; +use rustc_target::abi::{Abi, Primitive, Size}; use super::{ util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy, @@ -349,10 +349,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Check that the range between them is dereferenceable ("in-bounds or one past the // end of the same allocation"). This is like the check in ptr_offset_inbounds. let min_ptr = if dist >= 0 { b } else { a }; - self.check_ptr_access_align( + self.check_ptr_access( min_ptr, Size::from_bytes(dist.unsigned_abs()), - Align::ONE, CheckInAllocMsg::OffsetFromTest, )?; @@ -500,6 +499,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { b: &ImmTy<'tcx, M::Provenance>, dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { + assert_eq!(a.layout.ty, b.layout.ty); + assert!(matches!(a.layout.ty.kind(), ty::Int(..) | ty::Uint(..))); + // Performs an exact division, resulting in undefined behavior where // `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`. // First, check x % y != 0 (or if that computation overflows). @@ -522,7 +524,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { l: &ImmTy<'tcx, M::Provenance>, r: &ImmTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, Scalar<M::Provenance>> { + assert_eq!(l.layout.ty, r.layout.ty); + assert!(matches!(l.layout.ty.kind(), ty::Int(..) | ty::Uint(..))); assert!(matches!(mir_op, BinOp::Add | BinOp::Sub)); + let (val, overflowed) = self.overflowing_binary_op(mir_op, l, r)?; Ok(if overflowed { let size = l.layout.size; @@ -565,16 +570,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn ptr_offset_inbounds( &self, ptr: Pointer<Option<M::Provenance>>, - pointee_ty: Ty<'tcx>, - offset_count: i64, + offset_bytes: i64, ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> { - // We cannot overflow i64 as a type's size must be <= isize::MAX. - let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); - // The computed offset, in bytes, must not overflow an isize. - // `checked_mul` enforces a too small bound, but no actual allocation can be big enough for - // the difference to be noticeable. - let offset_bytes = - offset_count.checked_mul(pointee_size).ok_or(err_ub!(PointerArithOverflow))?; // The offset being in bounds cannot rely on "wrapping around" the address space. // So, first rule out overflows in the pointer arithmetic. let offset_ptr = ptr.signed_offset(offset_bytes, self)?; @@ -583,10 +580,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // pointers to be properly aligned (unlike a read/write operation). let min_ptr = if offset_bytes >= 0 { ptr } else { offset_ptr }; // This call handles checking for integer/null pointers. - self.check_ptr_access_align( + self.check_ptr_access( min_ptr, Size::from_bytes(offset_bytes.unsigned_abs()), - Align::ONE, CheckInAllocMsg::PointerArithmeticTest, )?; Ok(offset_ptr) @@ -615,7 +611,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let src = self.read_pointer(src)?; let dst = self.read_pointer(dst)?; - self.mem_copy(src, align, dst, align, size, nonoverlapping) + self.check_ptr_align(src, align)?; + self.check_ptr_align(dst, align)?; + + self.mem_copy(src, dst, size, nonoverlapping) } pub(crate) fn write_bytes_intrinsic( @@ -671,7 +670,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { size| -> InterpResult<'tcx, &[u8]> { let ptr = this.read_pointer(op)?; - let Some(alloc_ref) = self.get_ptr_alloc(ptr, size, Align::ONE)? else { + let Some(alloc_ref) = self.get_ptr_alloc(ptr, size)? else { // zero-sized access return Ok(&[]); }; diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index aaa674a598f..61fe9151d8b 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -6,16 +6,15 @@ use std::borrow::{Borrow, Cow}; use std::fmt::Debug; use std::hash::Hash; +use rustc_apfloat::{Float, FloatConvert}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_middle::mir; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::def_id::DefId; -use rustc_target::abi::{Align, Size}; +use rustc_target::abi::Size; use rustc_target::spec::abi::Abi as CallAbi; -use crate::const_eval::CheckAlignment; - use super::{ AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, FnArg, Frame, ImmTy, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, PlaceTy, Pointer, Provenance, @@ -134,7 +133,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { const POST_MONO_CHECKS: bool = true; /// Whether memory accesses should be alignment-checked. - fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment; + fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; /// Whether, when checking alignment, we should look at the actual address and thus support /// custom alignment logic based on whatever the integer address happens to be. @@ -142,13 +141,6 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { /// If this returns true, Provenance::OFFSET_IS_ADDR must be true. fn use_addr_for_alignment_check(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; - fn alignment_check_failed( - ecx: &InterpCx<'mir, 'tcx, Self>, - has: Align, - required: Align, - check: CheckAlignment, - ) -> InterpResult<'tcx, ()>; - /// Whether to enforce the validity invariant for a specific layout. fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool; @@ -240,6 +232,16 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { right: &ImmTy<'tcx, Self::Provenance>, ) -> InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)>; + /// Generate the NaN returned by a float operation, given the list of inputs. + /// (This is all inputs, not just NaN inputs!) + fn generate_nan<F1: Float + FloatConvert<F2>, F2: Float>( + _ecx: &InterpCx<'mir, 'tcx, Self>, + _inputs: &[F1], + ) -> F2 { + // By default we always return the preferred NaN. + F2::NAN + } + /// Called before writing the specified `local` of the `frame`. /// Since writing a ZST is not actually accessing memory or locals, this is never invoked /// for ZST reads. @@ -434,6 +436,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { place: &PlaceTy<'tcx, Self::Provenance>, ) -> InterpResult<'tcx> { // Without an aliasing model, all we can do is put `Uninit` into the place. + // Conveniently this also ensures that the place actually points to suitable memory. ecx.write_uninit(place) } diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index ce666e6af3b..5b31738e4e1 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -18,13 +18,12 @@ use rustc_middle::mir::display_allocation; use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; use rustc_target::abi::{Align, HasDataLayout, Size}; -use crate::const_eval::CheckAlignment; use crate::fluent_generated as fluent; use super::{ - alloc_range, AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg, - GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Provenance, - Scalar, + alloc_range, AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckAlignMsg, + CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Misalignment, Pointer, + PointerArithmetic, Provenance, Scalar, }; #[derive(Debug, PartialEq, Copy, Clone)] @@ -259,14 +258,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { None => self.get_alloc_raw(alloc_id)?.size(), }; // This will also call the access hooks. - self.mem_copy( - ptr, - Align::ONE, - new_ptr.into(), - Align::ONE, - old_size.min(new_size), - /*nonoverlapping*/ true, - )?; + self.mem_copy(ptr, new_ptr.into(), old_size.min(new_size), /*nonoverlapping*/ true)?; self.deallocate_ptr(ptr, old_size_and_align, kind)?; Ok(new_ptr) @@ -368,13 +360,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, ptr: Pointer<Option<M::Provenance>>, size: Size, - align: Align, ) -> InterpResult<'tcx, Option<(AllocId, Size, M::ProvenanceExtra)>> { self.check_and_deref_ptr( ptr, size, - align, - M::enforce_alignment(self), CheckInAllocMsg::MemoryAccessTest, |alloc_id, offset, prov| { let (size, align) = self @@ -384,43 +373,31 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) } - /// Check if the given pointer points to live memory of given `size` and `align` - /// (ignoring `M::enforce_alignment`). The caller can control the error message for the - /// out-of-bounds case. + /// Check if the given pointer points to live memory of the given `size`. + /// The caller can control the error message for the out-of-bounds case. #[inline(always)] - pub fn check_ptr_access_align( + pub fn check_ptr_access( &self, ptr: Pointer<Option<M::Provenance>>, size: Size, - align: Align, msg: CheckInAllocMsg, ) -> InterpResult<'tcx> { - self.check_and_deref_ptr( - ptr, - size, - align, - CheckAlignment::Error, - msg, - |alloc_id, _, _| { - let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?; - Ok((size, align, ())) - }, - )?; + self.check_and_deref_ptr(ptr, size, msg, |alloc_id, _, _| { + let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?; + Ok((size, align, ())) + })?; Ok(()) } /// Low-level helper function to check if a ptr is in-bounds and potentially return a reference /// to the allocation it points to. Supports both shared and mutable references, as the actual - /// checking is offloaded to a helper closure. `align` defines whether and which alignment check - /// is done. + /// checking is offloaded to a helper closure. /// /// If this returns `None`, the size is 0; it can however return `Some` even for size 0. fn check_and_deref_ptr<T>( &self, ptr: Pointer<Option<M::Provenance>>, size: Size, - align: Align, - check: CheckAlignment, msg: CheckInAllocMsg, alloc_size: impl FnOnce( AllocId, @@ -435,14 +412,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if size.bytes() > 0 || addr == 0 { throw_ub!(DanglingIntPointer(addr, msg)); } - // Must be aligned. - if check.should_check() { - self.check_offset_align(addr, align, check)?; - } None } Ok((alloc_id, offset, prov)) => { - let (alloc_size, alloc_align, ret_val) = alloc_size(alloc_id, offset, prov)?; + let (alloc_size, _alloc_align, ret_val) = alloc_size(alloc_id, offset, prov)?; // Test bounds. This also ensures non-null. // It is sufficient to check this for the end pointer. Also check for overflow! if offset.checked_add(size, &self.tcx).map_or(true, |end| end > alloc_size) { @@ -458,20 +431,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if M::Provenance::OFFSET_IS_ADDR { assert_ne!(ptr.addr(), Size::ZERO); } - // Test align. Check this last; if both bounds and alignment are violated - // we want the error to be about the bounds. - if check.should_check() { - if M::use_addr_for_alignment_check(self) { - // `use_addr_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true. - self.check_offset_align(ptr.addr().bytes(), align, check)?; - } else { - // Check allocation alignment and offset alignment. - if alloc_align.bytes() < align.bytes() { - M::alignment_check_failed(self, alloc_align, align, check)?; - } - self.check_offset_align(offset.bytes(), align, check)?; - } - } // We can still be zero-sized in this branch, in which case we have to // return `None`. @@ -480,19 +439,65 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }) } - fn check_offset_align( + pub(super) fn check_misalign( &self, - offset: u64, - align: Align, - check: CheckAlignment, + misaligned: Option<Misalignment>, + msg: CheckAlignMsg, ) -> InterpResult<'tcx> { - if offset % align.bytes() == 0 { - Ok(()) - } else { - // The biggest power of two through which `offset` is divisible. - let offset_pow2 = 1 << offset.trailing_zeros(); - M::alignment_check_failed(self, Align::from_bytes(offset_pow2).unwrap(), align, check) + if let Some(misaligned) = misaligned { + throw_ub!(AlignmentCheckFailed(misaligned, msg)) } + Ok(()) + } + + pub(super) fn is_ptr_misaligned( + &self, + ptr: Pointer<Option<M::Provenance>>, + align: Align, + ) -> Option<Misalignment> { + if !M::enforce_alignment(self) || align.bytes() == 1 { + return None; + } + + #[inline] + fn offset_misalignment(offset: u64, align: Align) -> Option<Misalignment> { + if offset % align.bytes() == 0 { + None + } else { + // The biggest power of two through which `offset` is divisible. + let offset_pow2 = 1 << offset.trailing_zeros(); + Some(Misalignment { has: Align::from_bytes(offset_pow2).unwrap(), required: align }) + } + } + + match self.ptr_try_get_alloc_id(ptr) { + Err(addr) => offset_misalignment(addr, align), + Ok((alloc_id, offset, _prov)) => { + let (_size, alloc_align, _kind) = self.get_alloc_info(alloc_id); + if M::use_addr_for_alignment_check(self) { + // `use_addr_for_alignment_check` can only be true if `OFFSET_IS_ADDR` is true. + offset_misalignment(ptr.addr().bytes(), align) + } else { + // Check allocation alignment and offset alignment. + if alloc_align.bytes() < align.bytes() { + Some(Misalignment { has: alloc_align, required: align }) + } else { + offset_misalignment(offset.bytes(), align) + } + } + } + } + } + + /// Checks a pointer for misalignment. + /// + /// The error assumes this is checking the pointer used directly for an access. + pub fn check_ptr_align( + &self, + ptr: Pointer<Option<M::Provenance>>, + align: Align, + ) -> InterpResult<'tcx> { + self.check_misalign(self.is_ptr_misaligned(ptr, align), CheckAlignMsg::AccessedPtr) } } @@ -550,17 +555,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) } - /// Get the base address for the bytes in an `Allocation` specified by the - /// `AllocID` passed in; error if no such allocation exists. - /// - /// It is up to the caller to take sufficient care when using this address: - /// there could be provenance or uninit memory in there, and other memory - /// accesses could invalidate the exposed pointer. - pub fn alloc_base_addr(&self, id: AllocId) -> InterpResult<'tcx, *const u8> { - let alloc = self.get_alloc_raw(id)?; - Ok(alloc.base_addr()) - } - /// Gives raw access to the `Allocation`, without bounds or alignment checks. /// The caller is responsible for calling the access hooks! /// @@ -598,19 +592,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } - /// "Safe" (bounds and align-checked) allocation access. + /// Bounds-checked *but not align-checked* allocation access. pub fn get_ptr_alloc<'a>( &'a self, ptr: Pointer<Option<M::Provenance>>, size: Size, - align: Align, ) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>> { let ptr_and_alloc = self.check_and_deref_ptr( ptr, size, - align, - M::enforce_alignment(self), CheckInAllocMsg::MemoryAccessTest, |alloc_id, offset, prov| { let alloc = self.get_alloc_raw(alloc_id)?; @@ -671,15 +662,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok((alloc, &mut self.machine)) } - /// "Safe" (bounds and align-checked) allocation access. + /// Bounds-checked *but not align-checked* allocation access. pub fn get_ptr_alloc_mut<'a>( &'a mut self, ptr: Pointer<Option<M::Provenance>>, size: Size, - align: Align, ) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>> { - let parts = self.get_ptr_access(ptr, size, align)?; + let parts = self.get_ptr_access(ptr, size)?; if let Some((alloc_id, offset, prov)) = parts { let tcx = *self.tcx; // FIXME: can we somehow avoid looking up the allocation twice here? @@ -1036,7 +1026,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ptr: Pointer<Option<M::Provenance>>, size: Size, ) -> InterpResult<'tcx, &[u8]> { - let Some(alloc_ref) = self.get_ptr_alloc(ptr, size, Align::ONE)? else { + let Some(alloc_ref) = self.get_ptr_alloc(ptr, size)? else { // zero-sized access return Ok(&[]); }; @@ -1062,7 +1052,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert_eq!(lower, len, "can only write iterators with a precise length"); let size = Size::from_bytes(len); - let Some(alloc_ref) = self.get_ptr_alloc_mut(ptr, size, Align::ONE)? else { + let Some(alloc_ref) = self.get_ptr_alloc_mut(ptr, size)? else { // zero-sized access assert_matches!(src.next(), None, "iterator said it was empty but returned an element"); return Ok(()); @@ -1087,29 +1077,25 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn mem_copy( &mut self, src: Pointer<Option<M::Provenance>>, - src_align: Align, dest: Pointer<Option<M::Provenance>>, - dest_align: Align, size: Size, nonoverlapping: bool, ) -> InterpResult<'tcx> { - self.mem_copy_repeatedly(src, src_align, dest, dest_align, size, 1, nonoverlapping) + self.mem_copy_repeatedly(src, dest, size, 1, nonoverlapping) } pub fn mem_copy_repeatedly( &mut self, src: Pointer<Option<M::Provenance>>, - src_align: Align, dest: Pointer<Option<M::Provenance>>, - dest_align: Align, size: Size, num_copies: u64, nonoverlapping: bool, ) -> InterpResult<'tcx> { let tcx = self.tcx; // We need to do our own bounds-checks. - let src_parts = self.get_ptr_access(src, size, src_align)?; - let dest_parts = self.get_ptr_access(dest, size * num_copies, dest_align)?; // `Size` multiplication + let src_parts = self.get_ptr_access(src, size)?; + let dest_parts = self.get_ptr_access(dest, size * num_copies)?; // `Size` multiplication // FIXME: we look up both allocations twice here, once before for the `check_ptr_access` // and once below to get the underlying `&[mut] Allocation`. diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index 69eb22028fa..13664456987 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -26,7 +26,7 @@ pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackP pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind}; pub use self::operand::{ImmTy, Immediate, OpTy, Readable}; pub use self::place::{MPlaceTy, MemPlaceMeta, PlaceTy, Writeable}; -pub use self::projection::Projectable; +pub use self::projection::{OffsetMode, Projectable}; pub use self::terminator::FnArg; pub use self::validity::{CtfeValidationMode, RefTracking}; pub use self::visitor::ValueVisitor; diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 99dba977a43..99424518ad4 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -10,11 +10,12 @@ use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter}; use rustc_middle::ty::{ConstInt, Ty, TyCtxt}; use rustc_middle::{mir, ty}; -use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size}; +use rustc_target::abi::{self, Abi, HasDataLayout, Size}; use super::{ alloc_range, from_known_layout, mir_assign_valid_types, AllocId, Frame, InterpCx, InterpResult, - MPlaceTy, Machine, MemPlace, MemPlaceMeta, PlaceTy, Pointer, Projectable, Provenance, Scalar, + MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode, PlaceTy, Pointer, Projectable, + Provenance, Scalar, }; /// An `Immediate` represents a single immediate self-contained Rust value. @@ -43,12 +44,16 @@ impl<Prov: Provenance> From<Scalar<Prov>> for Immediate<Prov> { } impl<Prov: Provenance> Immediate<Prov> { - pub fn from_pointer(ptr: Pointer<Prov>, cx: &impl HasDataLayout) -> Self { - Immediate::Scalar(Scalar::from_pointer(ptr, cx)) - } - - pub fn from_maybe_pointer(ptr: Pointer<Option<Prov>>, cx: &impl HasDataLayout) -> Self { - Immediate::Scalar(Scalar::from_maybe_pointer(ptr, cx)) + pub fn new_pointer_with_meta( + ptr: Pointer<Option<Prov>>, + meta: MemPlaceMeta<Prov>, + cx: &impl HasDataLayout, + ) -> Self { + let ptr = Scalar::from_maybe_pointer(ptr, cx); + match meta { + MemPlaceMeta::None => Immediate::from(ptr), + MemPlaceMeta::Meta(meta) => Immediate::ScalarPair(ptr, meta), + } } pub fn new_slice(ptr: Pointer<Option<Prov>>, len: u64, cx: &impl HasDataLayout) -> Self { @@ -219,6 +224,17 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { /// given layout. // Not called `offset` to avoid confusion with the trait method. fn offset_(&self, offset: Size, layout: TyAndLayout<'tcx>, cx: &impl HasDataLayout) -> Self { + debug_assert!(layout.is_sized(), "unsized immediates are not a thing"); + // `ImmTy` have already been checked to be in-bounds, so we can just check directly if this + // remains in-bounds. This cannot actually be violated since projections are type-checked + // and bounds-checked. + assert!( + offset + layout.size <= self.layout.size, + "attempting to project to field at offset {} with size {} into immediate with layout {:#?}", + offset.bytes(), + layout.size.bytes(), + self.layout, + ); // This makes several assumptions about what layouts we will encounter; we match what // codegen does as good as we can (see `extract_field` in `rustc_codegen_ssa/src/mir/operand.rs`). let inner_val: Immediate<_> = match (**self, self.layout.abi) { @@ -286,6 +302,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> { fn offset_with_meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( &self, offset: Size, + _mode: OffsetMode, meta: MemPlaceMeta<Prov>, layout: TyAndLayout<'tcx>, ecx: &InterpCx<'mir, 'tcx, M>, @@ -315,14 +332,6 @@ pub(super) enum Operand<Prov: Provenance = AllocId> { pub struct OpTy<'tcx, Prov: Provenance = AllocId> { op: Operand<Prov>, // Keep this private; it helps enforce invariants. pub layout: TyAndLayout<'tcx>, - /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: - /// it needs to have a different alignment than the field type would usually have. - /// So we represent this here with a separate field that "overwrites" `layout.align`. - /// This means `layout.align` should never be used for an `OpTy`! - /// `None` means "alignment does not matter since this is a by-value operand" - /// (`Operand::Immediate`); this field is only relevant for `Operand::Indirect`. - /// Also CTFE ignores alignment anyway, so this is for Miri only. - pub align: Option<Align>, } impl<Prov: Provenance> std::fmt::Debug for OpTy<'_, Prov> { @@ -338,18 +347,14 @@ impl<Prov: Provenance> std::fmt::Debug for OpTy<'_, Prov> { impl<'tcx, Prov: Provenance> From<ImmTy<'tcx, Prov>> for OpTy<'tcx, Prov> { #[inline(always)] fn from(val: ImmTy<'tcx, Prov>) -> Self { - OpTy { op: Operand::Immediate(val.imm), layout: val.layout, align: None } + OpTy { op: Operand::Immediate(val.imm), layout: val.layout } } } impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for OpTy<'tcx, Prov> { #[inline(always)] fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self { - OpTy { - op: Operand::Indirect(*mplace.mplace()), - layout: mplace.layout, - align: Some(mplace.align), - } + OpTy { op: Operand::Indirect(*mplace.mplace()), layout: mplace.layout } } } @@ -380,14 +385,14 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> { fn offset_with_meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( &self, offset: Size, + mode: OffsetMode, meta: MemPlaceMeta<Prov>, layout: TyAndLayout<'tcx>, ecx: &InterpCx<'mir, 'tcx, M>, ) -> InterpResult<'tcx, Self> { match self.as_mplace_or_imm() { - Left(mplace) => Ok(mplace.offset_with_meta(offset, meta, layout, ecx)?.into()), + Left(mplace) => Ok(mplace.offset_with_meta(offset, mode, meta, layout, ecx)?.into()), Right(imm) => { - debug_assert!(layout.is_sized(), "unsized immediates are not a thing"); assert_matches!(meta, MemPlaceMeta::None); // no place to store metadata here // Every part of an uninit is uninit. Ok(imm.offset_(offset, layout, ecx).into()) @@ -622,7 +627,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { throw_inval!(ConstPropNonsense); } } - Ok(OpTy { op, layout, align: Some(layout.align.abi) }) + Ok(OpTy { op, layout }) } /// Every place can be read from, so we can turn them into an operand. @@ -637,16 +642,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Right((frame, local, offset)) => { debug_assert!(place.layout.is_sized()); // only sized locals can ever be `Place::Local`. let base = self.local_to_op(&self.stack()[frame], local, None)?; - let mut field = match offset { + Ok(match offset { Some(offset) => base.offset(offset, place.layout, self)?, None => { // In the common case this hasn't been projected. debug_assert_eq!(place.layout, base.layout); base } - }; - field.align = Some(place.align); - Ok(field) + }) } } } @@ -734,27 +737,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }) }; let layout = from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty))?; - let op = match val_val { + let imm = match val_val { mir::ConstValue::Indirect { alloc_id, offset } => { // We rely on mutability being set correctly in that allocation to prevent writes // where none should happen. let ptr = self.global_base_pointer(Pointer::new(alloc_id, offset))?; - Operand::Indirect(MemPlace::from_ptr(ptr.into())) + return Ok(self.ptr_to_mplace(ptr.into(), layout).into()); } - mir::ConstValue::Scalar(x) => Operand::Immediate(adjust_scalar(x)?.into()), - mir::ConstValue::ZeroSized => Operand::Immediate(Immediate::Uninit), + mir::ConstValue::Scalar(x) => adjust_scalar(x)?.into(), + mir::ConstValue::ZeroSized => Immediate::Uninit, mir::ConstValue::Slice { data, meta } => { // We rely on mutability being set correctly in `data` to prevent writes // where none should happen. let ptr = Pointer::new(self.tcx.reserve_and_set_memory_alloc(data), Size::ZERO); - Operand::Immediate(Immediate::new_slice( - self.global_base_pointer(ptr)?.into(), - meta, - self, - )) + Immediate::new_slice(self.global_base_pointer(ptr)?.into(), meta, self) } }; - Ok(OpTy { op, layout, align: Some(layout.align.abi) }) + Ok(OpTy { op: Operand::Immediate(imm), layout }) } } @@ -767,6 +766,6 @@ mod size_asserts { static_assert_size!(Immediate, 48); static_assert_size!(ImmTy<'_>, 64); static_assert_size!(Operand, 56); - static_assert_size!(OpTy<'_>, 80); + static_assert_size!(OpTy<'_>, 72); // tidy-alphabetical-end } diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index b084864f3a7..a3ba9530f9d 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -1,7 +1,7 @@ -use rustc_apfloat::Float; +use rustc_apfloat::{Float, FloatConvert}; use rustc_middle::mir; use rustc_middle::mir::interpret::{InterpResult, Scalar}; -use rustc_middle::ty::layout::TyAndLayout; +use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, FloatTy, Ty}; use rustc_span::symbol::sym; use rustc_target::abi::Abi; @@ -104,7 +104,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { (ImmTy::from_bool(res, *self.tcx), false) } - fn binary_float_op<F: Float + Into<Scalar<M::Provenance>>>( + fn binary_float_op<F: Float + FloatConvert<F> + Into<Scalar<M::Provenance>>>( &self, bin_op: mir::BinOp, layout: TyAndLayout<'tcx>, @@ -113,6 +113,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> (ImmTy<'tcx, M::Provenance>, bool) { use rustc_middle::mir::BinOp::*; + // Performs appropriate non-deterministic adjustments of NaN results. + let adjust_nan = |f: F| -> F { + if f.is_nan() { M::generate_nan(self, &[l, r]) } else { f } + }; + let val = match bin_op { Eq => ImmTy::from_bool(l == r, *self.tcx), Ne => ImmTy::from_bool(l != r, *self.tcx), @@ -120,11 +125,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Le => ImmTy::from_bool(l <= r, *self.tcx), Gt => ImmTy::from_bool(l > r, *self.tcx), Ge => ImmTy::from_bool(l >= r, *self.tcx), - Add => ImmTy::from_scalar((l + r).value.into(), layout), - Sub => ImmTy::from_scalar((l - r).value.into(), layout), - Mul => ImmTy::from_scalar((l * r).value.into(), layout), - Div => ImmTy::from_scalar((l / r).value.into(), layout), - Rem => ImmTy::from_scalar((l % r).value.into(), layout), + Add => ImmTy::from_scalar(adjust_nan((l + r).value).into(), layout), + Sub => ImmTy::from_scalar(adjust_nan((l - r).value).into(), layout), + Mul => ImmTy::from_scalar(adjust_nan((l * r).value).into(), layout), + Div => ImmTy::from_scalar(adjust_nan((l / r).value).into(), layout), + Rem => ImmTy::from_scalar(adjust_nan((l % r).value).into(), layout), _ => span_bug!(self.cur_span(), "invalid float op: `{:?}`", bin_op), }; (val, false) @@ -332,7 +337,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let offset_count = right.to_scalar().to_target_isize(self)?; let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty; - let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?; + // We cannot overflow i64 as a type's size must be <= isize::MAX. + let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); + // The computed offset, in bytes, must not overflow an isize. + // `checked_mul` enforces a too small bound, but no actual allocation can be big enough for + // the difference to be noticeable. + let offset_bytes = + offset_count.checked_mul(pointee_size).ok_or(err_ub!(PointerArithOverflow))?; + + let offset_ptr = self.ptr_offset_inbounds(ptr, offset_bytes)?; Ok(( ImmTy::from_scalar(Scalar::from_maybe_pointer(offset_ptr, self), left.layout), false, @@ -456,6 +469,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok((ImmTy::from_bool(res, *self.tcx), false)) } ty::Float(fty) => { + // No NaN adjustment here, `-` is a bitwise operation! let res = match (un_op, fty) { (Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?), (Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?), diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 79448f07cae..09ffdec7de7 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -15,9 +15,9 @@ use rustc_middle::ty::Ty; use rustc_target::abi::{Abi, Align, FieldIdx, HasDataLayout, Size, FIRST_VARIANT}; use super::{ - alloc_range, mir_assign_valid_types, AllocId, AllocRef, AllocRefMut, CheckInAllocMsg, ImmTy, - Immediate, InterpCx, InterpResult, Machine, MemoryKind, OpTy, Operand, Pointer, - PointerArithmetic, Projectable, Provenance, Readable, Scalar, + alloc_range, mir_assign_valid_types, AllocId, AllocRef, AllocRefMut, CheckAlignMsg, ImmTy, + Immediate, InterpCx, InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy, + Operand, Pointer, PointerArithmetic, Projectable, Provenance, Readable, Scalar, }; #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] @@ -57,19 +57,11 @@ pub(super) struct MemPlace<Prov: Provenance = AllocId> { /// Must not be present for sized types, but can be missing for unsized types /// (e.g., `extern type`). pub meta: MemPlaceMeta<Prov>, + /// Stores whether this place was created based on a sufficiently aligned pointer. + misaligned: Option<Misalignment>, } impl<Prov: Provenance> MemPlace<Prov> { - #[inline(always)] - pub fn from_ptr(ptr: Pointer<Option<Prov>>) -> Self { - MemPlace { ptr, meta: MemPlaceMeta::None } - } - - #[inline(always)] - pub fn from_ptr_with_meta(ptr: Pointer<Option<Prov>>, meta: MemPlaceMeta<Prov>) -> Self { - MemPlace { ptr, meta } - } - /// Adjust the provenance of the main pointer (metadata is unaffected). pub fn map_provenance(self, f: impl FnOnce(Option<Prov>) -> Option<Prov>) -> Self { MemPlace { ptr: self.ptr.map_provenance(f), ..self } @@ -78,27 +70,32 @@ impl<Prov: Provenance> MemPlace<Prov> { /// Turn a mplace into a (thin or wide) pointer, as a reference, pointing to the same space. #[inline] pub fn to_ref(self, cx: &impl HasDataLayout) -> Immediate<Prov> { - match self.meta { - MemPlaceMeta::None => Immediate::from(Scalar::from_maybe_pointer(self.ptr, cx)), - MemPlaceMeta::Meta(meta) => { - Immediate::ScalarPair(Scalar::from_maybe_pointer(self.ptr, cx), meta) - } - } + Immediate::new_pointer_with_meta(self.ptr, self.meta, cx) } #[inline] // Not called `offset_with_meta` to avoid confusion with the trait method. - fn offset_with_meta_<'tcx>( + fn offset_with_meta_<'mir, 'tcx, M: Machine<'mir, 'tcx, Provenance = Prov>>( self, offset: Size, + mode: OffsetMode, meta: MemPlaceMeta<Prov>, - cx: &impl HasDataLayout, + ecx: &InterpCx<'mir, 'tcx, M>, ) -> InterpResult<'tcx, Self> { debug_assert!( !meta.has_meta() || self.meta.has_meta(), "cannot use `offset_with_meta` to add metadata to a place" ); - Ok(MemPlace { ptr: self.ptr.offset(offset, cx)?, meta }) + if offset > ecx.data_layout().max_size_of_val() { + throw_ub!(PointerArithOverflow); + } + let ptr = match mode { + OffsetMode::Inbounds => { + ecx.ptr_offset_inbounds(self.ptr, offset.bytes().try_into().unwrap())? + } + OffsetMode::Wrapping => self.ptr.wrapping_offset(offset, ecx), + }; + Ok(MemPlace { ptr, meta, misaligned: self.misaligned }) } } @@ -107,11 +104,6 @@ impl<Prov: Provenance> MemPlace<Prov> { pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> { mplace: MemPlace<Prov>, pub layout: TyAndLayout<'tcx>, - /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: - /// it needs to have a different alignment than the field type would usually have. - /// So we represent this here with a separate field that "overwrites" `layout.align`. - /// This means `layout.align` should never be used for a `MPlaceTy`! - pub align: Align, } impl<Prov: Provenance> std::fmt::Debug for MPlaceTy<'_, Prov> { @@ -133,25 +125,7 @@ impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> { assert!(layout.is_zst()); let align = layout.align.abi; let ptr = Pointer::from_addr_invalid(align.bytes()); // no provenance, absolute address - MPlaceTy { mplace: MemPlace { ptr, meta: MemPlaceMeta::None }, layout, align } - } - - #[inline] - pub fn from_aligned_ptr(ptr: Pointer<Option<Prov>>, layout: TyAndLayout<'tcx>) -> Self { - MPlaceTy { mplace: MemPlace::from_ptr(ptr), layout, align: layout.align.abi } - } - - #[inline] - pub fn from_aligned_ptr_with_meta( - ptr: Pointer<Option<Prov>>, - layout: TyAndLayout<'tcx>, - meta: MemPlaceMeta<Prov>, - ) -> Self { - MPlaceTy { - mplace: MemPlace::from_ptr_with_meta(ptr, meta), - layout, - align: layout.align.abi, - } + MPlaceTy { mplace: MemPlace { ptr, meta: MemPlaceMeta::None, misaligned: None }, layout } } /// Adjust the provenance of the main pointer (metadata is unaffected). @@ -189,15 +163,12 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { fn offset_with_meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( &self, offset: Size, + mode: OffsetMode, meta: MemPlaceMeta<Prov>, layout: TyAndLayout<'tcx>, ecx: &InterpCx<'mir, 'tcx, M>, ) -> InterpResult<'tcx, Self> { - Ok(MPlaceTy { - mplace: self.mplace.offset_with_meta_(offset, meta, ecx)?, - align: self.align.restrict_for_offset(offset), - layout, - }) + Ok(MPlaceTy { mplace: self.mplace.offset_with_meta_(offset, mode, meta, ecx)?, layout }) } fn to_op<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( @@ -228,11 +199,6 @@ pub(super) enum Place<Prov: Provenance = AllocId> { pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> { place: Place<Prov>, // Keep this private; it helps enforce invariants. pub layout: TyAndLayout<'tcx>, - /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct: - /// it needs to have a different alignment than the field type would usually have. - /// So we represent this here with a separate field that "overwrites" `layout.align`. - /// This means `layout.align` should never be used for a `PlaceTy`! - pub align: Align, } impl<Prov: Provenance> std::fmt::Debug for PlaceTy<'_, Prov> { @@ -248,7 +214,7 @@ impl<Prov: Provenance> std::fmt::Debug for PlaceTy<'_, Prov> { impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for PlaceTy<'tcx, Prov> { #[inline(always)] fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self { - PlaceTy { place: Place::Ptr(mplace.mplace), layout: mplace.layout, align: mplace.align } + PlaceTy { place: Place::Ptr(mplace.mplace), layout: mplace.layout } } } @@ -264,7 +230,7 @@ impl<'tcx, Prov: Provenance> PlaceTy<'tcx, Prov> { &self, ) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>)> { match self.place { - Place::Ptr(mplace) => Left(MPlaceTy { mplace, layout: self.layout, align: self.align }), + Place::Ptr(mplace) => Left(MPlaceTy { mplace, layout: self.layout }), Place::Local { frame, local, offset } => Right((frame, local, offset)), } } @@ -301,27 +267,27 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for PlaceTy<'tcx, Prov> { fn offset_with_meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( &self, offset: Size, + mode: OffsetMode, meta: MemPlaceMeta<Prov>, layout: TyAndLayout<'tcx>, ecx: &InterpCx<'mir, 'tcx, M>, ) -> InterpResult<'tcx, Self> { Ok(match self.as_mplace_or_local() { - Left(mplace) => mplace.offset_with_meta(offset, meta, layout, ecx)?.into(), + Left(mplace) => mplace.offset_with_meta(offset, mode, meta, layout, ecx)?.into(), Right((frame, local, old_offset)) => { debug_assert!(layout.is_sized(), "unsized locals should live in memory"); assert_matches!(meta, MemPlaceMeta::None); // we couldn't store it anyway... - let new_offset = ecx - .data_layout() - .offset(old_offset.unwrap_or(Size::ZERO).bytes(), offset.bytes())?; - PlaceTy { - place: Place::Local { - frame, - local, - offset: Some(Size::from_bytes(new_offset)), - }, - align: self.align.restrict_for_offset(offset), - layout, - } + // `Place::Local` are always in-bounds of their surrounding local, so we can just + // check directly if this remains in-bounds. This cannot actually be violated since + // projections are type-checked and bounds-checked. + assert!(offset + layout.size <= self.layout.size); + + let new_offset = Size::from_bytes( + ecx.data_layout() + .offset(old_offset.unwrap_or(Size::ZERO).bytes(), offset.bytes())?, + ); + + PlaceTy { place: Place::Local { frame, local, offset: Some(new_offset) }, layout } } }) } @@ -339,9 +305,7 @@ impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> { #[inline(always)] pub fn as_mplace_or_imm(&self) -> Either<MPlaceTy<'tcx, Prov>, ImmTy<'tcx, Prov>> { match self.op() { - Operand::Indirect(mplace) => { - Left(MPlaceTy { mplace: *mplace, layout: self.layout, align: self.align.unwrap() }) - } + Operand::Indirect(mplace) => Left(MPlaceTy { mplace: *mplace, layout: self.layout }), Operand::Immediate(imm) => Right(ImmTy::from_immediate(*imm, self.layout)), } } @@ -362,7 +326,7 @@ impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> { pub trait Writeable<'tcx, Prov: Provenance>: Projectable<'tcx, Prov> { fn as_mplace_or_local( &self, - ) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>, Align, TyAndLayout<'tcx>)>; + ) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>, TyAndLayout<'tcx>)>; fn force_mplace<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( &self, @@ -374,10 +338,9 @@ impl<'tcx, Prov: Provenance> Writeable<'tcx, Prov> for PlaceTy<'tcx, Prov> { #[inline(always)] fn as_mplace_or_local( &self, - ) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>, Align, TyAndLayout<'tcx>)> - { + ) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>, TyAndLayout<'tcx>)> { self.as_mplace_or_local() - .map_right(|(frame, local, offset)| (frame, local, offset, self.align, self.layout)) + .map_right(|(frame, local, offset)| (frame, local, offset, self.layout)) } #[inline(always)] @@ -393,8 +356,7 @@ impl<'tcx, Prov: Provenance> Writeable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { #[inline(always)] fn as_mplace_or_local( &self, - ) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>, Align, TyAndLayout<'tcx>)> - { + ) -> Either<MPlaceTy<'tcx, Prov>, (usize, mir::Local, Option<Size>, TyAndLayout<'tcx>)> { Left(self.clone()) } @@ -413,6 +375,25 @@ where Prov: Provenance, M: Machine<'mir, 'tcx, Provenance = Prov>, { + pub fn ptr_with_meta_to_mplace( + &self, + ptr: Pointer<Option<M::Provenance>>, + meta: MemPlaceMeta<M::Provenance>, + layout: TyAndLayout<'tcx>, + ) -> MPlaceTy<'tcx, M::Provenance> { + let misaligned = self.is_ptr_misaligned(ptr, layout.align.abi); + MPlaceTy { mplace: MemPlace { ptr, meta, misaligned }, layout } + } + + pub fn ptr_to_mplace( + &self, + ptr: Pointer<Option<M::Provenance>>, + layout: TyAndLayout<'tcx>, + ) -> MPlaceTy<'tcx, M::Provenance> { + assert!(layout.is_sized()); + self.ptr_with_meta_to_mplace(ptr, MemPlaceMeta::None, layout) + } + /// Take a value, which represents a (thin or wide) reference, and make it a place. /// Alignment is just based on the type. This is the inverse of `mplace_to_ref()`. /// @@ -434,7 +415,8 @@ where // `ref_to_mplace` is called on raw pointers even if they don't actually get dereferenced; // we hence can't call `size_and_align_of` since that asserts more validity than we want. - Ok(MPlaceTy::from_aligned_ptr_with_meta(ptr.to_pointer(self)?, layout, meta)) + let ptr = ptr.to_pointer(self)?; + Ok(self.ptr_with_meta_to_mplace(ptr, meta, layout)) } /// Turn a mplace into a (thin or wide) mutable raw pointer, pointing to the same space. @@ -464,7 +446,6 @@ where } let mplace = self.ref_to_mplace(&val)?; - self.check_mplace(&mplace)?; Ok(mplace) } @@ -477,8 +458,11 @@ where let (size, _align) = self .size_and_align_of_mplace(&mplace)? .unwrap_or((mplace.layout.size, mplace.layout.align.abi)); - // Due to packed places, only `mplace.align` matters. - self.get_ptr_alloc(mplace.ptr(), size, mplace.align) + // We check alignment separately, and *after* checking everything else. + // If an access is both OOB and misaligned, we want to see the bounds error. + let a = self.get_ptr_alloc(mplace.ptr(), size)?; + self.check_misalign(mplace.mplace.misaligned, CheckAlignMsg::BasedOn)?; + Ok(a) } #[inline] @@ -490,20 +474,13 @@ where let (size, _align) = self .size_and_align_of_mplace(&mplace)? .unwrap_or((mplace.layout.size, mplace.layout.align.abi)); - // Due to packed places, only `mplace.align` matters. - self.get_ptr_alloc_mut(mplace.ptr(), size, mplace.align) - } - - /// Check if this mplace is dereferenceable and sufficiently aligned. - pub fn check_mplace(&self, mplace: &MPlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { - let (size, _align) = self - .size_and_align_of_mplace(&mplace)? - .unwrap_or((mplace.layout.size, mplace.layout.align.abi)); - // Due to packed places, only `mplace.align` matters. - let align = - if M::enforce_alignment(self).should_check() { mplace.align } else { Align::ONE }; - self.check_ptr_access_align(mplace.ptr(), size, align, CheckInAllocMsg::DerefTest)?; - Ok(()) + // We check alignment separately, and raise that error *after* checking everything else. + // If an access is both OOB and misaligned, we want to see the bounds error. + // However we have to call `check_misalign` first to make the borrow checker happy. + let misalign_err = self.check_misalign(mplace.mplace.misaligned, CheckAlignMsg::BasedOn); + let a = self.get_ptr_alloc_mut(mplace.ptr(), size)?; + misalign_err?; + Ok(a) } /// Converts a repr(simd) place into a place where `place_index` accesses the SIMD elements. @@ -518,8 +495,8 @@ where let (len, e_ty) = mplace.layout.ty.simd_size_and_type(*self.tcx); let array = Ty::new_array(self.tcx.tcx, e_ty, len); let layout = self.layout_of(array)?; - assert_eq!(layout.size, mplace.layout.size); - Ok((MPlaceTy { layout, ..*mplace }, len)) + let mplace = mplace.transmute(layout, self)?; + Ok((mplace, len)) } /// Converts a repr(simd) place into a place where `place_index` accesses the SIMD elements. @@ -555,7 +532,7 @@ where Operand::Indirect(mplace) => Place::Ptr(*mplace), } }; - Ok(PlaceTy { place, layout, align: layout.align.abi }) + Ok(PlaceTy { place, layout }) } /// Computes a place. You should only use this if you intend to write into this @@ -645,7 +622,7 @@ where // See if we can avoid an allocation. This is the counterpart to `read_immediate_raw`, // but not factored as a separate function. let mplace = match dest.as_mplace_or_local() { - Right((frame, local, offset, align, layout)) => { + Right((frame, local, offset, layout)) => { if offset.is_some() { // This has been projected to a part of this local. We could have complicated // logic to still keep this local as an `Operand`... but it's much easier to @@ -686,7 +663,7 @@ where } Operand::Indirect(mplace) => { // The local is in memory, go on below. - MPlaceTy { mplace: *mplace, align, layout } + MPlaceTy { mplace: *mplace, layout } } } } @@ -695,7 +672,7 @@ where }; // This is already in memory, write there. - self.write_immediate_to_mplace_no_validate(src, mplace.layout, mplace.align, mplace.mplace) + self.write_immediate_to_mplace_no_validate(src, mplace.layout, mplace.mplace) } /// Write an immediate to memory. @@ -705,7 +682,6 @@ where &mut self, value: Immediate<M::Provenance>, layout: TyAndLayout<'tcx>, - align: Align, dest: MemPlace<M::Provenance>, ) -> InterpResult<'tcx> { // Note that it is really important that the type here is the right one, and matches the @@ -714,9 +690,7 @@ where // wrong type. let tcx = *self.tcx; - let Some(mut alloc) = - self.get_place_alloc_mut(&MPlaceTy { mplace: dest, layout, align })? - else { + let Some(mut alloc) = self.get_place_alloc_mut(&MPlaceTy { mplace: dest, layout })? else { // zero-sized access return Ok(()); }; @@ -734,9 +708,6 @@ where alloc.write_scalar(alloc_range(Size::ZERO, size), scalar) } Immediate::ScalarPair(a_val, b_val) => { - // We checked `ptr_align` above, so all fields will have the alignment they need. - // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`, - // which `ptr.offset(b_offset)` cannot possibly fail to satisfy. let Abi::ScalarPair(a, b) = layout.abi else { span_bug!( self.cur_span(), @@ -765,7 +736,7 @@ where ) -> InterpResult<'tcx> { let mplace = match dest.as_mplace_or_local() { Left(mplace) => mplace, - Right((frame, local, offset, align, layout)) => { + Right((frame, local, offset, layout)) => { if offset.is_some() { // This has been projected to a part of this local. We could have complicated // logic to still keep this local as an `Operand`... but it's much easier to @@ -781,7 +752,7 @@ where } Operand::Indirect(mplace) => { // The local is in memory, go on below. - MPlaceTy { mplace: *mplace, layout, align } + MPlaceTy { mplace: *mplace, layout } } } } @@ -874,7 +845,6 @@ where self.write_immediate_to_mplace_no_validate( *src_val, src.layout(), - dest_mem.align, dest_mem.mplace, ) }; @@ -901,14 +871,12 @@ where // type does not have Scalar/ScalarPair layout. // (Or as the `Assign` docs put it, assignments "not producing primitives" must be // non-overlapping.) - self.mem_copy( - src.ptr(), - src.align, - dest.ptr(), - dest.align, - dest_size, - /*nonoverlapping*/ true, - ) + // We check alignment separately, and *after* checking everything else. + // If an access is both OOB and misaligned, we want to see the bounds error. + self.mem_copy(src.ptr(), dest.ptr(), dest_size, /*nonoverlapping*/ true)?; + self.check_misalign(src.mplace.misaligned, CheckAlignMsg::BasedOn)?; + self.check_misalign(dest.mplace.misaligned, CheckAlignMsg::BasedOn)?; + Ok(()) } /// Ensures that a place is in memory, and returns where it is. @@ -942,7 +910,6 @@ where self.write_immediate_to_mplace_no_validate( local_val, local_layout, - local_layout.align.abi, mplace.mplace, )?; } @@ -957,7 +924,13 @@ where &mut Operand::Indirect(mplace) => mplace, // this already was an indirect local }; if let Some(offset) = offset { - whole_local.offset_with_meta_(offset, MemPlaceMeta::None, self)? + // This offset is always inbounds, no need to check it again. + whole_local.offset_with_meta_( + offset, + OffsetMode::Wrapping, + MemPlaceMeta::None, + self, + )? } else { // Preserve wide place metadata, do not call `offset`. whole_local @@ -966,7 +939,7 @@ where Place::Ptr(mplace) => mplace, }; // Return with the original layout and align, so that the caller can go on - Ok(MPlaceTy { mplace, layout: place.layout, align: place.align }) + Ok(MPlaceTy { mplace, layout: place.layout }) } pub fn allocate_dyn( @@ -979,7 +952,7 @@ where span_bug!(self.cur_span(), "cannot allocate space for `extern` type, size is not known") }; let ptr = self.allocate_ptr(size, align, kind)?; - Ok(MPlaceTy::from_aligned_ptr_with_meta(ptr.into(), layout, meta)) + Ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout)) } pub fn allocate( @@ -991,7 +964,7 @@ where self.allocate_dyn(layout, kind, MemPlaceMeta::None) } - /// Returns a wide MPlace of type `&'static [mut] str` to a new 1-aligned allocation. + /// Returns a wide MPlace of type `str` to a new 1-aligned allocation. pub fn allocate_str( &mut self, str: &str, @@ -1000,15 +973,8 @@ where ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl)?; let meta = Scalar::from_target_usize(u64::try_from(str.len()).unwrap(), self); - let mplace = MemPlace { ptr: ptr.into(), meta: MemPlaceMeta::Meta(meta) }; - - let ty = Ty::new_ref( - self.tcx.tcx, - self.tcx.lifetimes.re_static, - ty::TypeAndMut { ty: self.tcx.types.str_, mutbl }, - ); - let layout = self.layout_of(ty).unwrap(); - Ok(MPlaceTy { mplace, layout, align: layout.align.abi }) + let layout = self.layout_of(self.tcx.types.str_).unwrap(); + Ok(self.ptr_with_meta_to_mplace(ptr.into(), MemPlaceMeta::Meta(meta), layout)) } /// Writes the aggregate to the destination. @@ -1047,7 +1013,7 @@ where let _ = self.tcx.global_alloc(raw.alloc_id); let ptr = self.global_base_pointer(Pointer::from(raw.alloc_id))?; let layout = self.layout_of(raw.ty)?; - Ok(MPlaceTy::from_aligned_ptr(ptr.into(), layout)) + Ok(self.ptr_to_mplace(ptr.into(), layout)) } /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type. @@ -1063,12 +1029,10 @@ where let vtable = mplace.meta().unwrap_meta().to_pointer(self)?; let (ty, _) = self.get_ptr_vtable(vtable)?; let layout = self.layout_of(ty)?; - - let mplace = MPlaceTy { - mplace: MemPlace { meta: MemPlaceMeta::None, ..mplace.mplace }, - layout, - align: layout.align.abi, - }; + // This is a kind of transmute, from a place with unsized type and metadata to + // a place with sized type and no metadata. + let mplace = + MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..mplace.mplace }, layout }; Ok((mplace, vtable)) } @@ -1100,10 +1064,10 @@ mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; // tidy-alphabetical-start - static_assert_size!(MemPlace, 40); + static_assert_size!(MemPlace, 48); static_assert_size!(MemPlaceMeta, 24); static_assert_size!(MPlaceTy<'_>, 64); - static_assert_size!(Place, 40); + static_assert_size!(Place, 48); static_assert_size!(PlaceTy<'_>, 64); // tidy-alphabetical-end } diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 70df3d8fd78..6694c43c992 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -19,6 +19,15 @@ use rustc_target::abi::{self, VariantIdx}; use super::{InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Provenance, Scalar}; +/// Describes the constraints placed on offset-projections. +#[derive(Copy, Clone, Debug)] +pub enum OffsetMode { + /// The offset has to be inbounds, like `ptr::offset`. + Inbounds, + /// No constraints, just wrap around the edge of the address space. + Wrapping, +} + /// A thing that we can project into, and that has a layout. pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug { /// Get the layout. @@ -53,12 +62,12 @@ pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug { fn offset_with_meta<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( &self, offset: Size, + mode: OffsetMode, meta: MemPlaceMeta<Prov>, layout: TyAndLayout<'tcx>, ecx: &InterpCx<'mir, 'tcx, M>, ) -> InterpResult<'tcx, Self>; - #[inline] fn offset<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( &self, offset: Size, @@ -66,10 +75,9 @@ pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug { ecx: &InterpCx<'mir, 'tcx, M>, ) -> InterpResult<'tcx, Self> { assert!(layout.is_sized()); - self.offset_with_meta(offset, MemPlaceMeta::None, layout, ecx) + self.offset_with_meta(offset, OffsetMode::Inbounds, MemPlaceMeta::None, layout, ecx) } - #[inline] fn transmute<'mir, M: Machine<'mir, 'tcx, Provenance = Prov>>( &self, layout: TyAndLayout<'tcx>, @@ -77,7 +85,7 @@ pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug { ) -> InterpResult<'tcx, Self> { assert!(self.layout().is_sized() && layout.is_sized()); assert_eq!(self.layout().size, layout.size); - self.offset_with_meta(Size::ZERO, MemPlaceMeta::None, layout, ecx) + self.offset_with_meta(Size::ZERO, OffsetMode::Wrapping, MemPlaceMeta::None, layout, ecx) } /// Convert this to an `OpTy`. This might be an irreversible transformation, but is useful for @@ -104,7 +112,17 @@ impl<'tcx, 'a, Prov: Provenance, P: Projectable<'tcx, Prov>> ArrayIterator<'tcx, ecx: &InterpCx<'mir, 'tcx, M>, ) -> InterpResult<'tcx, Option<(u64, P)>> { let Some(idx) = self.range.next() else { return Ok(None) }; - Ok(Some((idx, self.base.offset(self.stride * idx, self.field_layout, ecx)?))) + // We use `Wrapping` here since the offset has already been checked when the iterator was created. + Ok(Some(( + idx, + self.base.offset_with_meta( + self.stride * idx, + OffsetMode::Wrapping, + MemPlaceMeta::None, + self.field_layout, + ecx, + )?, + ))) } } @@ -159,7 +177,7 @@ where (MemPlaceMeta::None, offset) }; - base.offset_with_meta(offset, meta, field_layout, self) + base.offset_with_meta(offset, OffsetMode::Inbounds, meta, field_layout, self) } /// Downcasting to an enum variant. @@ -248,6 +266,10 @@ where }; let len = base.len(self)?; let field_layout = base.layout().field(self, 0); + // Ensure that all the offsets are in-bounds once, up-front. + debug!("project_array_fields: {base:?} {len}"); + base.offset(len * stride, self.layout_of(self.tcx.types.unit).unwrap(), self)?; + // Create the iterator. Ok(ArrayIterator { base, range: 0..len, stride, field_layout, _phantom: PhantomData }) } @@ -305,7 +327,7 @@ where }; let layout = self.layout_of(ty)?; - base.offset_with_meta(from_offset, meta, layout, self) + base.offset_with_meta(from_offset, OffsetMode::Inbounds, meta, layout, self) } /// Applying a general projection diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 284e13407f7..79cbda545f1 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -206,15 +206,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let elem_size = first.layout.size; let first_ptr = first.ptr(); let rest_ptr = first_ptr.offset(elem_size, self)?; - // For the alignment of `rest_ptr`, we crucially do *not* use `first.align` as - // that place might be more aligned than its type mandates (a `u8` array could - // be 4-aligned if it sits at the right spot in a struct). We have to also factor - // in element size. + // No alignment requirement since `copy_op` above already checked it. self.mem_copy_repeatedly( first_ptr, - dest.align, rest_ptr, - dest.align.restrict_for_offset(elem_size), elem_size, length - 1, /*nonoverlapping:*/ true, @@ -268,7 +263,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { NullaryOp(ref null_op, ty) => { let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?; let layout = self.layout_of(ty)?; - if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op && layout.is_unsized() { + if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op + && layout.is_unsized() + { span_bug!( self.frame().current_span(), "{null_op:?} MIR operator called for unsized type {ty}", diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 578dd6622aa..59e89819880 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -1,6 +1,5 @@ use std::borrow::Cow; -use either::Either; use rustc_ast::ast::InlineAsmOptions; use rustc_middle::{ mir, @@ -729,13 +728,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { callee_ty: callee_fn_abi.ret.layout.ty }); } - // Ensure the return place is aligned and dereferenceable, and protect it for - // in-place return value passing. - if let Either::Left(mplace) = destination.as_mplace_or_local() { - self.check_mplace(&mplace)?; - } else { - // Nothing to do for locals, they are always properly allocated and aligned. - } + // Protect return place for in-place return value passing. M::protect_in_place_function_argument(self, destination)?; // Don't forget to mark "initially live" locals as live. @@ -890,11 +883,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } fn check_fn_target_features(&self, instance: ty::Instance<'tcx>) -> InterpResult<'tcx, ()> { + // Calling functions with `#[target_feature]` is not unsafe on WASM, see #84988 let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); - if attrs - .target_features - .iter() - .any(|feature| !self.tcx.sess.target_features.contains(feature)) + if !self.tcx.sess.target.is_like_wasm + && attrs + .target_features + .iter() + .any(|feature| !self.tcx.sess.target_features.contains(feature)) { throw_ub_custom!( fluent::const_eval_unavailable_target_features_for_fn, diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 3e023a89648..082e5466fe2 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -13,7 +13,7 @@ use rustc_ast::Mutability; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_middle::mir::interpret::{ - ExpectedKind, InterpError, InvalidMetaKind, PointerKind, ValidationErrorInfo, + ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, ValidationErrorInfo, ValidationErrorKind, ValidationErrorKind::*, }; use rustc_middle::ty; @@ -355,7 +355,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' value: &OpTy<'tcx, M::Provenance>, ptr_kind: PointerKind, ) -> InterpResult<'tcx> { - // Not using `deref_pointer` since we do the dereferenceable check ourselves below. + // Not using `deref_pointer` since we want to use our `read_immediate` wrapper. let place = self.ecx.ref_to_mplace(&self.read_immediate(value, ptr_kind.into())?)?; // Handle wide pointers. // Check metadata early, for better diagnostics @@ -378,18 +378,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' .unwrap_or_else(|| (place.layout.size, place.layout.align.abi)); // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines. try_validation!( - self.ecx.check_ptr_access_align( + self.ecx.check_ptr_access( place.ptr(), size, - align, CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message ), self.path, - Ub(AlignmentCheckFailed { required, has }) => UnalignedPtr { - ptr_kind, - required_bytes: required.bytes(), - found_bytes: has.bytes() - }, Ub(DanglingIntPointer(0, _)) => NullPtr { ptr_kind }, Ub(DanglingIntPointer(i, _)) => DanglingPtrNoProvenance { ptr_kind, @@ -405,6 +399,18 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' ptr_kind, }, ); + try_validation!( + self.ecx.check_ptr_align( + place.ptr(), + align, + ), + self.path, + Ub(AlignmentCheckFailed(Misalignment { required, has }, _msg)) => UnalignedPtr { + ptr_kind, + required_bytes: required.bytes(), + found_bytes: has.bytes() + }, + ); // Do not allow pointers to uninhabited types. if place.layout.abi.is_uninhabited() { let ty = place.layout.ty; @@ -645,7 +651,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> #[inline(always)] fn ecx(&self) -> &InterpCx<'mir, 'tcx, M> { - &self.ecx + self.ecx } fn read_discriminant( @@ -781,14 +787,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // Optimization: we just check the entire range at once. // NOTE: Keep this in sync with the handling of integer and float // types above, in `visit_primitive`. - // In run-time mode, we accept pointers in here. This is actually more - // permissive than a per-element check would be, e.g., we accept - // a &[u8] that contains a pointer even though bytewise checking would - // reject it. However, that's good: We don't inherently want - // to reject those pointers, we just do not have the machinery to - // talk about parts of a pointer. - // We also accept uninit, for consistency with the slow path. - let alloc = self.ecx.get_ptr_alloc(mplace.ptr(), size, mplace.align)?.expect("we already excluded size 0"); + // No need for an alignment check here, this is not an actual memory access. + let alloc = self.ecx.get_ptr_alloc(mplace.ptr(), size)?.expect("we already excluded size 0"); match alloc.get_bytes_strip_provenance() { // In the happy case, we needn't check anything else. diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 8bb409cea08..1fd5723f277 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -4,6 +4,9 @@ Rust MIR: a lowered representation of Rust. */ +#![cfg_attr(not(bootstrap), allow(internal_features))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), doc(rust_logo))] #![deny(rustc::untranslatable_diagnostic)] #![feature(assert_matches)] #![feature(box_patterns)] diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index f8f9bfb0470..92e7922ad3b 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -9,16 +9,17 @@ use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::traits::BuiltinImplSource; +use rustc_middle::ty::GenericArgs; use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, InstanceDef, Ty, TyCtxt}; -use rustc_middle::ty::{GenericArgKind, GenericArgs}; use rustc_middle::ty::{TraitRef, TypeVisitableExt}; use rustc_mir_dataflow::{self, Analysis}; use rustc_span::{sym, Span, Symbol}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt, SelectionContext}; +use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitor}; use std::mem; -use std::ops::Deref; +use std::ops::{ControlFlow, Deref}; use super::ops::{self, NonConstOp, Status}; use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop}; @@ -188,6 +189,24 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> { } } +struct LocalReturnTyVisitor<'ck, 'mir, 'tcx> { + kind: LocalKind, + checker: &'ck mut Checker<'mir, 'tcx>, +} + +impl<'ck, 'mir, 'tcx> TypeVisitor<TyCtxt<'tcx>> for LocalReturnTyVisitor<'ck, 'mir, 'tcx> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + match t.kind() { + ty::FnPtr(_) => ControlFlow::Continue(()), + ty::Ref(_, _, hir::Mutability::Mut) => { + self.checker.check_op(ops::ty::MutRef(self.kind)); + t.super_visit_with(self) + } + _ => t.super_visit_with(self), + } + } +} + pub struct Checker<'mir, 'tcx> { ccx: &'mir ConstCx<'mir, 'tcx>, qualifs: Qualifs<'mir, 'tcx>, @@ -304,7 +323,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { let gate = match op.status_in_item(self.ccx) { Status::Allowed => return, - Status::Unstable(gate) if self.tcx.features().enabled(gate) => { + Status::Unstable(gate) if self.tcx.features().active(gate) => { let unstable_in_stable = self.ccx.is_const_stable_const_fn() && !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate); if unstable_in_stable { @@ -346,20 +365,9 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) { let kind = self.body.local_kind(local); - for ty in ty.walk() { - let ty = match ty.unpack() { - GenericArgKind::Type(ty) => ty, - - // No constraints on lifetimes or constants, except potentially - // constants' types, but `walk` will get to them as well. - GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue, - }; + let mut visitor = LocalReturnTyVisitor { kind, checker: self }; - match *ty.kind() { - ty::Ref(_, _, hir::Mutability::Mut) => self.check_op(ops::ty::MutRef(kind)), - _ => {} - } - } + visitor.visit_ty(ty); } fn check_mut_borrow(&mut self, local: Local, kind: hir::BorrowKind) { @@ -456,7 +464,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::Aggregate(kind, ..) => { if let AggregateKind::Generator(def_id, ..) = kind.as_ref() - && let Some(generator_kind @ hir::GeneratorKind::Async(..)) = self.tcx.generator_kind(def_id) + && let Some(generator_kind @ hir::GeneratorKind::Async(..)) = + self.tcx.generator_kind(def_id) { self.check_op(ops::Generator(generator_kind)); } @@ -571,8 +580,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } - Rvalue::BinaryOp(op, box (lhs, rhs)) - | Rvalue::CheckedBinaryOp(op, box (lhs, rhs)) => { + Rvalue::BinaryOp(op, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(op, box (lhs, rhs)) => { let lhs_ty = lhs.ty(self.body, self.tcx); let rhs_ty = rhs.ty(self.body, self.tcx); @@ -580,18 +588,16 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // Int, bool, and char operations are fine. } else if lhs_ty.is_fn_ptr() || lhs_ty.is_unsafe_ptr() { assert_eq!(lhs_ty, rhs_ty); - assert!( - matches!( - op, - BinOp::Eq + assert!(matches!( + op, + BinOp::Eq | BinOp::Ne | BinOp::Le | BinOp::Lt | BinOp::Ge | BinOp::Gt | BinOp::Offset - ) - ); + )); self.check_op(ops::RawPtrComparison); } else if lhs_ty.is_floating_point() || rhs_ty.is_floating_point() { @@ -939,7 +945,9 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { if self.span.allows_unstable(gate) { return; } - if let Some(implied_by_gate) = implied_by && self.span.allows_unstable(implied_by_gate) { + if let Some(implied_by_gate) = implied_by + && self.span.allows_unstable(implied_by_gate) + { return; } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 1f3cda35c2b..e8d1d595820 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -311,10 +311,10 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { ccx.const_kind(), )); - if let Some(feature) = feature && ccx.tcx.sess.is_nightly_build() { - err.help(format!( - "add `#![feature({feature})]` to the crate attributes to enable", - )); + if let Some(feature) = feature + && ccx.tcx.sess.is_nightly_build() + { + err.help(format!("add `#![feature({feature})]` to the crate attributes to enable",)); } if let ConstContext::Static(_) = ccx.const_kind() { diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index a924afda6f0..54eb14ae8fc 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -3,7 +3,7 @@ use rustc_hir::def_id::CrateNum; use rustc_hir::definitions::DisambiguatedDefPathData; use rustc_middle::ty::{ self, - print::{PrettyPrinter, Print, Printer}, + print::{PrettyPrinter, Print, PrintError, Printer}, GenericArg, GenericArgKind, Ty, TyCtxt, }; use std::fmt::Write; @@ -14,23 +14,15 @@ struct AbsolutePathPrinter<'tcx> { } impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { - type Error = std::fmt::Error; - - type Path = Self; - type Region = Self; - type Type = Self; - type DynExistential = Self; - type Const = Self; - fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } - fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> { + fn print_region(self, _region: ty::Region<'_>) -> Result<Self, PrintError> { Ok(self) } - fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> { + fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self, PrintError> { match *ty.kind() { // Types without identity. ty::Bool @@ -68,18 +60,18 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { } } - fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { + fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self, PrintError> { self.pretty_print_const(ct, false) } fn print_dyn_existential( self, predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, - ) -> Result<Self::DynExistential, Self::Error> { + ) -> Result<Self, PrintError> { self.pretty_print_dyn_existential(predicates) } - fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { + fn path_crate(mut self, cnum: CrateNum) -> Result<Self, PrintError> { self.path.push_str(self.tcx.crate_name(cnum).as_str()); Ok(self) } @@ -88,17 +80,17 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { self, self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { self.pretty_path_qualified(self_ty, trait_ref) } fn path_append_impl( self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, _disambiguated_data: &DisambiguatedDefPathData, self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { self.pretty_path_append_impl( |mut cx| { cx = print_prefix(cx)?; @@ -114,9 +106,9 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { fn path_append( mut self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, disambiguated_data: &DisambiguatedDefPathData, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { self = print_prefix(self)?; write!(self.path, "::{}", disambiguated_data.data).unwrap(); @@ -126,9 +118,9 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { fn path_generic_args( mut self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, args: &[GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { self = print_prefix(self)?; let args = args.iter().cloned().filter(|arg| !matches!(arg.unpack(), GenericArgKind::Lifetime(_))); @@ -144,9 +136,9 @@ impl<'tcx> PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> { fn should_print_region(&self, _region: ty::Region<'_>) -> bool { false } - fn comma_sep<T>(mut self, mut elems: impl Iterator<Item = T>) -> Result<Self, Self::Error> + fn comma_sep<T>(mut self, mut elems: impl Iterator<Item = T>) -> Result<Self, PrintError> where - T: Print<'tcx, Self, Output = Self, Error = Self::Error>, + T: Print<'tcx, Self>, { if let Some(first) = elems.next() { self = first.print(self)?; @@ -160,8 +152,8 @@ impl<'tcx> PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> { fn generic_delimiters( mut self, - f: impl FnOnce(Self) -> Result<Self, Self::Error>, - ) -> Result<Self, Self::Error> { + f: impl FnOnce(Self) -> Result<Self, PrintError>, + ) -> Result<Self, PrintError> { write!(self, "<")?; self = f(self)?; diff --git a/compiler/rustc_data_structures/src/functor.rs b/compiler/rustc_data_structures/src/functor.rs deleted file mode 100644 index e3fcaccb1bd..00000000000 --- a/compiler/rustc_data_structures/src/functor.rs +++ /dev/null @@ -1,116 +0,0 @@ -use rustc_index::{Idx, IndexVec}; -use std::{mem, rc::Rc, sync::Arc}; - -pub trait IdFunctor: Sized { - type Inner; - - fn try_map_id<F, E>(self, f: F) -> Result<Self, E> - where - F: FnMut(Self::Inner) -> Result<Self::Inner, E>; -} - -impl<T> IdFunctor for Box<T> { - type Inner = T; - - #[inline] - fn try_map_id<F, E>(self, mut f: F) -> Result<Self, E> - where - F: FnMut(Self::Inner) -> Result<Self::Inner, E>, - { - let raw = Box::into_raw(self); - Ok(unsafe { - // SAFETY: The raw pointer points to a valid value of type `T`. - let value = raw.read(); - // SAFETY: Converts `Box<T>` to `Box<MaybeUninit<T>>` which is the - // inverse of `Box::assume_init()` and should be safe. - let raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast()); - // SAFETY: Write the mapped value back into the `Box`. - Box::write(raw, f(value)?) - }) - } -} - -impl<T> IdFunctor for Vec<T> { - type Inner = T; - - #[inline] - fn try_map_id<F, E>(self, f: F) -> Result<Self, E> - where - F: FnMut(Self::Inner) -> Result<Self::Inner, E>, - { - self.into_iter().map(f).collect() - } -} - -impl<T> IdFunctor for Box<[T]> { - type Inner = T; - - #[inline] - fn try_map_id<F, E>(self, f: F) -> Result<Self, E> - where - F: FnMut(Self::Inner) -> Result<Self::Inner, E>, - { - Vec::from(self).try_map_id(f).map(Into::into) - } -} - -impl<I: Idx, T> IdFunctor for IndexVec<I, T> { - type Inner = T; - - #[inline] - fn try_map_id<F, E>(self, f: F) -> Result<Self, E> - where - F: FnMut(Self::Inner) -> Result<Self::Inner, E>, - { - self.raw.try_map_id(f).map(IndexVec::from_raw) - } -} - -macro_rules! rc { - ($($rc:ident),+) => {$( - impl<T: Clone> IdFunctor for $rc<T> { - type Inner = T; - - #[inline] - fn try_map_id<F, E>(mut self, mut f: F) -> Result<Self, E> - where - F: FnMut(Self::Inner) -> Result<Self::Inner, E>, - { - // We merely want to replace the contained `T`, if at all possible, - // so that we don't needlessly allocate a new `$rc` or indeed clone - // the contained type. - unsafe { - // First step is to ensure that we have a unique reference to - // the contained type, which `$rc::make_mut` will accomplish (by - // allocating a new `$rc` and cloning the `T` only if required). - // This is done *before* casting to `$rc<ManuallyDrop<T>>` so that - // panicking during `make_mut` does not leak the `T`. - $rc::make_mut(&mut self); - - // Casting to `$rc<ManuallyDrop<T>>` is safe because `ManuallyDrop` - // is `repr(transparent)`. - let ptr = $rc::into_raw(self).cast::<mem::ManuallyDrop<T>>(); - let mut unique = $rc::from_raw(ptr); - - // Call to `$rc::make_mut` above guarantees that `unique` is the - // sole reference to the contained value, so we can avoid doing - // a checked `get_mut` here. - let slot = $rc::get_mut_unchecked(&mut unique); - - // Semantically move the contained type out from `unique`, fold - // it, then move the folded value back into `unique`. Should - // folding fail, `ManuallyDrop` ensures that the "moved-out" - // value is not re-dropped. - let owned = mem::ManuallyDrop::take(slot); - let folded = f(owned)?; - *slot = mem::ManuallyDrop::new(folded); - - // Cast back to `$rc<T>`. - Ok($rc::from_raw($rc::into_raw(unique).cast())) - } - } - } - )+}; -} - -rc! { Rc, Arc } diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index 9685ad24a97..5dd414cfd41 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -349,7 +349,7 @@ struct Inner<N: Idx> { post_order_rank: IndexVec<N, usize>, // Even though we track only the immediate dominator of each node, it's // possible to get its full list of dominators by looking up the dominator - // of each dominator. (See the `impl Iterator for Iter` definition). + // of each dominator. immediate_dominators: IndexVec<N, Option<N>>, time: IndexVec<N, Time>, } @@ -377,13 +377,6 @@ impl<Node: Idx> Dominators<Node> { } } - /// Provides an iterator over each dominator up the CFG, for the given Node. - /// See the `impl Iterator for Iter` definition to understand how this works. - pub fn dominators(&self, node: Node) -> Iter<'_, Node> { - assert!(self.is_reachable(node), "node {node:?} is not reachable"); - Iter { dom_tree: self, node: Some(node) } - } - /// Provide deterministic ordering of nodes such that, if any two nodes have a dominator /// relationship, the dominator will always precede the dominated. (The relative ordering /// of two unrelated nodes will also be consistent, but otherwise the order has no @@ -413,24 +406,6 @@ impl<Node: Idx> Dominators<Node> { } } -pub struct Iter<'dom, Node: Idx> { - dom_tree: &'dom Dominators<Node>, - node: Option<Node>, -} - -impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> { - type Item = Node; - - fn next(&mut self) -> Option<Self::Item> { - if let Some(node) = self.node { - self.node = self.dom_tree.immediate_dominator(node); - Some(node) - } else { - None - } - } -} - /// Describes the number of vertices discovered at the time when processing of a particular vertex /// started and when it finished. Both values are zero for unreachable vertices. #[derive(Copy, Clone, Default, Debug)] diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 461ec3a90ed..9511f1700e1 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -6,9 +6,10 @@ //! //! This API is completely unstable and subject to change. +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(array_windows)] -#![feature(associated_type_bounds)] #![feature(auto_traits)] #![feature(cell_leak)] #![feature(core_intrinsics)] @@ -19,15 +20,12 @@ #![feature(min_specialization)] #![feature(never_type)] #![feature(type_alias_impl_trait)] -#![feature(new_uninit)] #![feature(lazy_cell)] #![feature(rustc_attrs)] #![feature(negative_impls)] #![feature(test)] #![feature(thread_id_value)] -#![feature(vec_into_raw_parts)] #![feature(allocator_api)] -#![feature(get_mut_unchecked)] #![feature(lint_reasons)] #![feature(unwrap_infallible)] #![feature(strict_provenance)] @@ -63,7 +61,6 @@ pub mod binary_search_util; pub mod captures; pub mod flat_map_in_place; pub mod flock; -pub mod functor; pub mod fx; pub mod graph; pub mod intern; diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 0cd0b51b6ad..27f08fe7eef 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -1,4 +1,8 @@ // This crate is intentionally empty and a re-export of `rustc_driver_impl` to allow the code in // `rustc_driver_impl` to be compiled in parallel with other crates. +#![cfg_attr(not(bootstrap), allow(internal_features))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), doc(rust_logo))] + pub use rustc_driver_impl::*; diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index a7b01618ade..d931a8dab9b 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -6,53 +6,55 @@ edition = "2021" [lib] [dependencies] -time = { version = "0.3", default-features = false, features = ["formatting", ] } -tracing = { version = "0.1.35" } -serde_json = "1.0.59" -rustc_log = { path = "../rustc_log" } +# tidy-alphabetical-start +rustc_ast = { path = "../rustc_ast" } rustc_ast_lowering = { path = "../rustc_ast_lowering" } rustc_ast_passes = { path = "../rustc_ast_passes" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_attr = { path = "../rustc_attr" } rustc_borrowck = { path = "../rustc_borrowck" } rustc_builtin_macros = { path = "../rustc_builtin_macros" } +rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } rustc_const_eval = { path = "../rustc_const_eval" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_error_codes = { path = "../rustc_error_codes" } rustc_error_messages = { path = "../rustc_error_messages" } +rustc_errors = { path = "../rustc_errors" } rustc_expand = { path = "../rustc_expand" } -rustc_hir_typeck = { path = "../rustc_hir_typeck" } +rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } +rustc_hir = { path = "../rustc_hir" } +rustc_hir_analysis = { path = "../rustc_hir_analysis" } +rustc_hir_pretty = { path = "../rustc_hir_pretty" } +rustc_hir_typeck = { path = "../rustc_hir_typeck" } rustc_incremental = { path = "../rustc_incremental" } rustc_infer = { path = "../rustc_infer" } +rustc_interface = { path = "../rustc_interface" } +rustc_lint = { path = "../rustc_lint" } +rustc_log = { path = "../rustc_log" } +rustc_macros = { path = "../rustc_macros" } +rustc_metadata = { path = "../rustc_metadata" } +rustc_middle = { path = "../rustc_middle" } rustc_mir_build = { path = "../rustc_mir_build" } rustc_mir_dataflow = { path = "../rustc_mir_dataflow" } +rustc_mir_transform = { path = "../rustc_mir_transform" } rustc_monomorphize = { path = "../rustc_monomorphize" } +rustc_parse = { path = "../rustc_parse" } rustc_passes = { path = "../rustc_passes" } +rustc_plugin_impl = { path = "../rustc_plugin_impl" } rustc_privacy = { path = "../rustc_privacy" } rustc_query_system = { path = "../rustc_query_system" } rustc_resolve = { path = "../rustc_resolve" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } +rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_ty_utils = { path = "../rustc_ty_utils" } -rustc_middle = { path = "../rustc_middle" } -rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_target = { path = "../rustc_target" } -rustc_lint = { path = "../rustc_lint" } -rustc_data_structures = { path = "../rustc_data_structures" } -rustc_errors = { path = "../rustc_errors" } -rustc_feature = { path = "../rustc_feature" } -rustc_hir = { path = "../rustc_hir" } -rustc_hir_pretty = { path = "../rustc_hir_pretty" } -rustc_macros = { path = "../rustc_macros" } -rustc_metadata = { path = "../rustc_metadata" } -rustc_parse = { path = "../rustc_parse" } -rustc_plugin_impl = { path = "../rustc_plugin_impl" } -rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } -rustc_session = { path = "../rustc_session" } -rustc_error_codes = { path = "../rustc_error_codes" } -rustc_interface = { path = "../rustc_interface" } -rustc_ast = { path = "../rustc_ast" } -rustc_span = { path = "../rustc_span" } -rustc_hir_analysis = { path = "../rustc_hir_analysis" } -rustc_mir_transform = { path = "../rustc_mir_transform" } +serde_json = "1.0.59" +time = { version = "0.3", default-features = false, features = ["alloc", "formatting"] } +tracing = { version = "0.1.35" } +# tidy-alphabetical-end [target.'cfg(unix)'.dependencies] libc = "0.2" diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 1b3f39e69e1..7e4a7d93210 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -5,10 +5,13 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![feature(lazy_cell)] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), allow(internal_features))] #![feature(decl_macro)] -#![feature(panic_update_hook)] +#![feature(lazy_cell)] #![feature(let_chains)] +#![feature(panic_update_hook)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] @@ -59,7 +62,6 @@ use std::str; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::OnceLock; use std::time::{Instant, SystemTime}; -use time::format_description::well_known::Rfc3339; use time::OffsetDateTime; #[allow(unused_macros)] @@ -309,6 +311,7 @@ fn run_compiler( locale_resources: DEFAULT_LOCALE_RESOURCES, lint_caps: Default::default(), parse_sess_created: None, + hash_untracked_state: None, register_lints: None, override_queries: None, make_codegen_backend, @@ -392,7 +395,7 @@ fn run_compiler( if ppm.needs_ast_map() { queries.global_ctxt()?.enter(|tcx| { tcx.ensure().early_lint_checks(()); - pretty::print_after_hir_lowering(tcx, *ppm); + pretty::print(sess, *ppm, pretty::PrintExtra::NeedsAstMap { tcx }); Ok(()) })?; @@ -401,7 +404,7 @@ fn run_compiler( queries.global_ctxt()?.enter(|tcx| tcx.output_filenames(())); } else { let krate = queries.parse()?.steal(); - pretty::print_after_parsing(sess, &krate, *ppm); + pretty::print(sess, *ppm, pretty::PrintExtra::AfterParsing { krate }); } trace!("finished pretty-printing"); return early_exit(); @@ -542,7 +545,7 @@ pub enum Compilation { } impl Compilation { - pub fn and_then<F: FnOnce() -> Compilation>(self, next: F) -> Compilation { + fn and_then<F: FnOnce() -> Compilation>(self, next: F) -> Compilation { match self { Compilation::Stop => Compilation::Stop, Compilation::Continue => next(), @@ -654,7 +657,7 @@ fn show_md_content_with_pager(content: &str, color: ColorConfig) { } } -pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation { +fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation { if sess.opts.unstable_opts.link_only { if let Input::File(file) = &sess.io.input { let outputs = compiler.build_output_filenames(sess, &[]); @@ -695,7 +698,7 @@ pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Comp } } -pub fn list_metadata( +fn list_metadata( handler: &EarlyErrorHandler, sess: &Session, metadata_loader: &dyn MetadataLoader, @@ -1181,6 +1184,10 @@ fn print_flag_list<T>( /// /// So with all that in mind, the comments below have some more detail about the /// contortions done here to get things to work out correctly. +/// +/// This does not need to be `pub` for rustc itself, but @chaosite needs it to +/// be public when using rustc as a library, see +/// <https://github.com/rust-lang/rust/commit/2b4c33817a5aaecabf4c6598d41e190080ec119e> pub fn handle_options(handler: &EarlyErrorHandler, args: &[String]) -> Option<getopts::Matches> { if args.is_empty() { // user did not write `-v` nor `-Z unstable-options`, so do not @@ -1280,14 +1287,16 @@ pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 { } } -pub static ICE_PATH: OnceLock<Option<PathBuf>> = OnceLock::new(); +static ICE_PATH: OnceLock<Option<PathBuf>> = OnceLock::new(); -pub fn ice_path() -> &'static Option<PathBuf> { +fn ice_path() -> &'static Option<PathBuf> { ICE_PATH.get_or_init(|| { if !rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build() { return None; } - if let Some(s) = std::env::var_os("RUST_BACKTRACE") && s == "0" { + if let Some(s) = std::env::var_os("RUST_BACKTRACE") + && s == "0" + { return None; } let mut path = match std::env::var_os("RUSTC_ICE") { @@ -1301,7 +1310,13 @@ pub fn ice_path() -> &'static Option<PathBuf> { None => std::env::current_dir().unwrap_or_default(), }; let now: OffsetDateTime = SystemTime::now().into(); - let file_now = now.format(&Rfc3339).unwrap_or_default(); + let file_now = now + .format( + // Don't use a standard datetime format because Windows doesn't support `:` in paths + &time::format_description::parse("[year]-[month]-[day]T[hour]_[minute]_[second]") + .unwrap(), + ) + .unwrap_or_default(); let pid = std::process::id(); path.push(format!("rustc-ice-{file_now}-{pid}.txt")); Some(path) @@ -1354,8 +1369,7 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler)) eprintln!(); if let Some(ice_path) = ice_path() - && let Ok(mut out) = - File::options().create(true).append(true).open(&ice_path) + && let Ok(mut out) = File::options().create(true).append(true).open(&ice_path) { // The current implementation always returns `Some`. let location = info.location().unwrap(); @@ -1391,7 +1405,7 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler)) /// /// When `install_ice_hook` is called, this function will be called as the panic /// hook. -pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info: fn(&Handler)) { +fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info: fn(&Handler)) { let fallback_bundle = rustc_errors::fallback_fluent_bundle(crate::DEFAULT_LOCALE_RESOURCES.to_vec(), false); let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr( diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 222c7b5d6a7..8c6fee83013 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -1,14 +1,13 @@ //! The various pretty-printing routines. use rustc_ast as ast; -use rustc_ast_pretty::pprust; -use rustc_errors::ErrorGuaranteed; +use rustc_ast_pretty::pprust as pprust_ast; use rustc_hir as hir; use rustc_hir_pretty as pprust_hir; -use rustc_middle::hir::map as hir_map; +use rustc_middle::bug; use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty}; use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::config::{OutFileName, PpAstTreeMode, PpHirMode, PpMode, PpSourceMode}; +use rustc_session::config::{OutFileName, PpHirMode, PpMode, PpSourceMode}; use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::FileName; @@ -20,174 +19,57 @@ pub use self::PpMode::*; pub use self::PpSourceMode::*; use crate::abort_on_err; -// This slightly awkward construction is to allow for each PpMode to -// choose whether it needs to do analyses (which can consume the -// Session) and then pass through the session (now attached to the -// analysis results) on to the chosen pretty-printer, along with the -// `&PpAnn` object. -// -// Note that since the `&PrinterSupport` is freshly constructed on each -// call, it would not make sense to try to attach the lifetime of `self` -// to the lifetime of the `&PrinterObject`. - -/// Constructs a `PrinterSupport` object and passes it to `f`. -fn call_with_pp_support<'tcx, A, F>( - ppmode: &PpSourceMode, - sess: &'tcx Session, - tcx: Option<TyCtxt<'tcx>>, - f: F, -) -> A -where - F: FnOnce(&dyn PrinterSupport) -> A, -{ - match *ppmode { - Normal | Expanded => { - let annotation = NoAnn { sess, tcx }; - f(&annotation) - } - - Identified | ExpandedIdentified => { - let annotation = IdentifiedAnnotation { sess, tcx }; - f(&annotation) - } - ExpandedHygiene => { - let annotation = HygieneAnnotation { sess }; - f(&annotation) - } - } -} -fn call_with_pp_support_hir<A, F>(ppmode: &PpHirMode, tcx: TyCtxt<'_>, f: F) -> A -where - F: FnOnce(&dyn HirPrinterSupport<'_>, hir_map::Map<'_>) -> A, -{ - match *ppmode { - PpHirMode::Normal => { - let annotation = NoAnn { sess: tcx.sess, tcx: Some(tcx) }; - f(&annotation, tcx.hir()) - } - - PpHirMode::Identified => { - let annotation = IdentifiedAnnotation { sess: tcx.sess, tcx: Some(tcx) }; - f(&annotation, tcx.hir()) - } - PpHirMode::Typed => { - abort_on_err(tcx.analysis(()), tcx.sess); - - let annotation = TypedAnnotation { tcx, maybe_typeck_results: Cell::new(None) }; - tcx.dep_graph.with_ignore(|| f(&annotation, tcx.hir())) - } - } -} - -trait PrinterSupport: pprust::PpAnn { - /// Provides a uniform interface for re-extracting a reference to a - /// `Session` from a value that now owns it. - fn sess(&self) -> &Session; - - /// Produces the pretty-print annotation object. - /// - /// (Rust does not yet support upcasting from a trait object to - /// an object for one of its supertraits.) - fn pp_ann(&self) -> &dyn pprust::PpAnn; -} - -trait HirPrinterSupport<'hir>: pprust_hir::PpAnn { - /// Provides a uniform interface for re-extracting a reference to a - /// `Session` from a value that now owns it. - fn sess(&self) -> &Session; - - /// Provides a uniform interface for re-extracting a reference to an - /// `hir_map::Map` from a value that now owns it. - fn hir_map(&self) -> Option<hir_map::Map<'hir>>; - - /// Produces the pretty-print annotation object. - /// - /// (Rust does not yet support upcasting from a trait object to - /// an object for one of its supertraits.) - fn pp_ann(&self) -> &dyn pprust_hir::PpAnn; -} - -struct NoAnn<'hir> { - sess: &'hir Session, - tcx: Option<TyCtxt<'hir>>, -} - -impl<'hir> PrinterSupport for NoAnn<'hir> { - fn sess(&self) -> &Session { - self.sess - } - - fn pp_ann(&self) -> &dyn pprust::PpAnn { - self - } -} +struct AstNoAnn; -impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> { - fn sess(&self) -> &Session { - self.sess - } - - fn hir_map(&self) -> Option<hir_map::Map<'hir>> { - self.tcx.map(|tcx| tcx.hir()) - } +impl pprust_ast::PpAnn for AstNoAnn {} - fn pp_ann(&self) -> &dyn pprust_hir::PpAnn { - self - } +struct HirNoAnn<'tcx> { + tcx: TyCtxt<'tcx>, } -impl<'hir> pprust::PpAnn for NoAnn<'hir> {} -impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> { +impl<'tcx> pprust_hir::PpAnn for HirNoAnn<'tcx> { fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { - if let Some(tcx) = self.tcx { - pprust_hir::PpAnn::nested(&(&tcx.hir() as &dyn hir::intravisit::Map<'_>), state, nested) - } + pprust_hir::PpAnn::nested( + &(&self.tcx.hir() as &dyn hir::intravisit::Map<'_>), + state, + nested, + ) } } -struct IdentifiedAnnotation<'hir> { - sess: &'hir Session, - tcx: Option<TyCtxt<'hir>>, -} - -impl<'hir> PrinterSupport for IdentifiedAnnotation<'hir> { - fn sess(&self) -> &Session { - self.sess - } +struct AstIdentifiedAnn; - fn pp_ann(&self) -> &dyn pprust::PpAnn { - self - } -} - -impl<'hir> pprust::PpAnn for IdentifiedAnnotation<'hir> { - fn pre(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) { - if let pprust::AnnNode::Expr(_) = node { +impl pprust_ast::PpAnn for AstIdentifiedAnn { + fn pre(&self, s: &mut pprust_ast::State<'_>, node: pprust_ast::AnnNode<'_>) { + if let pprust_ast::AnnNode::Expr(_) = node { s.popen(); } } - fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) { + + fn post(&self, s: &mut pprust_ast::State<'_>, node: pprust_ast::AnnNode<'_>) { match node { - pprust::AnnNode::Crate(_) | pprust::AnnNode::Ident(_) | pprust::AnnNode::Name(_) => {} + pprust_ast::AnnNode::Crate(_) + | pprust_ast::AnnNode::Ident(_) + | pprust_ast::AnnNode::Name(_) => {} - pprust::AnnNode::Item(item) => { + pprust_ast::AnnNode::Item(item) => { s.s.space(); s.synth_comment(item.id.to_string()) } - pprust::AnnNode::SubItem(id) => { + pprust_ast::AnnNode::SubItem(id) => { s.s.space(); s.synth_comment(id.to_string()) } - pprust::AnnNode::Block(blk) => { + pprust_ast::AnnNode::Block(blk) => { s.s.space(); s.synth_comment(format!("block {}", blk.id)) } - pprust::AnnNode::Expr(expr) => { + pprust_ast::AnnNode::Expr(expr) => { s.s.space(); s.synth_comment(expr.id.to_string()); s.pclose() } - pprust::AnnNode::Pat(pat) => { + pprust_ast::AnnNode::Pat(pat) => { s.s.space(); s.synth_comment(format!("pat {}", pat.id)); } @@ -195,31 +77,25 @@ impl<'hir> pprust::PpAnn for IdentifiedAnnotation<'hir> { } } -impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> { - fn sess(&self) -> &Session { - self.sess - } - - fn hir_map(&self) -> Option<hir_map::Map<'hir>> { - self.tcx.map(|tcx| tcx.hir()) - } - - fn pp_ann(&self) -> &dyn pprust_hir::PpAnn { - self - } +struct HirIdentifiedAnn<'tcx> { + tcx: TyCtxt<'tcx>, } -impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> { +impl<'tcx> pprust_hir::PpAnn for HirIdentifiedAnn<'tcx> { fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { - if let Some(ref tcx) = self.tcx { - pprust_hir::PpAnn::nested(&(&tcx.hir() as &dyn hir::intravisit::Map<'_>), state, nested) - } + pprust_hir::PpAnn::nested( + &(&self.tcx.hir() as &dyn hir::intravisit::Map<'_>), + state, + nested, + ) } + fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) { if let pprust_hir::AnnNode::Expr(_) = node { s.popen(); } } + fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) { match node { pprust_hir::AnnNode::Name(_) => {} @@ -252,32 +128,22 @@ impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> { } } -struct HygieneAnnotation<'a> { +struct AstHygieneAnn<'a> { sess: &'a Session, } -impl<'a> PrinterSupport for HygieneAnnotation<'a> { - fn sess(&self) -> &Session { - self.sess - } - - fn pp_ann(&self) -> &dyn pprust::PpAnn { - self - } -} - -impl<'a> pprust::PpAnn for HygieneAnnotation<'a> { - fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) { +impl<'a> pprust_ast::PpAnn for AstHygieneAnn<'a> { + fn post(&self, s: &mut pprust_ast::State<'_>, node: pprust_ast::AnnNode<'_>) { match node { - pprust::AnnNode::Ident(&Ident { name, span }) => { + pprust_ast::AnnNode::Ident(&Ident { name, span }) => { s.s.space(); s.synth_comment(format!("{}{:?}", name.as_u32(), span.ctxt())) } - pprust::AnnNode::Name(&name) => { + pprust_ast::AnnNode::Name(&name) => { s.s.space(); s.synth_comment(name.as_u32().to_string()) } - pprust::AnnNode::Crate(_) => { + pprust_ast::AnnNode::Crate(_) => { s.s.hardbreak(); let verbose = self.sess.verbose(); s.synth_comment(rustc_span::hygiene::debug_hygiene_data(verbose)); @@ -288,26 +154,12 @@ impl<'a> pprust::PpAnn for HygieneAnnotation<'a> { } } -struct TypedAnnotation<'tcx> { +struct HirTypedAnn<'tcx> { tcx: TyCtxt<'tcx>, maybe_typeck_results: Cell<Option<&'tcx ty::TypeckResults<'tcx>>>, } -impl<'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'tcx> { - fn sess(&self) -> &Session { - self.tcx.sess - } - - fn hir_map(&self) -> Option<hir_map::Map<'tcx>> { - Some(self.tcx.hir()) - } - - fn pp_ann(&self) -> &dyn pprust_hir::PpAnn { - self - } -} - -impl<'tcx> pprust_hir::PpAnn for TypedAnnotation<'tcx> { +impl<'tcx> pprust_hir::PpAnn for HirTypedAnn<'tcx> { fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { let old_maybe_typeck_results = self.maybe_typeck_results.get(); if let pprust_hir::Nested::Body(id) = nested { @@ -317,11 +169,13 @@ impl<'tcx> pprust_hir::PpAnn for TypedAnnotation<'tcx> { pprust_hir::PpAnn::nested(pp_ann, state, nested); self.maybe_typeck_results.set(old_maybe_typeck_results); } + fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) { if let pprust_hir::AnnNode::Expr(_) = node { s.popen(); } } + fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) { if let pprust_hir::AnnNode::Expr(expr) = node { let typeck_results = self.maybe_typeck_results.get().or_else(|| { @@ -360,119 +214,119 @@ fn write_or_print(out: &str, sess: &Session) { sess.io.output_file.as_ref().unwrap_or(&OutFileName::Stdout).overwrite(out, sess); } -pub fn print_after_parsing(sess: &Session, krate: &ast::Crate, ppm: PpMode) { - let (src, src_name) = get_source(sess); +// Extra data for pretty-printing, the form of which depends on what kind of +// pretty-printing we are doing. +pub enum PrintExtra<'tcx> { + AfterParsing { krate: ast::Crate }, + NeedsAstMap { tcx: TyCtxt<'tcx> }, +} - let out = match ppm { - Source(s) => { - // Silently ignores an identified node. - call_with_pp_support(&s, sess, None, move |annotation| { - debug!("pretty printing source code {:?}", s); - let sess = annotation.sess(); - let parse = &sess.parse_sess; - pprust::print_crate( - sess.source_map(), - krate, - src_name, - src, - annotation.pp_ann(), - false, - parse.edition, - &sess.parse_sess.attr_id_generator, - ) - }) +impl<'tcx> PrintExtra<'tcx> { + fn with_krate<F, R>(&self, f: F) -> R + where + F: FnOnce(&ast::Crate) -> R, + { + match self { + PrintExtra::AfterParsing { krate, .. } => f(krate), + PrintExtra::NeedsAstMap { tcx } => f(&tcx.resolver_for_lowering(()).borrow().1), } - AstTree(PpAstTreeMode::Normal) => { - debug!("pretty printing AST tree"); - format!("{krate:#?}") - } - _ => unreachable!(), - }; + } - write_or_print(&out, sess); + fn tcx(&self) -> TyCtxt<'tcx> { + match self { + PrintExtra::AfterParsing { .. } => bug!("PrintExtra::tcx"), + PrintExtra::NeedsAstMap { tcx } => *tcx, + } + } } -pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, ppm: PpMode) { +pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { if ppm.needs_analysis() { - abort_on_err(print_with_analysis(tcx, ppm), tcx.sess); - return; + abort_on_err(ex.tcx().analysis(()), sess); } - let (src, src_name) = get_source(tcx.sess); + let (src, src_name) = get_source(sess); let out = match ppm { Source(s) => { - // Silently ignores an identified node. - call_with_pp_support(&s, tcx.sess, Some(tcx), move |annotation| { - debug!("pretty printing source code {:?}", s); - let sess = annotation.sess(); - let parse = &sess.parse_sess; - pprust::print_crate( + debug!("pretty printing source code {:?}", s); + let annotation: Box<dyn pprust_ast::PpAnn> = match s { + Normal => Box::new(AstNoAnn), + Expanded => Box::new(AstNoAnn), + Identified => Box::new(AstIdentifiedAnn), + ExpandedIdentified => Box::new(AstIdentifiedAnn), + ExpandedHygiene => Box::new(AstHygieneAnn { sess }), + }; + let parse = &sess.parse_sess; + let is_expanded = ppm.needs_ast_map(); + ex.with_krate(|krate| { + pprust_ast::print_crate( sess.source_map(), - &tcx.resolver_for_lowering(()).borrow().1, + krate, src_name, src, - annotation.pp_ann(), - true, + &*annotation, + is_expanded, parse.edition, &sess.parse_sess.attr_id_generator, ) }) } - - AstTree(PpAstTreeMode::Expanded) => { + AstTree => { + debug!("pretty printing AST tree"); + ex.with_krate(|krate| format!("{krate:#?}")) + } + AstTreeExpanded => { debug!("pretty-printing expanded AST"); - format!("{:#?}", tcx.resolver_for_lowering(()).borrow().1) + format!("{:#?}", ex.tcx().resolver_for_lowering(()).borrow().1) } - - Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, hir_map| { + Hir(s) => { debug!("pretty printing HIR {:?}", s); - let sess = annotation.sess(); - let sm = sess.source_map(); - let attrs = |id| hir_map.attrs(id); - pprust_hir::print_crate( - sm, - hir_map.root_module(), - src_name, - src, - &attrs, - annotation.pp_ann(), - ) - }), - + let tcx = ex.tcx(); + let f = |annotation: &dyn pprust_hir::PpAnn| { + let sm = sess.source_map(); + let hir_map = tcx.hir(); + let attrs = |id| hir_map.attrs(id); + pprust_hir::print_crate( + sm, + hir_map.root_module(), + src_name, + src, + &attrs, + annotation, + ) + }; + match s { + PpHirMode::Normal => { + let annotation = HirNoAnn { tcx }; + f(&annotation) + } + PpHirMode::Identified => { + let annotation = HirIdentifiedAnn { tcx }; + f(&annotation) + } + PpHirMode::Typed => { + let annotation = HirTypedAnn { tcx, maybe_typeck_results: Cell::new(None) }; + tcx.dep_graph.with_ignore(|| f(&annotation)) + } + } + } HirTree => { - call_with_pp_support_hir(&PpHirMode::Normal, tcx, move |_annotation, hir_map| { - debug!("pretty printing HIR tree"); - format!("{:#?}", hir_map.krate()) - }) + debug!("pretty printing HIR tree"); + format!("{:#?}", ex.tcx().hir().krate()) } - - _ => unreachable!(), - }; - - write_or_print(&out, tcx.sess); -} - -// In an ideal world, this would be a public function called by the driver after -// analysis is performed. However, we want to call `phase_3_run_analysis_passes` -// with a different callback than the standard driver, so that isn't easy. -// Instead, we call that function ourselves. -fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuaranteed> { - tcx.analysis(())?; - let out = match ppm { Mir => { let mut out = Vec::new(); - write_mir_pretty(tcx, None, &mut out).unwrap(); + write_mir_pretty(ex.tcx(), None, &mut out).unwrap(); String::from_utf8(out).unwrap() } - MirCFG => { let mut out = Vec::new(); - write_mir_graphviz(tcx, None, &mut out).unwrap(); + write_mir_graphviz(ex.tcx(), None, &mut out).unwrap(); String::from_utf8(out).unwrap() } - ThirTree => { + let tcx = ex.tcx(); let mut out = String::new(); abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess); debug!("pretty printing THIR tree"); @@ -481,8 +335,8 @@ fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuarante } out } - ThirFlat => { + let tcx = ex.tcx(); let mut out = String::new(); abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess); debug!("pretty printing THIR flat"); @@ -491,11 +345,7 @@ fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuarante } out } - - _ => unreachable!(), }; - write_or_print(&out, tcx.sess); - - Ok(()) + write_or_print(&out, sess); } diff --git a/compiler/rustc_error_codes/src/error_codes/E0706.md b/compiler/rustc_error_codes/src/error_codes/E0706.md index fabd855a222..a09abb59ba8 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0706.md +++ b/compiler/rustc_error_codes/src/error_codes/E0706.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + `async fn`s are not yet supported in traits in Rust. Erroneous code example: -```compile_fail,edition2018 +```ignore,edition2018 trait T { // Neither case is currently supported. async fn foo() {} @@ -13,7 +15,7 @@ trait T { `async fn`s return an `impl Future`, making the following two examples equivalent: -```edition2018,ignore (example-of-desugaring-equivalence) +```ignore,edition2018 (example-of-desugaring-equivalence) async fn foo() -> User { unimplemented!() } diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index d6b120e4dfc..81ad661286e 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -1,3 +1,6 @@ +#![cfg_attr(not(bootstrap), allow(internal_features))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), doc(rust_logo))] #![deny(rustdoc::invalid_codeblock_attributes)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 6c29144569d..6249c1e7961 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![feature(let_chains)] #![feature(lazy_cell)] #![feature(rustc_attrs)] diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 5e23ae655fe..85acf8ab5aa 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -659,6 +659,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { msg: impl Into<SubdiagnosticMessage>, ) -> &mut Self); forward!(pub fn help(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self); + forward!(pub fn help_once(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self); forward!(pub fn span_help( &mut self, sp: impl Into<MultiSpan>, diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index d322cbe9d9b..922846775f6 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -337,9 +337,7 @@ pub trait Emitter: Translate { && last_name != name { let descr = macro_kind.descr(); - format!( - " which comes from the expansion of the {descr} `{last_name}`", - ) + format!(" which comes from the expansion of the {descr} `{last_name}`",) } else { "".to_string() }; @@ -1935,7 +1933,9 @@ impl EmitterWriter { is_multiline, ) } - if let DisplaySuggestion::Add = show_code_change && is_item_attribute { + if let DisplaySuggestion::Add = show_code_change + && is_item_attribute + { // The suggestion adds an entire line of code, ending on a newline, so we'll also // print the *following* line, to provide context of what we're advising people to // do. Otherwise you would only see contextless code that can be confused for diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 665b5d6adec..da74ee6391a 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -3,6 +3,8 @@ //! This module contains the code for creating and emitting diagnostics. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![feature(array_windows)] #![feature(extract_if)] #![feature(if_let_guard)] @@ -505,6 +507,7 @@ pub enum StashKey { CallAssocMethod, TraitMissingMethod, OpaqueHiddenTypeMismatch, + MaybeForgetReturn, } fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) { @@ -1671,7 +1674,11 @@ impl HandlerInner { let _ = write!( &mut out, "delayed span bug: {}\n{}\n", - bug.inner.styled_message().iter().filter_map(|(msg, _)| msg.as_str()).collect::<String>(), + bug.inner + .styled_message() + .iter() + .filter_map(|(msg, _)| msg.as_str()) + .collect::<String>(), &bug.note ); } diff --git a/compiler/rustc_errors/src/tests.rs b/compiler/rustc_errors/src/tests.rs index 0e729b71680..79a2af7f38f 100644 --- a/compiler/rustc_errors/src/tests.rs +++ b/compiler/rustc_errors/src/tests.rs @@ -151,12 +151,14 @@ fn misformed_fluent() { primary: box TranslateError::One { kind: TranslateErrorKind::PrimaryBundleMissing, .. }, fallback: box TranslateError::One { kind: TranslateErrorKind::Fluent { errs }, .. }, } = &err - && let [FluentError::ResolverError(ResolverError::Reference( - ReferenceKind::Message { id, .. } - | ReferenceKind::Variable { id, .. }, - ))] = &**errs + && let [ + FluentError::ResolverError(ResolverError::Reference( + ReferenceKind::Message { id, .. } | ReferenceKind::Variable { id, .. }, + )), + ] = &**errs && id == "name" - {} else { + { + } else { panic!("{err:#?}") }; assert_eq!( @@ -176,12 +178,14 @@ fn misformed_fluent() { primary: box TranslateError::One { kind: TranslateErrorKind::PrimaryBundleMissing, .. }, fallback: box TranslateError::One { kind: TranslateErrorKind::Fluent { errs }, .. }, } = &err - && let [FluentError::ResolverError(ResolverError::Reference( - ReferenceKind::Message { id, .. } - | ReferenceKind::Variable { id, .. }, - ))] = &**errs + && let [ + FluentError::ResolverError(ResolverError::Reference( + ReferenceKind::Message { id, .. } | ReferenceKind::Variable { id, .. }, + )), + ] = &**errs && id == "oops" - {} else { + { + } else { panic!("{err:#?}") }; assert_eq!( diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 7ad0e799f44..b73c7593381 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -14,12 +14,12 @@ use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem use rustc_attr as attr; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_data_structures::fx::FxHashSet; -use rustc_feature::{Feature, Features, State as FeatureState}; -use rustc_feature::{ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES}; +use rustc_feature::Features; +use rustc_feature::{ACCEPTED_FEATURES, REMOVED_FEATURES, UNSTABLE_FEATURES}; use rustc_parse::validate_attr; use rustc_session::parse::feature_err; use rustc_session::Session; -use rustc_span::edition::{Edition, ALL_EDITIONS}; +use rustc_span::edition::ALL_EDITIONS; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use thin_vec::ThinVec; @@ -36,18 +36,10 @@ pub struct StripUnconfigured<'a> { } pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features { - fn active_features_up_to(edition: Edition) -> impl Iterator<Item = &'static Feature> { - ACTIVE_FEATURES.iter().filter(move |feature| { - if let Some(feature_edition) = feature.edition { - feature_edition <= edition - } else { - false - } - }) - } - fn feature_list(attr: &Attribute) -> ThinVec<ast::NestedMetaItem> { - if attr.has_name(sym::feature) && let Some(list) = attr.meta_item_list() { + if attr.has_name(sym::feature) + && let Some(list) = attr.meta_item_list() + { list } else { ThinVec::new() @@ -69,7 +61,9 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features { if mi.is_word() { let name = mi.name_or_empty(); let edition = ALL_EDITIONS.iter().find(|e| name == e.feature_name()).copied(); - if let Some(edition) = edition && edition > features_edition { + if let Some(edition) = edition + && edition > features_edition + { features_edition = edition; } } @@ -79,11 +73,13 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features { // Enable edition-dependent features based on `features_edition`. // - E.g. enable `test_2018_feature` if `features_edition` is 2018 or higher let mut edition_enabled_features = FxHashSet::default(); - for feature in active_features_up_to(features_edition) { - // FIXME(Manishearth) there is currently no way to set lib features by - // edition. - edition_enabled_features.insert(feature.name); - feature.set(&mut features); + for f in UNSTABLE_FEATURES { + if let Some(edition) = f.feature.edition && edition <= features_edition { + // FIXME(Manishearth) there is currently no way to set lib features by + // edition. + edition_enabled_features.insert(f.feature.name); + (f.set_enabled)(&mut features); + } } // Process all features declared in the code. @@ -143,19 +139,17 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features { } // If the declared feature has been removed, issue an error. - if let Some(Feature { state, .. }) = REMOVED_FEATURES.iter().find(|f| name == f.name) { - if let FeatureState::Removed { reason } = state { - sess.emit_err(FeatureRemoved { - span: mi.span(), - reason: reason.map(|reason| FeatureRemovedReason { reason }), - }); - continue; - } + if let Some(f) = REMOVED_FEATURES.iter().find(|f| name == f.feature.name) { + sess.emit_err(FeatureRemoved { + span: mi.span(), + reason: f.reason.map(|reason| FeatureRemovedReason { reason }), + }); + continue; } // If the declared feature is stable, record it. - if let Some(Feature { since, .. }) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) { - let since = Some(Symbol::intern(since)); + if let Some(f) = ACCEPTED_FEATURES.iter().find(|f| name == f.name) { + let since = Some(Symbol::intern(f.since)); features.set_declared_lang_feature(name, mi.span(), since); continue; } @@ -171,8 +165,8 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute]) -> Features { } // If the declared feature is unstable, record it. - if let Some(f) = ACTIVE_FEATURES.iter().find(|f| name == f.name) { - f.set(&mut features); + if let Some(f) = UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name) { + (f.set_enabled)(&mut features); features.set_declared_lang_feature(name, mi.span(), None); continue; } @@ -248,7 +242,8 @@ impl<'a> StripUnconfigured<'a> { let trees: Vec<_> = stream .0 .iter() - .flat_map(|tree| match tree.clone() { + .flat_map(|tree| { + match tree.clone() { AttrTokenTree::Attributes(mut data) => { data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr)); @@ -263,18 +258,17 @@ impl<'a> StripUnconfigured<'a> { } AttrTokenTree::Delimited(sp, delim, mut inner) => { inner = self.configure_tokens(&inner); - Some(AttrTokenTree::Delimited(sp, delim, inner)) - .into_iter() + Some(AttrTokenTree::Delimited(sp, delim, inner)).into_iter() } - AttrTokenTree::Token(ref token, _) if let TokenKind::Interpolated(nt) = &token.kind => { - panic!( - "Nonterminal should have been flattened at {:?}: {:?}", - token.span, nt - ); + AttrTokenTree::Token(ref token, _) + if let TokenKind::Interpolated(nt) = &token.kind => + { + panic!("Nonterminal should have been flattened at {:?}: {:?}", token.span, nt); } AttrTokenTree::Token(token, spacing) => { Some(AttrTokenTree::Token(token, spacing)).into_iter() } + } }) .collect(); AttrTokenStream::new(trees) diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 8b1fc5b90b4..5a774164a4b 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![feature(array_windows)] #![feature(associated_type_bounds)] #![feature(associated_type_defaults)] diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index a5959d68fbc..ebdd3cb547c 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -716,18 +716,18 @@ fn has_compile_error_macro(rhs: &mbe::TokenTree) -> bool { match rhs { mbe::TokenTree::Delimited(_sp, d) => { let has_compile_error = d.tts.array_windows::<3>().any(|[ident, bang, args]| { - if let mbe::TokenTree::Token(ident) = ident && - let TokenKind::Ident(ident, _) = ident.kind && - ident == sym::compile_error && - let mbe::TokenTree::Token(bang) = bang && - let TokenKind::Not = bang.kind && - let mbe::TokenTree::Delimited(_, del) = args && - del.delim != Delimiter::Invisible - { - true - } else { - false - } + if let mbe::TokenTree::Token(ident) = ident + && let TokenKind::Ident(ident, _) = ident.kind + && ident == sym::compile_error + && let mbe::TokenTree::Token(bang) = bang + && let TokenKind::Not = bang.kind + && let mbe::TokenTree::Delimited(_, del) = args + && del.delim != Delimiter::Invisible + { + true + } else { + false + } }); if has_compile_error { true } else { d.tts.iter().any(has_compile_error_macro) } } diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index 7c37aadc67a..7cb279a9812 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -124,8 +124,7 @@ fn parse_depth<'sess>( && let Ok(n_usize) = usize::try_from(n_u128) { Ok(n_usize) - } - else { + } else { let msg = "only unsuffixes integer literals are supported in meta-variable expressions"; Err(sess.span_diagnostic.struct_span_err(span, msg)) } @@ -137,15 +136,16 @@ fn parse_ident<'sess>( sess: &'sess ParseSess, span: Span, ) -> PResult<'sess, Ident> { - if let Some(tt) = iter.next() && let TokenTree::Token(token, _) = tt { + if let Some(tt) = iter.next() + && let TokenTree::Token(token, _) = tt + { if let Some((elem, false)) = token.ident() { return Ok(elem); } let token_str = pprust::token_to_string(token); - let mut err = sess.span_diagnostic.struct_span_err( - span, - format!("expected identifier, found `{}`", &token_str) - ); + let mut err = sess + .span_diagnostic + .struct_span_err(span, format!("expected identifier, found `{}`", &token_str)); err.span_suggestion( token.span, format!("try removing `{}`", &token_str), diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 3779af19e12..df6bdc6952b 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -91,7 +91,9 @@ pub(crate) fn mod_dir_path( inline: Inline, ) -> (PathBuf, DirOwnership) { match inline { - Inline::Yes if let Some(file_path) = mod_file_path_from_attr(sess, attrs, &module.dir_path) => { + Inline::Yes + if let Some(file_path) = mod_file_path_from_attr(sess, attrs, &module.dir_path) => + { // For inline modules file path from `#[path]` is actually the directory path // for historical reasons, so we don't pop the last segment here. (file_path, DirOwnership::Owned { relative: None }) diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 2dc9b51a37e..aa4c7a53135 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -226,9 +226,8 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre })); } - Interpolated(nt) if let NtIdent(ident, is_raw) = *nt => { - trees.push(TokenTree::Ident(Ident { sym: ident.name, is_raw, span: ident.span })) - } + Interpolated(nt) if let NtIdent(ident, is_raw) = *nt => trees + .push(TokenTree::Ident(Ident { sym: ident.name, is_raw, span: ident.span })), Interpolated(nt) => { let stream = TokenStream::from_nonterminal_ast(&nt); diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 32d8380abd3..f07022733d4 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -1,23 +1,20 @@ //! List of the accepted feature gates. -use super::{to_nonzero, Feature, State}; +use super::{to_nonzero, Feature}; use rustc_span::symbol::sym; macro_rules! declare_features { ($( $(#[doc = $doc:tt])* (accepted, $feature:ident, $ver:expr, $issue:expr, None), )+) => { - /// Those language feature has since been Accepted (it was once Active) + /// Formerly unstable features that have now been accepted (stabilized). pub const ACCEPTED_FEATURES: &[Feature] = &[ - $( - Feature { - state: State::Accepted, - name: sym::$feature, - since: $ver, - issue: to_nonzero($issue), - edition: None, - } - ),+ + $(Feature { + name: sym::$feature, + since: $ver, + issue: to_nonzero($issue), + edition: None, + }),+ ]; } } @@ -67,6 +64,8 @@ declare_features! ( (accepted, associated_types, "1.0.0", None, None), /// Allows free and inherent `async fn`s, `async` blocks, and `<expr>.await` expressions. (accepted, async_await, "1.39.0", Some(50547), None), + /// Allows async functions to be declared, implemented, and used in traits. + (accepted, async_fn_in_trait, "CURRENT_RUSTC_VERSION", Some(91611), None), /// Allows all literals in attribute lists and values of key-value pairs. (accepted, attr_literals, "1.30.0", Some(34981), None), /// Allows overloading augmented assignment operations like `a += b`. @@ -198,7 +197,7 @@ declare_features! ( /// + `impl Debug for Foo<'_>` (accepted, impl_header_lifetime_elision, "1.31.0", Some(15872), None), /// Allows referencing `Self` and projections in impl-trait. - (accepted, impl_trait_projections, "CURRENT_RUSTC_VERSION", Some(103532), None), + (accepted, impl_trait_projections, "1.74.0", Some(103532), None), /// Allows using `a..=b` and `..=b` as inclusive range syntaxes. (accepted, inclusive_range_syntax, "1.26.0", Some(28237), None), /// Allows inferring outlives requirements (RFC 2093). @@ -270,7 +269,7 @@ declare_features! ( /// Allows the use of or-patterns (e.g., `0 | 1`). (accepted, or_patterns, "1.53.0", Some(54883), None), /// Allows using `+bundle,+whole-archive` link modifiers with native libs. - (accepted, packed_bundled_libs, "CURRENT_RUSTC_VERSION", Some(108081), None), + (accepted, packed_bundled_libs, "1.74.0", Some(108081), None), /// Allows annotating functions conforming to `fn(&PanicInfo) -> !` with `#[panic_handler]`. /// This defines the behavior of panics. (accepted, panic_handler, "1.30.0", Some(44489), None), @@ -306,6 +305,8 @@ declare_features! ( (accepted, repr_packed, "1.33.0", Some(33158), None), /// Allows `#[repr(transparent)]` attribute on newtype structs. (accepted, repr_transparent, "1.28.0", Some(43036), None), + /// Allows return-position `impl Trait` in traits. + (accepted, return_position_impl_trait_in_trait, "CURRENT_RUSTC_VERSION", Some(91611), None), /// Allows code like `let x: &'static u32 = &42` to work (RFC 1414). (accepted, rvalue_static_promotion, "1.21.0", Some(38865), None), /// Allows `Self` in type definitions (RFC 2300). diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 4721bff0ec7..070234df94c 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -11,42 +11,26 @@ //! even if it is stabilized or removed, *do not remove it*. Instead, move the //! symbol to the `accepted` or `removed` modules respectively. +#![cfg_attr(not(bootstrap), allow(internal_features))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), doc(rust_logo))] #![feature(lazy_cell)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] mod accepted; -mod active; mod builtin_attrs; mod removed; +mod unstable; #[cfg(test)] mod tests; use rustc_span::{edition::Edition, symbol::Symbol}; -use std::fmt; use std::num::NonZeroU32; -#[derive(Clone, Copy)] -pub enum State { - Accepted, - Active { set: fn(&mut Features) }, - Removed { reason: Option<&'static str> }, -} - -impl fmt::Debug for State { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - State::Accepted { .. } => write!(f, "accepted"), - State::Active { .. } => write!(f, "active"), - State::Removed { .. } => write!(f, "removed"), - } - } -} - #[derive(Debug, Clone)] pub struct Feature { - pub state: State, pub name: Symbol, pub since: &'static str, issue: Option<NonZeroU32>, @@ -63,9 +47,9 @@ pub enum Stability { #[derive(Clone, Copy, Debug, Hash)] pub enum UnstableFeatures { - /// Hard errors for unstable features are active, as on beta/stable channels. + /// Disallow use of unstable features, as on beta/stable channels. Disallow, - /// Allow features to be activated, as on nightly. + /// Allow use of unstable features, as on nightly. Allow, /// Errors are bypassed for bootstrapping. This is required any time /// during the build that feature-related lints are set to warn or above @@ -106,17 +90,16 @@ impl UnstableFeatures { fn find_lang_feature_issue(feature: Symbol) -> Option<NonZeroU32> { // Search in all the feature lists. - let found = [] - .iter() - .chain(ACTIVE_FEATURES) - .chain(ACCEPTED_FEATURES) - .chain(REMOVED_FEATURES) - .find(|t| t.name == feature); - - match found { - Some(found) => found.issue, - None => panic!("feature `{feature}` is not declared anywhere"), + if let Some(f) = UNSTABLE_FEATURES.iter().find(|f| f.feature.name == feature) { + return f.feature.issue; + } + if let Some(f) = ACCEPTED_FEATURES.iter().find(|f| f.name == feature) { + return f.issue; + } + if let Some(f) = REMOVED_FEATURES.iter().find(|f| f.feature.name == feature) { + return f.feature.issue; } + panic!("feature `{feature}` is not declared anywhere"); } const fn to_nonzero(n: Option<u32>) -> Option<NonZeroU32> { @@ -141,7 +124,6 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZeroU3 } pub use accepted::ACCEPTED_FEATURES; -pub use active::{Features, ACTIVE_FEATURES, INCOMPATIBLE_FEATURES}; pub use builtin_attrs::AttributeDuplicates; pub use builtin_attrs::{ deprecated_attributes, find_gated_cfg, is_builtin_attr_name, is_builtin_only_local, @@ -149,3 +131,4 @@ pub use builtin_attrs::{ GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, }; pub use removed::REMOVED_FEATURES; +pub use unstable::{Features, INCOMPATIBLE_FEATURES, UNSTABLE_FEATURES}; diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index de15deef178..339f596144c 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -1,23 +1,28 @@ //! List of the removed feature gates. -use super::{to_nonzero, Feature, State}; +use super::{to_nonzero, Feature}; use rustc_span::symbol::sym; +pub struct RemovedFeature { + pub feature: Feature, + pub reason: Option<&'static str>, +} + macro_rules! declare_features { ($( $(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, None, $reason:expr), )+) => { - /// Represents unstable features which have since been removed (it was once Active) - pub const REMOVED_FEATURES: &[Feature] = &[ - $( - Feature { - state: State::Removed { reason: $reason }, + /// Formerly unstable features that have now been removed. + pub const REMOVED_FEATURES: &[RemovedFeature] = &[ + $(RemovedFeature { + feature: Feature { name: sym::$feature, since: $ver, issue: to_nonzero($issue), edition: None, - } - ),+ + }, + reason: $reason + }),+ ]; }; } @@ -121,7 +126,7 @@ declare_features! ( (removed, negate_unsigned, "1.0.0", Some(29645), None, None), /// Allows `#[no_coverage]` on functions. /// The feature was renamed to `coverage_attribute` and the attribute to `#[coverage(on|off)]` - (removed, no_coverage, "CURRENT_RUSTC_VERSION", Some(84605), None, Some("renamed to `coverage_attribute`")), + (removed, no_coverage, "1.74.0", Some(84605), None, Some("renamed to `coverage_attribute`")), /// Allows `#[no_debug]`. (removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")), /// Note: this feature was previously recorded in a separate diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/unstable.rs index 83961647bd4..27cdf1ba831 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -1,12 +1,17 @@ -//! List of the active feature gates. +//! List of the unstable feature gates. -use super::{to_nonzero, Feature, State}; +use super::{to_nonzero, Feature}; use rustc_data_structures::fx::FxHashSet; use rustc_span::edition::Edition; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; +pub struct UnstableFeature { + pub feature: Feature, + pub set_enabled: fn(&mut Features), +} + #[derive(PartialEq)] enum FeatureStatus { Default, @@ -15,7 +20,7 @@ enum FeatureStatus { } macro_rules! status_to_enum { - (active) => { + (unstable) => { FeatureStatus::Default }; (incomplete) => { @@ -30,23 +35,20 @@ macro_rules! declare_features { ($( $(#[doc = $doc:tt])* ($status:ident, $feature:ident, $ver:expr, $issue:expr, $edition:expr), )+) => { - /// Represents active features that are currently being implemented or - /// currently being considered for addition/removal. - pub const ACTIVE_FEATURES: - &[Feature] = - &[$( - // (sym::$feature, $ver, $issue, $edition, set!($feature)) - Feature { - state: State::Active { - // Sets this feature's corresponding bool within `features`. - set: |features| features.$feature = true, - }, + /// Unstable language features that are being implemented or being + /// considered for acceptance (stabilization) or removal. + pub const UNSTABLE_FEATURES: &[UnstableFeature] = &[ + $(UnstableFeature { + feature: Feature { name: sym::$feature, since: $ver, issue: to_nonzero($issue), edition: $edition, - } - ),+]; + }, + // Sets this feature's corresponding bool within `features`. + set_enabled: |features| features.$feature = true, + }),+ + ]; /// A set of features to be used by later passes. #[derive(Clone, Default, Debug)] @@ -57,7 +59,7 @@ macro_rules! declare_features { pub declared_lib_features: Vec<(Symbol, Span)>, /// `declared_lang_features` + `declared_lib_features`. pub declared_features: FxHashSet<Symbol>, - /// Individual features (unstable only). + /// Active state of individual features (unstable only). $( $(#[doc = $doc])* pub $feature: bool @@ -90,11 +92,11 @@ macro_rules! declare_features { self.declared_features.contains(&feature) } - /// Is the given feature enabled, i.e. declared or automatically + /// Is the given feature active, i.e. declared or automatically /// enabled due to the edition? /// /// Panics if the symbol doesn't correspond to a declared feature. - pub fn enabled(&self, feature: Symbol) -> bool { + pub fn active(&self, feature: Symbol) -> bool { match feature { $( sym::$feature => self.$feature, )* @@ -110,22 +112,21 @@ macro_rules! declare_features { $( sym::$feature => status_to_enum!($status) == FeatureStatus::Incomplete, )* - // accepted and removed features aren't in this file but are never incomplete + // Accepted/removed features aren't in this file but are never incomplete. _ if self.declared_features.contains(&feature) => false, _ => panic!("`{}` was not listed in `declare_features`", feature), } } /// Some features are internal to the compiler and standard library and should not - /// be used in normal projects. We warn the user about these - /// to alert them. + /// be used in normal projects. We warn the user about these to alert them. pub fn internal(&self, feature: Symbol) -> bool { match feature { $( sym::$feature => status_to_enum!($status) == FeatureStatus::Internal, )* - // accepted and removed features aren't in this file but are never internal - // (a removed feature might have been internal, but it doesn't matter anymore) + // Accepted/removed features aren't in this file but are never internal + // (a removed feature might have been internal, but that's now irrelevant). _ if self.declared_features.contains(&feature) => false, _ => panic!("`{}` was not listed in `declare_features`", feature), } @@ -134,16 +135,6 @@ macro_rules! declare_features { }; } -impl Feature { - /// Sets this feature in `Features`. Panics if called on a non-active feature. - pub fn set(&self, features: &mut Features) { - match self.state { - State::Active { set } => set(features), - _ => panic!("called `set` on feature `{}` which is not `active`", self.name), - } - } -} - // See https://rustc-dev-guide.rust-lang.org/feature-gates.html#feature-gates for more // documentation about handling feature gates. // @@ -153,8 +144,7 @@ impl Feature { // accepted or `removed.rs` if removed. // // The version numbers here correspond to the version in which the current status -// was set. This is most important for knowing when a particular feature became -// stable (active). +// 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. @@ -170,9 +160,9 @@ declare_features! ( // no-tracking-issue-start /// Allows using the `unadjusted` ABI; perma-unstable. - (active, abi_unadjusted, "1.16.0", None, None), + (unstable, abi_unadjusted, "1.16.0", None, None), /// Allows using the `vectorcall` ABI. - (active, abi_vectorcall, "1.7.0", None, None), + (unstable, abi_vectorcall, "1.7.0", None, None), /// Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`. (internal, allocator_internals, "1.20.0", None, None), /// Allows using `#[allow_internal_unsafe]`. This is an @@ -186,21 +176,21 @@ declare_features! ( /// macros disappear). (internal, allow_internal_unstable, "1.0.0", None, None), /// Allows using anonymous lifetimes in argument-position impl-trait. - (active, anonymous_lifetime_in_impl_trait, "1.63.0", None, None), + (unstable, anonymous_lifetime_in_impl_trait, "1.63.0", None, None), /// Allows identifying the `compiler_builtins` crate. (internal, compiler_builtins, "1.13.0", None, None), /// Allows writing custom MIR (internal, custom_mir, "1.65.0", None, None), /// Outputs useful `assert!` messages - (active, generic_assert, "1.63.0", None, None), + (unstable, generic_assert, "1.63.0", None, None), /// Allows using the `rust-intrinsic`'s "ABI". (internal, intrinsics, "1.0.0", None, None), /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic. (internal, lang_items, "1.0.0", None, None), /// Allows `#[link(..., cfg(..))]`; perma-unstable per #37406 - (active, link_cfg, "1.14.0", None, None), + (unstable, link_cfg, "1.14.0", None, None), /// Allows the `multiple_supertrait_upcastable` lint. - (active, multiple_supertrait_upcastable, "1.69.0", None, None), + (unstable, multiple_supertrait_upcastable, "1.69.0", None, None), /// Allow negative trait bounds. This is an internal-only feature for testing the trait solver! (incomplete, negative_bounds, "1.71.0", None, None), /// Allows using `#[omit_gdb_pretty_printer_section]`. @@ -222,7 +212,7 @@ declare_features! ( (internal, unsafe_pin_internals, "1.60.0", None, None), /// Use for stable + negative coherence and strict coherence depending on trait's /// rustc_strict_coherence value. - (active, with_negative_coherence, "1.60.0", None, None), + (unstable, with_negative_coherence, "1.60.0", None, None), // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! @@ -238,20 +228,20 @@ declare_features! ( /// Allows features specific to auto traits. /// Renamed from `optin_builtin_traits`. - (active, auto_traits, "1.50.0", Some(13231), None), + (unstable, auto_traits, "1.50.0", Some(13231), None), /// Allows using `box` in patterns (RFC 469). - (active, box_patterns, "1.0.0", Some(29641), None), + (unstable, box_patterns, "1.0.0", Some(29641), None), /// Allows `#[doc(notable_trait)]`. /// Renamed from `doc_spotlight`. - (active, doc_notable_trait, "1.52.0", Some(45040), None), + (unstable, doc_notable_trait, "1.52.0", Some(45040), None), /// Allows using the `may_dangle` attribute (RFC 1327). - (active, dropck_eyepatch, "1.10.0", Some(34761), None), + (unstable, dropck_eyepatch, "1.10.0", Some(34761), None), /// Allows using the `#[fundamental]` attribute. - (active, fundamental, "1.0.0", Some(29635), None), + (unstable, fundamental, "1.0.0", Some(29635), None), /// Allows using `#[link_name="llvm.*"]`. (internal, link_llvm_intrinsics, "1.0.0", Some(29602), None), /// Allows using the `#[linkage = ".."]` attribute. - (active, linkage, "1.0.0", Some(29603), None), + (unstable, linkage, "1.0.0", Some(29603), None), /// Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed. (internal, needs_panic_runtime, "1.10.0", Some(32837), None), /// Allows using the `#![panic_runtime]` attribute. @@ -263,19 +253,19 @@ declare_features! ( /// purpose as `#[allow_internal_unstable]`. (internal, rustc_allow_const_fn_unstable, "1.49.0", Some(69399), None), /// Allows using compiler's own crates. - (active, rustc_private, "1.0.0", Some(27812), None), + (unstable, rustc_private, "1.0.0", Some(27812), None), /// Allows using internal rustdoc features like `doc(keyword)`. (internal, rustdoc_internals, "1.58.0", Some(90418), None), /// Allows using the `rustdoc::missing_doc_code_examples` lint - (active, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730), None), + (unstable, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730), None), /// Allows using `#[start]` on a function indicating that it is the program entrypoint. - (active, start, "1.0.0", Some(29633), None), + (unstable, start, "1.0.0", Some(29633), None), /// Allows using `#[structural_match]` which indicates that a type is structurally matchable. /// FIXME: Subsumed by trait `StructuralPartialEq`, cannot move to removed until a library /// feature with the same name exists. - (active, structural_match, "1.8.0", Some(31434), None), + (unstable, structural_match, "1.8.0", Some(31434), None), /// Allows using the `rust-call` ABI. - (active, unboxed_closures, "1.0.0", Some(29625), None), + (unstable, unboxed_closures, "1.0.0", Some(29625), None), // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! @@ -291,20 +281,20 @@ declare_features! ( // FIXME: Document these and merge with the list below. // Unstable `#[target_feature]` directives. - (active, aarch64_ver_target_feature, "1.27.0", Some(44839), None), - (active, arm_target_feature, "1.27.0", Some(44839), None), - (active, avx512_target_feature, "1.27.0", Some(44839), None), - (active, bpf_target_feature, "1.54.0", Some(44839), None), - (active, csky_target_feature, "1.73.0", Some(44839), None), - (active, ermsb_target_feature, "1.49.0", Some(44839), None), - (active, hexagon_target_feature, "1.27.0", Some(44839), None), - (active, mips_target_feature, "1.27.0", Some(44839), None), - (active, powerpc_target_feature, "1.27.0", Some(44839), None), - (active, riscv_target_feature, "1.45.0", Some(44839), None), - (active, rtm_target_feature, "1.35.0", Some(44839), None), - (active, sse4a_target_feature, "1.27.0", Some(44839), None), - (active, tbm_target_feature, "1.27.0", Some(44839), None), - (active, wasm_target_feature, "1.30.0", Some(44839), None), + (unstable, aarch64_ver_target_feature, "1.27.0", Some(44839), None), + (unstable, arm_target_feature, "1.27.0", Some(44839), None), + (unstable, avx512_target_feature, "1.27.0", Some(44839), None), + (unstable, bpf_target_feature, "1.54.0", Some(44839), None), + (unstable, csky_target_feature, "1.73.0", Some(44839), None), + (unstable, ermsb_target_feature, "1.49.0", Some(44839), None), + (unstable, hexagon_target_feature, "1.27.0", Some(44839), None), + (unstable, mips_target_feature, "1.27.0", Some(44839), None), + (unstable, powerpc_target_feature, "1.27.0", Some(44839), None), + (unstable, riscv_target_feature, "1.45.0", Some(44839), None), + (unstable, rtm_target_feature, "1.35.0", Some(44839), None), + (unstable, sse4a_target_feature, "1.27.0", Some(44839), None), + (unstable, tbm_target_feature, "1.27.0", Some(44839), None), + (unstable, wasm_target_feature, "1.30.0", Some(44839), None), // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! @@ -318,157 +308,155 @@ declare_features! ( // ------------------------------------------------------------------------- /// Allows using the `amdgpu-kernel` ABI. - (active, abi_amdgpu_kernel, "1.29.0", Some(51575), None), + (unstable, abi_amdgpu_kernel, "1.29.0", Some(51575), None), /// Allows `extern "avr-interrupt" fn()` and `extern "avr-non-blocking-interrupt" fn()`. - (active, abi_avr_interrupt, "1.45.0", Some(69664), None), + (unstable, abi_avr_interrupt, "1.45.0", Some(69664), None), /// Allows `extern "C-cmse-nonsecure-call" fn()`. - (active, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391), None), + (unstable, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391), None), /// Allows `extern "msp430-interrupt" fn()`. - (active, abi_msp430_interrupt, "1.16.0", Some(38487), None), + (unstable, abi_msp430_interrupt, "1.16.0", Some(38487), None), /// Allows `extern "ptx-*" fn()`. - (active, abi_ptx, "1.15.0", Some(38788), None), + (unstable, abi_ptx, "1.15.0", Some(38788), None), /// Allows `extern "riscv-interrupt-m" fn()` and `extern "riscv-interrupt-s" fn()`. - (active, abi_riscv_interrupt, "1.73.0", Some(111889), None), + (unstable, abi_riscv_interrupt, "1.73.0", Some(111889), None), /// Allows `extern "x86-interrupt" fn()`. - (active, abi_x86_interrupt, "1.17.0", Some(40180), None), + (unstable, abi_x86_interrupt, "1.17.0", Some(40180), None), /// Allows additional const parameter types, such as `&'static str` or user defined types (incomplete, adt_const_params, "1.56.0", Some(95174), None), /// Allows defining an `#[alloc_error_handler]`. - (active, alloc_error_handler, "1.29.0", Some(51540), None), + (unstable, alloc_error_handler, "1.29.0", Some(51540), None), /// Allows trait methods with arbitrary self types. - (active, arbitrary_self_types, "1.23.0", Some(44874), None), + (unstable, arbitrary_self_types, "1.23.0", Some(44874), None), /// Allows using `const` operands in inline assembly. - (active, asm_const, "1.58.0", Some(93332), None), + (unstable, asm_const, "1.58.0", Some(93332), None), /// Enables experimental inline assembly support for additional architectures. - (active, asm_experimental_arch, "1.58.0", Some(93335), None), + (unstable, asm_experimental_arch, "1.58.0", Some(93335), None), /// Allows the `may_unwind` option in inline assembly. - (active, asm_unwind, "1.58.0", Some(93334), None), + (unstable, asm_unwind, "1.58.0", Some(93334), None), /// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`. - (active, associated_const_equality, "1.58.0", Some(92827), None), + (unstable, associated_const_equality, "1.58.0", Some(92827), None), /// Allows the user of associated type bounds. - (active, associated_type_bounds, "1.34.0", Some(52662), None), + (unstable, associated_type_bounds, "1.34.0", Some(52662), None), /// Allows associated type defaults. - (active, associated_type_defaults, "1.2.0", Some(29661), None), + (unstable, associated_type_defaults, "1.2.0", Some(29661), None), /// Allows `async || body` closures. - (active, async_closure, "1.37.0", Some(62290), None), - /// Allows async functions to be declared, implemented, and used in traits. - (active, async_fn_in_trait, "1.66.0", Some(91611), None), + (unstable, async_closure, "1.37.0", Some(62290), None), /// Allows `#[track_caller]` on async functions. - (active, async_fn_track_caller, "1.73.0", Some(110011), None), + (unstable, async_fn_track_caller, "1.73.0", Some(110011), None), /// Allows builtin # foo() syntax - (active, builtin_syntax, "1.71.0", Some(110680), None), + (unstable, builtin_syntax, "1.71.0", Some(110680), None), /// Allows `c"foo"` literals. - (active, c_str_literals, "1.71.0", Some(105723), None), + (unstable, c_str_literals, "1.71.0", Some(105723), None), /// Treat `extern "C"` function as nounwind. - (active, c_unwind, "1.52.0", Some(74990), None), + (unstable, c_unwind, "1.52.0", Some(74990), None), /// Allows using C-variadics. - (active, c_variadic, "1.34.0", Some(44930), None), + (unstable, c_variadic, "1.34.0", Some(44930), None), /// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour. - (active, cfg_overflow_checks, "1.71.0", Some(111466), None), + (unstable, cfg_overflow_checks, "1.71.0", Some(111466), None), /// Provides the relocation model information as cfg entry - (active, cfg_relocation_model, "1.73.0", Some(114929), None), + (unstable, cfg_relocation_model, "1.73.0", Some(114929), None), /// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used. - (active, cfg_sanitize, "1.41.0", Some(39699), None), + (unstable, cfg_sanitize, "1.41.0", Some(39699), None), /// Allows `cfg(target_abi = "...")`. - (active, cfg_target_abi, "1.55.0", Some(80970), None), + (unstable, cfg_target_abi, "1.55.0", Some(80970), None), /// Allows `cfg(target(abi = "..."))`. - (active, cfg_target_compact, "1.63.0", Some(96901), None), + (unstable, cfg_target_compact, "1.63.0", Some(96901), None), /// Allows `cfg(target_has_atomic_load_store = "...")`. - (active, cfg_target_has_atomic, "1.60.0", Some(94039), None), + (unstable, cfg_target_has_atomic, "1.60.0", Some(94039), None), /// Allows `cfg(target_has_atomic_equal_alignment = "...")`. - (active, cfg_target_has_atomic_equal_alignment, "1.60.0", Some(93822), None), + (unstable, cfg_target_has_atomic_equal_alignment, "1.60.0", Some(93822), None), /// Allows `cfg(target_thread_local)`. - (active, cfg_target_thread_local, "1.7.0", Some(29594), None), + (unstable, cfg_target_thread_local, "1.7.0", Some(29594), None), /// Allow conditional compilation depending on rust version - (active, cfg_version, "1.45.0", Some(64796), None), + (unstable, cfg_version, "1.45.0", Some(64796), None), /// Allows to use the `#[cfi_encoding = ""]` attribute. - (active, cfi_encoding, "1.71.0", Some(89653), None), + (unstable, cfi_encoding, "1.71.0", Some(89653), None), /// Allows `for<...>` on closures and generators. - (active, closure_lifetime_binder, "1.64.0", Some(97362), None), + (unstable, closure_lifetime_binder, "1.64.0", Some(97362), None), /// Allows `#[track_caller]` on closures and generators. - (active, closure_track_caller, "1.57.0", Some(87417), None), + (unstable, closure_track_caller, "1.57.0", Some(87417), None), /// Allows to use the `#[cmse_nonsecure_entry]` attribute. - (active, cmse_nonsecure_entry, "1.48.0", Some(75835), None), + (unstable, cmse_nonsecure_entry, "1.48.0", Some(75835), None), /// Allows use of the `#[collapse_debuginfo]` attribute. - (active, collapse_debuginfo, "1.65.0", Some(100758), None), + (unstable, collapse_debuginfo, "1.65.0", Some(100758), None), /// Allows `async {}` expressions in const contexts. - (active, const_async_blocks, "1.53.0", Some(85368), None), + (unstable, const_async_blocks, "1.53.0", Some(85368), None), /// Allows `const || {}` closures in const contexts. (incomplete, const_closures, "1.68.0", Some(106003), None), /// Allows the definition of `const extern fn` and `const unsafe extern fn`. - (active, const_extern_fn, "1.40.0", Some(64926), None), + (unstable, const_extern_fn, "1.40.0", Some(64926), None), /// Allows basic arithmetic on floating point types in a `const fn`. - (active, const_fn_floating_point_arithmetic, "1.48.0", Some(57241), None), + (unstable, const_fn_floating_point_arithmetic, "1.48.0", Some(57241), None), /// Allows `for _ in _` loops in const contexts. - (active, const_for, "1.56.0", Some(87575), None), + (unstable, const_for, "1.56.0", Some(87575), None), /// Allows using `&mut` in constant functions. - (active, const_mut_refs, "1.41.0", Some(57349), None), + (unstable, const_mut_refs, "1.41.0", Some(57349), None), /// Be more precise when looking for live drops in a const context. - (active, const_precise_live_drops, "1.46.0", Some(73255), None), + (unstable, const_precise_live_drops, "1.46.0", Some(73255), None), /// Allows references to types with interior mutability within constants - (active, const_refs_to_cell, "1.51.0", Some(80384), None), + (unstable, const_refs_to_cell, "1.51.0", Some(80384), None), /// Allows `impl const Trait for T` syntax. - (active, const_trait_impl, "1.42.0", Some(67792), None), + (unstable, const_trait_impl, "1.42.0", Some(67792), None), /// Allows the `?` operator in const contexts. - (active, const_try, "1.56.0", Some(74935), None), + (unstable, const_try, "1.56.0", Some(74935), None), /// Allows function attribute `#[coverage(on/off)]`, to control coverage /// instrumentation of that function. - (active, coverage_attribute, "CURRENT_RUSTC_VERSION", Some(84605), None), + (unstable, coverage_attribute, "1.74.0", Some(84605), None), /// Allows users to provide classes for fenced code block using `class:classname`. - (active, custom_code_classes_in_docs, "CURRENT_RUSTC_VERSION", Some(79483), None), + (unstable, custom_code_classes_in_docs, "1.74.0", Some(79483), None), /// Allows non-builtin attributes in inner attribute position. - (active, custom_inner_attributes, "1.30.0", Some(54726), None), + (unstable, custom_inner_attributes, "1.30.0", Some(54726), None), /// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`. - (active, custom_test_frameworks, "1.30.0", Some(50297), None), + (unstable, custom_test_frameworks, "1.30.0", Some(50297), None), /// Allows declarative macros 2.0 (`macro`). - (active, decl_macro, "1.17.0", Some(39412), None), + (unstable, decl_macro, "1.17.0", Some(39412), None), /// Allows default type parameters to influence type inference. - (active, default_type_parameter_fallback, "1.3.0", Some(27336), None), + (unstable, default_type_parameter_fallback, "1.3.0", Some(27336), None), /// Allows using `#[deprecated_safe]` to deprecate the safeness of a function or trait - (active, deprecated_safe, "1.61.0", Some(94978), None), + (unstable, deprecated_safe, "1.61.0", Some(94978), None), /// Allows having using `suggestion` in the `#[deprecated]` attribute. - (active, deprecated_suggestion, "1.61.0", Some(94785), None), + (unstable, deprecated_suggestion, "1.61.0", Some(94785), None), /// Allows using the `#[diagnostic]` attribute tool namespace - (active, diagnostic_namespace, "1.73.0", Some(111996), None), + (unstable, diagnostic_namespace, "1.73.0", Some(111996), None), /// Controls errors in trait implementations. - (active, do_not_recommend, "1.67.0", Some(51992), None), + (unstable, do_not_recommend, "1.67.0", Some(51992), None), /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. - (active, doc_auto_cfg, "1.58.0", Some(43781), None), + (unstable, doc_auto_cfg, "1.58.0", Some(43781), None), /// Allows `#[doc(cfg(...))]`. - (active, doc_cfg, "1.21.0", Some(43781), None), + (unstable, doc_cfg, "1.21.0", Some(43781), None), /// Allows `#[doc(cfg_hide(...))]`. - (active, doc_cfg_hide, "1.57.0", Some(43781), None), + (unstable, doc_cfg_hide, "1.57.0", Some(43781), None), /// Allows `#[doc(masked)]`. - (active, doc_masked, "1.21.0", Some(44027), None), + (unstable, doc_masked, "1.21.0", Some(44027), None), /// Allows `dyn* Trait` objects. (incomplete, dyn_star, "1.65.0", Some(102425), None), // Uses generic effect parameters for ~const bounds - (active, effects, "1.72.0", Some(102090), None), + (unstable, effects, "1.72.0", Some(102090), None), /// Allows `X..Y` patterns. - (active, exclusive_range_pattern, "1.11.0", Some(37854), None), + (unstable, exclusive_range_pattern, "1.11.0", Some(37854), None), /// Allows exhaustive pattern matching on types that contain uninhabited types. - (active, exhaustive_patterns, "1.13.0", Some(51085), None), + (unstable, exhaustive_patterns, "1.13.0", Some(51085), None), /// Allows explicit tail calls via `become` expression. (incomplete, explicit_tail_calls, "1.72.0", Some(112788), None), /// Allows using `efiapi`, `sysv64` and `win64` as calling convention /// for functions with varargs. - (active, extended_varargs_abi_support, "1.65.0", Some(100189), None), + (unstable, extended_varargs_abi_support, "1.65.0", Some(100189), None), /// Allows defining `extern type`s. - (active, extern_types, "1.23.0", Some(43467), None), + (unstable, extern_types, "1.23.0", Some(43467), None), /// Allows the use of `#[ffi_const]` on foreign functions. - (active, ffi_const, "1.45.0", Some(58328), None), + (unstable, ffi_const, "1.45.0", Some(58328), None), /// Allows the use of `#[ffi_pure]` on foreign functions. - (active, ffi_pure, "1.45.0", Some(58329), None), + (unstable, ffi_pure, "1.45.0", Some(58329), None), /// Allows using `#[ffi_returns_twice]` on foreign functions. - (active, ffi_returns_twice, "1.34.0", Some(58314), None), + (unstable, ffi_returns_twice, "1.34.0", Some(58314), None), /// Allows using `#[repr(align(...))]` on function items - (active, fn_align, "1.53.0", Some(82232), None), + (unstable, fn_align, "1.53.0", Some(82232), None), /// Allows generators to be cloned. - (active, generator_clone, "1.65.0", Some(95360), None), + (unstable, generator_clone, "1.65.0", Some(95360), None), /// Allows defining generators. - (active, generators, "1.21.0", Some(43122), None), + (unstable, generators, "1.21.0", Some(43122), None), /// Infer generic args for both consts and types. - (active, generic_arg_infer, "1.55.0", Some(85077), None), + (unstable, generic_arg_infer, "1.55.0", Some(85077), None), /// An extension to the `generic_associated_types` feature, allowing incomplete features. (incomplete, generic_associated_types_extended, "1.61.0", Some(95451), None), /// Allows non-trivial generic constants which have to have wfness manually propagated to callers @@ -476,139 +464,137 @@ declare_features! ( /// Allows generic parameters and where-clauses on free & associated const items. (incomplete, generic_const_items, "1.73.0", Some(113521), None), /// Allows using `..=X` as a patterns in slices. - (active, half_open_range_patterns_in_slices, "1.66.0", Some(67264), None), + (unstable, half_open_range_patterns_in_slices, "1.66.0", Some(67264), None), /// Allows `if let` guard in match arms. - (active, if_let_guard, "1.47.0", Some(51114), None), + (unstable, if_let_guard, "1.47.0", Some(51114), None), /// Allows `impl Trait` to be used inside associated types (RFC 2515). - (active, impl_trait_in_assoc_type, "1.70.0", Some(63063), None), + (unstable, impl_trait_in_assoc_type, "1.70.0", Some(63063), None), /// Allows `impl Trait` as output type in `Fn` traits in return position of functions. - (active, impl_trait_in_fn_trait_return, "1.64.0", Some(99697), None), + (unstable, impl_trait_in_fn_trait_return, "1.64.0", Some(99697), None), /// Allows using imported `main` function - (active, imported_main, "1.53.0", Some(28937), None), + (unstable, imported_main, "1.53.0", Some(28937), None), /// Allows associated types in inherent impls. (incomplete, inherent_associated_types, "1.52.0", Some(8995), None), /// Allow anonymous constants from an inline `const` block - (active, inline_const, "1.49.0", Some(76001), None), + (unstable, inline_const, "1.49.0", Some(76001), None), /// Allow anonymous constants from an inline `const` block in pattern position (incomplete, inline_const_pat, "1.58.0", Some(76001), None), /// Allows using `pointer` and `reference` in intra-doc links - (active, intra_doc_pointers, "1.51.0", Some(80896), None), + (unstable, intra_doc_pointers, "1.51.0", Some(80896), None), // Allows setting the threshold for the `large_assignments` lint. - (active, large_assignments, "1.52.0", Some(83518), None), + (unstable, large_assignments, "1.52.0", Some(83518), None), /// Allow to have type alias types for inter-crate use. (incomplete, lazy_type_alias, "1.72.0", Some(112792), None), /// Allows `if/while p && let q = r && ...` chains. - (active, let_chains, "1.37.0", Some(53667), None), + (unstable, let_chains, "1.37.0", Some(53667), None), /// Allows using `reason` in lint attributes and the `#[expect(lint)]` lint check. - (active, lint_reasons, "1.31.0", Some(54503), None), + (unstable, lint_reasons, "1.31.0", Some(54503), None), /// Give access to additional metadata about declarative macro meta-variables. - (active, macro_metavar_expr, "1.61.0", Some(83527), None), + (unstable, macro_metavar_expr, "1.61.0", Some(83527), None), /// Allows `#[marker]` on certain traits allowing overlapping implementations. - (active, marker_trait_attr, "1.30.0", Some(29864), None), + (unstable, marker_trait_attr, "1.30.0", Some(29864), None), /// A minimal, sound subset of specialization intended to be used by the /// standard library until the soundness issues with specialization /// are fixed. - (active, min_specialization, "1.7.0", Some(31844), None), + (unstable, min_specialization, "1.7.0", Some(31844), None), /// Allows qualified paths in struct expressions, struct patterns and tuple struct patterns. - (active, more_qualified_paths, "1.54.0", Some(86935), None), + (unstable, more_qualified_paths, "1.54.0", Some(86935), None), /// Allows the `#[must_not_suspend]` attribute. - (active, must_not_suspend, "1.57.0", Some(83310), None), + (unstable, must_not_suspend, "1.57.0", Some(83310), None), /// Allows using `#[naked]` on functions. - (active, naked_functions, "1.9.0", Some(32408), None), + (unstable, naked_functions, "1.9.0", Some(32408), None), /// Allows specifying the as-needed link modifier - (active, native_link_modifiers_as_needed, "1.53.0", Some(81490), None), + (unstable, native_link_modifiers_as_needed, "1.53.0", Some(81490), None), /// Allow negative trait implementations. - (active, negative_impls, "1.44.0", Some(68318), None), + (unstable, negative_impls, "1.44.0", Some(68318), None), /// Allows the `!` type. Does not imply 'exhaustive_patterns' (below) any more. - (active, never_type, "1.13.0", Some(35121), None), + (unstable, never_type, "1.13.0", Some(35121), None), /// Allows diverging expressions to fall back to `!` rather than `()`. - (active, never_type_fallback, "1.41.0", Some(65992), None), + (unstable, never_type_fallback, "1.41.0", Some(65992), None), /// Allows `#![no_core]`. - (active, no_core, "1.3.0", Some(29639), None), + (unstable, no_core, "1.3.0", Some(29639), None), /// Allows the use of `no_sanitize` attribute. - (active, no_sanitize, "1.42.0", Some(39699), None), + (unstable, no_sanitize, "1.42.0", Some(39699), None), /// Allows using the `non_exhaustive_omitted_patterns` lint. - (active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None), + (unstable, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None), /// Allows `for<T>` binders in where-clauses (incomplete, non_lifetime_binders, "1.69.0", Some(108185), None), /// Allows making `dyn Trait` well-formed even if `Trait` is not object safe. /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden. - (active, object_safe_for_dispatch, "1.40.0", Some(43561), None), + (unstable, object_safe_for_dispatch, "1.40.0", Some(43561), None), /// Allows using `#[optimize(X)]`. - (active, optimize_attribute, "1.34.0", Some(54882), None), + (unstable, optimize_attribute, "1.34.0", Some(54882), None), /// Allows using `#![plugin(myplugin)]`. - (active, plugin, "1.0.0", Some(29597), None), + (unstable, plugin, "1.0.0", Some(29597), None), /// Allows exhaustive integer pattern matching on `usize` and `isize`. - (active, precise_pointer_size_matching, "1.32.0", Some(56354), None), + (unstable, precise_pointer_size_matching, "1.32.0", Some(56354), None), /// Allows macro attributes on expressions, statements and non-inline modules. - (active, proc_macro_hygiene, "1.30.0", Some(54727), None), + (unstable, proc_macro_hygiene, "1.30.0", Some(54727), None), /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions. - (active, raw_ref_op, "1.41.0", Some(64490), None), + (unstable, raw_ref_op, "1.41.0", Some(64490), None), /// Allows using the `#[register_tool]` attribute. - (active, register_tool, "1.41.0", Some(66079), None), + (unstable, register_tool, "1.41.0", Some(66079), None), /// Allows the `#[repr(i128)]` attribute for enums. (incomplete, repr128, "1.16.0", Some(56071), None), /// Allows `repr(simd)` and importing the various simd intrinsics. - (active, repr_simd, "1.4.0", Some(27731), None), - /// Allows return-position `impl Trait` in traits. - (active, return_position_impl_trait_in_trait, "1.65.0", Some(91611), None), + (unstable, repr_simd, "1.4.0", Some(27731), None), /// Allows bounding the return type of AFIT/RPITIT. (incomplete, return_type_notation, "1.70.0", Some(109417), None), /// Allows `extern "rust-cold"`. - (active, rust_cold_cc, "1.63.0", Some(97544), None), + (unstable, rust_cold_cc, "1.63.0", Some(97544), None), /// Allows the use of SIMD types in functions declared in `extern` blocks. - (active, simd_ffi, "1.0.0", Some(27731), None), + (unstable, simd_ffi, "1.0.0", Some(27731), None), /// Allows specialization of implementations (RFC 1210). (incomplete, specialization, "1.7.0", Some(31844), None), /// Allows attributes on expressions and non-item statements. - (active, stmt_expr_attributes, "1.6.0", Some(15701), None), + (unstable, stmt_expr_attributes, "1.6.0", Some(15701), None), /// Allows lints part of the strict provenance effort. - (active, strict_provenance, "1.61.0", Some(95228), None), + (unstable, strict_provenance, "1.61.0", Some(95228), None), /// Allows string patterns to dereference values to match them. - (active, string_deref_patterns, "1.67.0", Some(87121), None), + (unstable, string_deref_patterns, "1.67.0", Some(87121), None), /// Allows the use of `#[target_feature]` on safe functions. - (active, target_feature_11, "1.45.0", Some(69098), None), + (unstable, target_feature_11, "1.45.0", Some(69098), None), /// Allows using `#[thread_local]` on `static` items. - (active, thread_local, "1.0.0", Some(29594), None), + (unstable, thread_local, "1.0.0", Some(29594), None), /// Allows defining `trait X = A + B;` alias items. - (active, trait_alias, "1.24.0", Some(41517), None), + (unstable, trait_alias, "1.24.0", Some(41517), None), /// Allows dyn upcasting trait objects via supertraits. /// Dyn upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`. - (active, trait_upcasting, "1.56.0", Some(65991), None), + (unstable, trait_upcasting, "1.56.0", Some(65991), None), /// Allows for transmuting between arrays with sizes that contain generic consts. - (active, transmute_generic_consts, "1.70.0", Some(109929), None), + (unstable, transmute_generic_consts, "1.70.0", Some(109929), None), /// Allows #[repr(transparent)] on unions (RFC 2645). - (active, transparent_unions, "1.37.0", Some(60405), None), + (unstable, transparent_unions, "1.37.0", Some(60405), None), /// Allows inconsistent bounds in where clauses. - (active, trivial_bounds, "1.28.0", Some(48214), None), + (unstable, trivial_bounds, "1.28.0", Some(48214), None), /// Allows using `try {...}` expressions. - (active, try_blocks, "1.29.0", Some(31436), None), + (unstable, try_blocks, "1.29.0", Some(31436), None), /// Allows `impl Trait` to be used inside type aliases (RFC 2515). - (active, type_alias_impl_trait, "1.38.0", Some(63063), None), + (unstable, type_alias_impl_trait, "1.38.0", Some(63063), None), /// Allows the use of type ascription in expressions. - (active, type_ascription, "1.6.0", Some(23416), None), + (unstable, type_ascription, "1.6.0", Some(23416), None), /// Allows creation of instances of a struct by moving fields that have /// not changed from prior instances of the same struct (RFC #2528) - (active, type_changing_struct_update, "1.58.0", Some(86555), None), + (unstable, type_changing_struct_update, "1.58.0", Some(86555), None), /// Allows using type privacy lints (`private_interfaces`, `private_bounds`, `unnameable_types`). - (active, type_privacy_lints, "1.72.0", Some(48054), None), + (unstable, type_privacy_lints, "1.72.0", Some(48054), None), /// Enables rustc to generate code that instructs libstd to NOT ignore SIGPIPE. - (active, unix_sigpipe, "1.65.0", Some(97889), None), + (unstable, unix_sigpipe, "1.65.0", Some(97889), None), /// Allows unnamed fields of struct and union type - (incomplete, unnamed_fields, "CURRENT_RUSTC_VERSION", Some(49804), None), + (incomplete, unnamed_fields, "1.74.0", Some(49804), None), /// Allows unsized fn parameters. - (active, unsized_fn_params, "1.49.0", Some(48055), None), + (unstable, unsized_fn_params, "1.49.0", Some(48055), None), /// Allows unsized rvalues at arguments and parameters. (incomplete, unsized_locals, "1.30.0", Some(48055), None), /// Allows unsized tuple coercion. - (active, unsized_tuple_coercion, "1.20.0", Some(42877), None), + (unstable, unsized_tuple_coercion, "1.20.0", Some(42877), None), /// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute. - (active, used_with_arg, "1.60.0", Some(93798), None), + (unstable, used_with_arg, "1.60.0", Some(93798), None), /// Allows `extern "wasm" fn` - (active, wasm_abi, "1.53.0", Some(83788), None), + (unstable, wasm_abi, "1.53.0", Some(83788), None), /// Allows `do yeet` expressions - (active, yeet_expr, "1.62.0", Some(96373), None), + (unstable, yeet_expr, "1.62.0", Some(96373), None), // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! diff --git a/compiler/rustc_fluent_macro/src/lib.rs b/compiler/rustc_fluent_macro/src/lib.rs index a01643cd67d..191fb787f70 100644 --- a/compiler/rustc_fluent_macro/src/lib.rs +++ b/compiler/rustc_fluent_macro/src/lib.rs @@ -1,4 +1,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), allow(internal_features))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![feature(proc_macro_diagnostic)] #![feature(proc_macro_span)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index 5d86d895817..9cb279e3efd 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -273,6 +273,9 @@ html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(allow(unused_variables), deny(warnings))) )] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), allow(internal_features))] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index 21611e9c586..711da6db5ac 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -284,6 +284,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { self.one_bound_for_assoc_type( || traits::supertraits(tcx, trait_ref), trait_ref.skip_binder().print_only_trait_name(), + None, binding.item_name, path_span, match binding.kind { @@ -447,7 +448,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { debug!(?args_trait_ref_and_assoc_item); - tcx.mk_alias_ty(assoc_item.def_id, args_trait_ref_and_assoc_item) + ty::AliasTy::new(tcx, assoc_item.def_id, args_trait_ref_and_assoc_item) }) }; @@ -517,8 +518,10 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { ); if let DefKind::AssocConst = def_kind - && let Some(t) = term.ty() && (t.is_enum() || t.references_error()) - && tcx.features().associated_const_equality { + && let Some(t) = term.ty() + && (t.is_enum() || t.references_error()) + && tcx.features().associated_const_equality + { err.span_suggestion( binding.span, "if equating a const, try wrapping with braces", diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index ed4dde419c4..889bc2ea432 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -6,10 +6,9 @@ use crate::errors::{ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, ErrorGuaranteed}; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::traits::FulfillmentError; -use rustc_middle::ty::TyCtxt; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt}; use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::symbol::{sym, Ident}; @@ -102,6 +101,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &self, all_candidates: impl Fn() -> I, ty_param_name: &str, + ty_param_def_id: Option<LocalDefId>, assoc_name: Ident, span: Span, ) -> ErrorGuaranteed @@ -190,13 +190,61 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }) .collect::<Vec<_>>()[..] { + let trait_name = self.tcx().def_path_str(*best_trait); + let an = if suggested_name != assoc_name.name { "a similarly named" } else { "an" }; err.span_label( assoc_name.span, format!( - "there is a similarly named associated type `{suggested_name}` in the trait `{}`", - self.tcx().def_path_str(*best_trait) + "there is {an} associated type `{suggested_name}` in the \ + trait `{trait_name}`", ), ); + let hir = self.tcx().hir(); + if let Some(def_id) = ty_param_def_id + && let parent = hir.get_parent_item(hir.local_def_id_to_hir_id(def_id)) + && let Some(generics) = hir.get_generics(parent.def_id) + { + if generics.bounds_for_param(def_id) + .flat_map(|pred| pred.bounds.iter()) + .any(|b| match b { + hir::GenericBound::Trait(t, ..) => { + t.trait_ref.trait_def_id().as_ref() == Some(best_trait) + } + _ => false, + }) + { + // The type param already has a bound for `trait_name`, we just need to + // change the associated type. + err.span_suggestion_verbose( + assoc_name.span, + format!( + "change the associated type name to use `{suggested_name}` from \ + `{trait_name}`", + ), + suggested_name.to_string(), + Applicability::MaybeIncorrect, + ); + } else if suggest_constraining_type_param( + self.tcx(), + generics, + &mut err, + &ty_param_name, + &trait_name, + None, + None, + ) + && suggested_name != assoc_name.name + { + // We suggested constraining a type parameter, but the associated type on it + // was also not an exact match, so we also suggest changing it. + err.span_suggestion_verbose( + assoc_name.span, + "and also change the associated type name", + suggested_name.to_string(), + Applicability::MaybeIncorrect, + ); + } + } return err.emit(); } } @@ -389,7 +437,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); let quiet_projection_ty = - tcx.mk_alias_ty(projection_ty.def_id, args_with_infer_self); + ty::AliasTy::new(tcx, projection_ty.def_id, args_with_infer_self); let term = pred.skip_binder().term; diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index e3621ef933a..7f0c0b961e4 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -432,9 +432,11 @@ pub(crate) fn check_generic_arg_count( let infer_lifetimes = (gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params(); - if gen_pos != GenericArgPosition::Type && let Some(b) = gen_args.bindings.first() { - prohibit_assoc_ty_binding(tcx, b.span, None); - } + if gen_pos != GenericArgPosition::Type + && let Some(b) = gen_args.bindings.first() + { + prohibit_assoc_ty_binding(tcx, b.span, None); + } let explicit_late_bound = prohibit_explicit_late_bound_lifetimes(tcx, gen_params, gen_args, gen_pos); diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs index 1bd1270beaf..bc57bbcca62 100644 --- a/compiler/rustc_hir_analysis/src/astconv/lint.rs +++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs @@ -18,18 +18,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(hir::Impl { - self_ty: impl_self_ty, of_trait: Some(of_trait_ref), generics, .. + self_ty: impl_self_ty, + of_trait: Some(of_trait_ref), + generics, + .. }), .. - }) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id + }) = tcx.hir().get_by_def_id(parent_id) + && self_ty.hir_id == impl_self_ty.hir_id { if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) { return; } let of_trait_span = of_trait_ref.path.span; // make sure that we are not calling unwrap to abort during the compilation - let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { return; }; - let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { return; }; + let Ok(impl_trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { + return; + }; + let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else { + return; + }; // check if the trait has generics, to make a correct suggestion let param_name = generics.params.next_type_param_name(None); @@ -39,13 +47,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (generics.span, format!("<{param_name}: {impl_trait_name}>")) }; diag.multipart_suggestion( - format!("alternatively use a blanket \ + format!( + "alternatively use a blanket \ implementation to implement `{of_trait_name}` for \ - all types that also implement `{impl_trait_name}`"), - vec![ - (self_ty.span, param_name), - add_generic_sugg, - ], + all types that also implement `{impl_trait_name}`" + ), + vec![(self_ty.span, param_name), add_generic_sugg], Applicability::MaybeIncorrect, ); } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index a91d9231390..2fcb45ef8aa 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -567,9 +567,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); if let ty::BoundConstness::ConstIfConst = constness - && generics.has_self && !tcx.has_attr(def_id, sym::const_trait) + && generics.has_self + && !tcx.has_attr(def_id, sym::const_trait) { - tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span } ); + tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span }); } (args, arg_count) @@ -915,7 +916,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Type aliases defined in crates that have the // feature `lazy_type_alias` enabled get encoded as a type alias that normalization will // then actually instantiate the where bounds of. - let alias_ty = tcx.mk_alias_ty(did, args); + let alias_ty = ty::AliasTy::new(tcx, did, args); Ty::new_alias(tcx, ty::Weak, alias_ty) } else { tcx.at(span).type_of(did).instantiate(tcx, args) @@ -1017,7 +1018,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } err.span_suggestions( span, - "use the fully-qualified path", + "use fully-qualified syntax", suggestions, Applicability::MachineApplicable, ); @@ -1061,6 +1062,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) }, param_name, + Some(ty_param_def_id), assoc_name, span, None, @@ -1074,6 +1076,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &self, all_candidates: impl Fn() -> I, ty_param_name: impl Display, + ty_param_def_id: Option<LocalDefId>, assoc_name: Ident, span: Span, is_equality: Option<ty::Term<'tcx>>, @@ -1088,13 +1091,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Const, assoc_name) }); - let (bound, next_cand) = match (matching_candidates.next(), const_candidates.next()) { + let (mut bound, mut next_cand) = match (matching_candidates.next(), const_candidates.next()) + { (Some(bound), _) => (bound, matching_candidates.next()), (None, Some(bound)) => (bound, const_candidates.next()), (None, None) => { let reported = self.complain_about_assoc_type_not_found( all_candidates, &ty_param_name.to_string(), + ty_param_def_id, assoc_name, span, ); @@ -1103,6 +1108,37 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }; debug!(?bound); + // look for a candidate that is not the same as our first bound, disregarding + // whether the bound is const. + while let Some(mut bound2) = next_cand { + debug!(?bound2); + let tcx = self.tcx(); + if bound2.bound_vars() != bound.bound_vars() { + break; + } + + let generics = tcx.generics_of(bound.def_id()); + let Some(host_index) = generics.host_effect_index else { break }; + + // always return the bound that contains the host param. + if let ty::ConstKind::Param(_) = bound2.skip_binder().args.const_at(host_index).kind() { + (bound, bound2) = (bound2, bound); + } + + let unconsted_args = bound + .skip_binder() + .args + .iter() + .enumerate() + .map(|(n, arg)| if host_index == n { tcx.consts.true_.into() } else { arg }); + + if unconsted_args.eq(bound2.skip_binder().args.iter()) { + next_cand = matching_candidates.next().or_else(|| const_candidates.next()); + } else { + break; + } + } + if let Some(bound2) = next_cand { debug!(?bound2); @@ -1142,30 +1178,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.span_label( bound_span, format!( - "ambiguous `{}` from `{}`", - assoc_name, + "ambiguous `{assoc_name}` from `{}`", bound.print_only_trait_path(), ), ); if let Some(constraint) = &is_equality { where_bounds.push(format!( - " T: {trait}::{assoc} = {constraint}", + " T: {trait}::{assoc_name} = {constraint}", trait=bound.print_only_trait_path(), - assoc=assoc_name, - constraint=constraint, )); } else { err.span_suggestion_verbose( span.with_hi(assoc_name.span.lo()), - "use fully qualified syntax to disambiguate", - format!("<{} as {}>::", ty_param_name, bound.print_only_trait_path()), + "use fully-qualified syntax to disambiguate", + format!("<{ty_param_name} as {}>::", bound.print_only_trait_path()), Applicability::MaybeIncorrect, ); } } else { err.note(format!( - "associated type `{}` could derive from `{}`", - ty_param_name, + "associated type `{ty_param_name}` could derive from `{}`", bound.print_only_trait_path(), )); } @@ -1173,8 +1205,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if !where_bounds.is_empty() { err.help(format!( "consider introducing a new type parameter `T` and adding `where` constraints:\ - \n where\n T: {},\n{}", - ty_param_name, + \n where\n T: {ty_param_name},\n{}", where_bounds.join(",\n"), )); } @@ -1396,6 +1427,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) }, kw::SelfUpper, + None, assoc_ident, span, None, @@ -1686,7 +1718,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .chain(args.into_iter().skip(parent_args.len())), ); - let ty = Ty::new_alias(tcx, ty::Inherent, tcx.mk_alias_ty(assoc_item, args)); + let ty = Ty::new_alias(tcx, ty::Inherent, ty::AliasTy::new(tcx, assoc_item, args)); return Ok(Some((ty, assoc_item))); } @@ -1919,9 +1951,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } else { Some(( match segment.res { - Res::PrimTy(ty) => format!("{} `{}`", segment.res.descr(), ty.name()), + Res::PrimTy(ty) => { + format!("{} `{}`", segment.res.descr(), ty.name()) + } Res::Def(_, def_id) - if let Some(name) = self.tcx().opt_item_name(def_id) => { + if let Some(name) = self.tcx().opt_item_name(def_id) => + { format!("{} `{name}`", segment.res.descr()) } Res::Err => "this type".to_string(), @@ -2251,7 +2286,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.note(msg); } for segment in path.segments { - if let Some(args) = segment.args && segment.ident.name == kw::SelfUpper { + if let Some(args) = segment.args + && segment.ident.name == kw::SelfUpper + { if generics == 0 { // FIXME(estebank): we could also verify that the arguments being // work for the `enum`, instead of just looking if it takes *any*. @@ -2633,7 +2670,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .iter() .enumerate() .map(|(i, a)| { - if let hir::TyKind::Infer = a.kind && !self.allow_ty_infer() { + if let hir::TyKind::Infer = a.kind + && !self.allow_ty_infer() + { if let Some(suggested_ty) = self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i)) { @@ -2662,7 +2701,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.ast_ty_to_ty(output) } } - hir::FnRetTy::DefaultReturn(..) => Ty::new_unit(tcx,), + hir::FnRetTy::DefaultReturn(..) => Ty::new_unit(tcx), }; debug!(?output_ty); diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index 1d9ae2b9cb7..b6688e0ce29 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -44,6 +44,34 @@ impl<'tcx> Bounds<'tcx> { span: Span, polarity: ty::ImplPolarity, ) { + self.push_trait_bound_inner(tcx, trait_ref, span, polarity); + + // push a non-const (`host = true`) version of the bound if it is `~const`. + if tcx.features().effects + && let Some(host_effect_idx) = tcx.generics_of(trait_ref.def_id()).host_effect_index + && trait_ref.skip_binder().args.const_at(host_effect_idx) != tcx.consts.true_ + { + let generics = tcx.generics_of(trait_ref.def_id()); + let Some(host_index) = generics.host_effect_index else { return }; + let trait_ref = trait_ref.map_bound(|mut trait_ref| { + trait_ref.args = + tcx.mk_args_from_iter(trait_ref.args.iter().enumerate().map(|(n, arg)| { + if host_index == n { tcx.consts.true_.into() } else { arg } + })); + trait_ref + }); + + self.push_trait_bound_inner(tcx, trait_ref, span, polarity); + } + } + + fn push_trait_bound_inner( + &mut self, + tcx: TyCtxt<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, + span: Span, + polarity: ty::ImplPolarity, + ) { self.clauses.push(( trait_ref .map_bound(|trait_ref| { diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 486aac21972..1745488dfd3 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -481,8 +481,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { fn_maybe_err(tcx, assoc_item.ident(tcx).span, abi); } ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => { - let trait_args = - GenericArgs::identity_for_item(tcx, id.owner_id); + let trait_args = GenericArgs::identity_for_item(tcx, id.owner_id); let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds( tcx, assoc_item, @@ -502,7 +501,8 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { } DefKind::OpaqueTy => { let origin = tcx.opaque_type_origin(id.owner_id.def_id); - if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin + if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) + | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin && let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id) && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() { @@ -589,7 +589,9 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) { } DefKind::GlobalAsm => { let it = tcx.hir().item(id); - let hir::ItemKind::GlobalAsm(asm) = it.kind else { span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) }; + let hir::ItemKind::GlobalAsm(asm) = it.kind else { + span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) + }; InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.owner_id.def_id); } _ => {} @@ -783,21 +785,21 @@ fn check_impl_items_against_trait<'tcx>( let (msg, feature) = if tcx.asyncness(def_id).is_async() { ( format!("async {descr} in trait cannot be specialized"), - sym::async_fn_in_trait, + "async functions in traits", ) } else { ( format!( "{descr} with return-position `impl Trait` in trait cannot be specialized" ), - sym::return_position_impl_trait_in_trait, + "return position `impl Trait` in traits", ) }; tcx.sess .struct_span_err(tcx.def_span(def_id), msg) .note(format!( "specialization behaves in inconsistent and \ - surprising ways with `#![feature({feature})]`, \ + surprising ways with {feature}, \ and for now is disallowed" )) .emit(); @@ -873,10 +875,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) => (), // struct(u8, u8, u8, u8) is ok ty::Array(t, _) if matches!(t.kind(), ty::Param(_)) => (), // pass struct<T>([T; N]) through, let monomorphization catch errors ty::Array(t, _clen) - if matches!( - t.kind(), - ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) - ) => + if matches!(t.kind(), ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_)) => { /* struct([f32; 4]) is ok */ } _ => { struct_span_err!( @@ -899,17 +898,17 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { for attr in tcx.get_attrs(def.did(), sym::repr) { for r in attr::parse_repr_attr(&tcx.sess, attr) { if let attr::ReprPacked(pack) = r - && let Some(repr_pack) = repr.pack - && pack as u64 != repr_pack.bytes() - { - struct_span_err!( - tcx.sess, - sp, - E0634, - "type has conflicting packed representation hints" - ) - .emit(); - } + && let Some(repr_pack) = repr.pack + && pack as u64 != repr_pack.bytes() + { + struct_span_err!( + tcx.sess, + sp, + E0634, + "type has conflicting packed representation hints" + ) + .emit(); + } } } if repr.align.is_some() { @@ -1174,7 +1173,8 @@ fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) let (span, display_discr) = match var.discr { ty::VariantDiscr::Explicit(discr_def_id) => { // In the case the discriminant is both a duplicate and overflowed, let the user know - if let hir::Node::AnonConst(expr) = tcx.hir().get_by_def_id(discr_def_id.expect_local()) + if let hir::Node::AnonConst(expr) = + tcx.hir().get_by_def_id(discr_def_id.expect_local()) && let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node && *lit_value != dis.val @@ -1303,15 +1303,9 @@ pub(super) fn check_type_params_are_used<'tcx>( && let ty::GenericParamDefKind::Type { .. } = param.kind { let span = tcx.def_span(param.def_id); - struct_span_err!( - tcx.sess, - span, - E0091, - "type parameter `{}` is unused", - param.name, - ) - .span_label(span, "unused type parameter") - .emit(); + struct_span_err!(tcx.sess, span, E0091, "type parameter `{}` is unused", param.name,) + .span_label(span, "unused type parameter") + .emit(); } } } @@ -1430,7 +1424,10 @@ fn opaque_type_cycle_error( let mut label_match = |ty: Ty<'_>, span| { for arg in ty.walk() { if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Alias(ty::Opaque, ty::AliasTy { def_id: captured_def_id, .. }) = *ty.kind() + && let ty::Alias( + ty::Opaque, + ty::AliasTy { def_id: captured_def_id, .. }, + ) = *ty.kind() && captured_def_id == opaque_def_id.to_def_id() { err.span_label( diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index f1514ecf69c..a1470cc69c3 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -633,8 +633,6 @@ fn compare_asyncness<'tcx>( /// For example, given the sample code: /// /// ``` -/// #![feature(return_position_impl_trait_in_trait)] -/// /// use std::ops::Deref; /// /// trait Foo { @@ -1011,7 +1009,11 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> { }); self.types.insert(proj.def_id, (infer_ty, proj.args)); // Recurse into bounds - for (pred, pred_span) in self.interner().explicit_item_bounds(proj.def_id).iter_instantiated_copied(self.interner(), proj.args) { + for (pred, pred_span) in self + .interner() + .explicit_item_bounds(proj.def_id) + .iter_instantiated_copied(self.interner(), proj.args) + { let pred = pred.fold_with(self); let pred = self.ocx.normalize( &ObligationCause::misc(self.span, self.body_id), @@ -1182,7 +1184,8 @@ fn report_trait_method_mismatch<'tcx>( if trait_sig.inputs().len() == *i { // Suggestion to change output type. We do not suggest in `async` functions // to avoid complex logic or incorrect output. - if let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind + if let ImplItemKind::Fn(sig, _) = + &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind && !sig.header.asyncness.is_async() { let msg = "change the output type to match the trait"; @@ -2283,7 +2286,7 @@ pub(super) fn check_type_bounds<'tcx>( _ => predicates.push( ty::Binder::bind_with_vars( ty::ProjectionPredicate { - projection_ty: tcx.mk_alias_ty(trait_ty.def_id, rebased_args), + projection_ty: ty::AliasTy::new(tcx, trait_ty.def_id, rebased_args), term: normalize_impl_ty.into(), }, bound_vars, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 97ebd42d077..34c28bce5d8 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -314,9 +314,10 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) { /// fn into_iter<'a>(&'a self) -> Self::Iter<'a>; /// } /// ``` -fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRef]) { +fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { // Associates every GAT's def_id to a list of possibly missing bounds detected by this lint. let mut required_bounds_by_item = FxHashMap::default(); + let associated_items = tcx.associated_items(trait_def_id); // Loop over all GATs together, because if this lint suggests adding a where-clause bound // to one GAT, it might then require us to an additional bound on another GAT. @@ -325,8 +326,8 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe // those GATs. loop { let mut should_continue = false; - for gat_item in associated_items { - let gat_def_id = gat_item.id.owner_id; + for gat_item in associated_items.in_definition_order() { + let gat_def_id = gat_item.def_id.expect_local(); let gat_item = tcx.associated_item(gat_def_id); // If this item is not an assoc ty, or has no args, then it's not a GAT if gat_item.kind != ty::AssocKind::Type { @@ -342,8 +343,8 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe // This is calculated by taking the intersection of the bounds that each item // constrains the GAT with individually. let mut new_required_bounds: Option<FxHashSet<ty::Clause<'_>>> = None; - for item in associated_items { - let item_def_id = item.id.owner_id; + for item in associated_items.in_definition_order() { + let item_def_id = item.def_id.expect_local(); // Skip our own GAT, since it does not constrain itself at all. if item_def_id == gat_def_id { continue; @@ -351,9 +352,9 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe let param_env = tcx.param_env(item_def_id); - let item_required_bounds = match item.kind { + let item_required_bounds = match tcx.associated_item(item_def_id).kind { // In our example, this corresponds to `into_iter` method - hir::AssocItemKind::Fn { .. } => { + ty::AssocKind::Fn => { // For methods, we check the function signature's return type for any GATs // to constrain. In the `into_iter` case, we see that the return type // `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from. @@ -369,12 +370,12 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe // We also assume that all of the function signature's parameter types // are well formed. &sig.inputs().iter().copied().collect(), - gat_def_id.def_id, + gat_def_id, gat_generics, ) } // In our example, this corresponds to the `Iter` and `Item` associated types - hir::AssocItemKind::Type => { + ty::AssocKind::Type => { // If our associated item is a GAT with missing bounds, add them to // the param-env here. This allows this GAT to propagate missing bounds // to other GATs. @@ -391,11 +392,11 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe .instantiate_identity_iter_copied() .collect::<Vec<_>>(), &FxIndexSet::default(), - gat_def_id.def_id, + gat_def_id, gat_generics, ) } - hir::AssocItemKind::Const => None, + ty::AssocKind::Const => None, }; if let Some(item_required_bounds) = item_required_bounds { @@ -431,7 +432,12 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe } for (gat_def_id, required_bounds) in required_bounds_by_item { - let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id.def_id); + // Don't suggest adding `Self: 'a` to a GAT that can't be named + if tcx.is_impl_trait_in_trait(gat_def_id.to_def_id()) { + continue; + } + + let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id); debug!(?required_bounds); let param_env = tcx.param_env(gat_def_id); @@ -441,21 +447,16 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => { !region_known_to_outlive( tcx, - gat_def_id.def_id, + gat_def_id, param_env, &FxIndexSet::default(), a, b, ) } - ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => !ty_known_to_outlive( - tcx, - gat_def_id.def_id, - param_env, - &FxIndexSet::default(), - a, - b, - ), + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => { + !ty_known_to_outlive(tcx, gat_def_id, param_env, &FxIndexSet::default(), a, b) + } _ => bug!("Unexpected ClauseKind"), }) .map(|clause| clause.to_string()) @@ -534,7 +535,7 @@ fn augment_param_env<'tcx>( fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - item_def_id: hir::OwnerId, + item_def_id: LocalDefId, to_check: T, wf_tys: &FxIndexSet<Ty<'tcx>>, gat_def_id: LocalDefId, @@ -567,7 +568,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( // reflected in a where clause on the GAT itself. for (ty, ty_idx) in &types { // In our example, requires that `Self: 'a` - if ty_known_to_outlive(tcx, item_def_id.def_id, param_env, &wf_tys, *ty, *region_a) { + if ty_known_to_outlive(tcx, item_def_id, param_env, &wf_tys, *ty, *region_a) { debug!(?ty_idx, ?region_a_idx); debug!("required clause: {ty} must outlive {region_a}"); // Translate into the generic parameters of the GAT. In @@ -606,14 +607,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( if matches!(**region_b, ty::ReStatic | ty::ReError(_)) || region_a == region_b { continue; } - if region_known_to_outlive( - tcx, - item_def_id.def_id, - param_env, - &wf_tys, - *region_a, - *region_b, - ) { + if region_known_to_outlive(tcx, item_def_id, param_env, &wf_tys, *region_a, *region_b) { debug!(?region_a_idx, ?region_b_idx); debug!("required clause: {region_a} must outlive {region_b}"); // Translate into the generic parameters of the GAT. @@ -1114,8 +1108,8 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { }); // Only check traits, don't check trait aliases - if let hir::ItemKind::Trait(_, _, _, _, items) = item.kind { - check_gat_where_clauses(tcx, items); + if let hir::ItemKind::Trait(..) = item.kind { + check_gat_where_clauses(tcx, item.owner_id.def_id); } } diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index e3e724df272..8fafbc4167f 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -550,9 +550,11 @@ fn infringing_fields_error( .entry((ty.clone(), predicate.clone())) .or_default() .push(origin.span()); - if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() { - bounds.push((b.to_string(), a.to_string(), None)); - } + if let ty::RegionKind::ReEarlyBound(ebr) = *b + && ebr.has_name() + { + bounds.push((b.to_string(), a.to_string(), None)); + } } RegionResolutionError::GenericBoundFailure(origin, a, b) => { let predicate = format!("{a}: {b}"); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 221df4e36b2..8e124d8eb1a 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -212,7 +212,9 @@ pub(crate) fn placeholder_type_error_diag<'tcx>( let mut is_fn = false; let mut is_const_or_static = false; - if let Some(hir_ty) = hir_ty && let hir::TyKind::BareFn(_) = hir_ty.kind { + if let Some(hir_ty) = hir_ty + && let hir::TyKind::BareFn(_) = hir_ty.kind + { is_fn = true; // Check if parent is const or static @@ -224,10 +226,8 @@ pub(crate) fn placeholder_type_error_diag<'tcx>( Node::Item(&hir::Item { kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..), .. - }) | Node::TraitItem(&hir::TraitItem { - kind: hir::TraitItemKind::Const(..), - .. - }) | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) + }) | Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Const(..), .. }) + | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) ); } @@ -1004,10 +1004,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { && let Some(lit) = meta.name_value_literal() { if seen_attr { - tcx.sess.span_err( - meta.span, - "duplicated `implement_via_object` meta item", - ); + tcx.sess.span_err(meta.span, "duplicated `implement_via_object` meta item"); } seen_attr = true; @@ -1021,7 +1018,10 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { _ => { tcx.sess.span_err( meta.span, - format!("unknown literal passed to `implement_via_object` attribute: {}", lit.symbol), + format!( + "unknown literal passed to `implement_via_object` attribute: {}", + lit.symbol + ), ); } } @@ -1115,8 +1115,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig< ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => { // Do not try to infer the return type for a impl method coming from a trait - if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) = - tcx.hir().get_parent(hir_id) + if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) = tcx.hir().get_parent(hir_id) && i.of_trait.is_some() { icx.astconv().ty_of_fn( @@ -1343,7 +1342,13 @@ fn suggest_impl_trait<'tcx>( if ocx.select_where_possible().is_empty() && let item_ty = infcx.resolve_vars_if_possible(item_ty) && let Some(item_ty) = item_ty.make_suggestable(tcx, false) - && let Some(sugg) = formatter(tcx, infcx.resolve_vars_if_possible(args), trait_def_id, assoc_item_def_id, item_ty) + && let Some(sugg) = formatter( + tcx, + infcx.resolve_vars_if_possible(args), + trait_def_id, + assoc_item_def_id, + item_ty, + ) { return Some(sugg); } diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 4b7743fae53..d746e6dea75 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -169,8 +169,8 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTyToOpaque<'tcx> { fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { if let ty::Alias(ty::Projection, projection_ty) = ty.kind() - && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) - = self.tcx.opt_rpitit_info(projection_ty.def_id) + && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) = + self.tcx.opt_rpitit_info(projection_ty.def_id) && fn_def_id == self.fn_def_id { self.tcx.type_of(projection_ty.def_id).instantiate(self.tcx, projection_ty.args) diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 1298c086087..104da581e01 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -11,7 +11,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{GenericPredicates, ImplTraitInTraitData, ToPredicate}; use rustc_span::symbol::Ident; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{sym, Span, DUMMY_SP}; /// Returns a list of all type predicates (explicit and implicit) for the definition with /// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus @@ -38,11 +38,38 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic // an obligation and instead be skipped. Otherwise we'd use // `tcx.def_span(def_id);` let span = rustc_span::DUMMY_SP; - result.predicates = - tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once(( - ty::TraitRef::identity(tcx, def_id).to_predicate(tcx), + let non_const_bound = if tcx.features().effects && tcx.has_attr(def_id, sym::const_trait) { + // when `Self` is a const trait, also add `Self: Trait<.., true>` as implied bound, + // because only implementing `Self: Trait<.., false>` is currently not possible. + Some(( + ty::TraitRef::new( + tcx, + def_id, + ty::GenericArgs::for_item(tcx, def_id, |param, _| { + if param.is_host_effect() { + tcx.consts.true_.into() + } else { + tcx.mk_param_from_def(param) + } + }), + ) + .to_predicate(tcx), span, - )))); + )) + } else { + None + }; + result.predicates = tcx.arena.alloc_from_iter( + result + .predicates + .iter() + .copied() + .chain(std::iter::once(( + ty::TraitRef::identity(tcx, def_id).to_predicate(tcx), + span, + ))) + .chain(non_const_bound), + ); } debug!("predicates_of(def_id={:?}) = {:?}", def_id, result); result @@ -180,7 +207,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // // default impl Foo for Bar { .. } // - // we add a default where clause `Foo: Bar`. We do a similar thing for traits + // we add a default where clause `Bar: Foo`. We do a similar thing for traits // (see below). Recall that a default impl is not itself an impl, but rather a // set of defaults that can be incorporated into another impl. if let Some(trait_ref) = is_default_impl_trait { @@ -389,7 +416,9 @@ fn const_evaluatable_predicates_of( let node = tcx.hir().get(hir_id); let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() }; - if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(impl_) = item.kind { + if let hir::Node::Item(item) = node + && let hir::ItemKind::Impl(impl_) = item.kind + { if let Some(of_trait) = &impl_.of_trait { debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id); collector.visit_trait_ref(of_trait); diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index eb4466449a0..ebb9e6f42d9 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1190,7 +1190,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Root { opt_parent_item } => { if let Some(parent_item) = opt_parent_item && let parent_generics = self.tcx.generics_of(parent_item) - && parent_generics.param_def_id_to_index(self.tcx, region_def_id.to_def_id()).is_some() + && parent_generics + .param_def_id_to_index(self.tcx, region_def_id.to_def_id()) + .is_some() { break Some(ResolvedArg::EarlyBound(region_def_id.to_def_id())); } @@ -1209,13 +1211,14 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { // regular fns. if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin && let hir::LifetimeName::Param(param_id) = lifetime_ref.res - && let Some(generics) = self.tcx.hir().get_generics(self.tcx.local_parent(param_id)) + && let Some(generics) = + self.tcx.hir().get_generics(self.tcx.local_parent(param_id)) && let Some(param) = generics.params.iter().find(|p| p.def_id == param_id) && param.is_elided_lifetime() && !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async() && !self.tcx.features().anonymous_lifetime_in_impl_trait { - let mut diag = rustc_session::parse::feature_err( + let mut diag = rustc_session::parse::feature_err( &self.tcx.sess.parse_sess, sym::anonymous_lifetime_in_impl_trait, lifetime_ref.ident.span, @@ -1225,25 +1228,31 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { if let Some(generics) = self.tcx.hir().get_generics(lifetime_ref.hir_id.owner.def_id) { - let new_param_sugg = if let Some(span) = - generics.span_for_lifetime_suggestion() - { - (span, "'a, ".to_owned()) - } else { - (generics.span, "<'a>".to_owned()) - }; + let new_param_sugg = + if let Some(span) = generics.span_for_lifetime_suggestion() { + (span, "'a, ".to_owned()) + } else { + (generics.span, "<'a>".to_owned()) + }; let lifetime_sugg = match lifetime_ref.suggestion_position() { - (hir::LifetimeSuggestionPosition::Normal, span) => (span, "'a".to_owned()), - (hir::LifetimeSuggestionPosition::Ampersand, span) => (span, "'a ".to_owned()), - (hir::LifetimeSuggestionPosition::ElidedPath, span) => (span, "<'a>".to_owned()), - (hir::LifetimeSuggestionPosition::ElidedPathArgument, span) => (span, "'a, ".to_owned()), - (hir::LifetimeSuggestionPosition::ObjectDefault, span) => (span, "+ 'a".to_owned()), + (hir::LifetimeSuggestionPosition::Normal, span) => { + (span, "'a".to_owned()) + } + (hir::LifetimeSuggestionPosition::Ampersand, span) => { + (span, "'a ".to_owned()) + } + (hir::LifetimeSuggestionPosition::ElidedPath, span) => { + (span, "<'a>".to_owned()) + } + (hir::LifetimeSuggestionPosition::ElidedPathArgument, span) => { + (span, "'a, ".to_owned()) + } + (hir::LifetimeSuggestionPosition::ObjectDefault, span) => { + (span, "+ 'a".to_owned()) + } }; - let suggestions = vec![ - lifetime_sugg, - new_param_sugg, - ]; + let suggestions = vec![lifetime_sugg, new_param_sugg]; diag.span_label( lifetime_ref.ident.span, @@ -1378,7 +1387,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { Scope::Root { opt_parent_item } => { if let Some(parent_item) = opt_parent_item && let parent_generics = self.tcx.generics_of(parent_item) - && parent_generics.param_def_id_to_index(self.tcx, param_def_id.to_def_id()).is_some() + && parent_generics + .param_def_id_to_index(self.tcx, param_def_id.to_def_id()) + .is_some() { break Some(ResolvedArg::EarlyBound(param_def_id.to_def_id())); } @@ -1689,14 +1700,12 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation { let bound_vars = if let Some(type_def_id) = type_def_id && self.tcx.def_kind(type_def_id) == DefKind::Trait - && let Some((mut bound_vars, assoc_fn)) = - BoundVarContext::supertrait_hrtb_vars( - self.tcx, - type_def_id, - binding.ident, - ty::AssocKind::Fn, - ) - { + && let Some((mut bound_vars, assoc_fn)) = BoundVarContext::supertrait_hrtb_vars( + self.tcx, + type_def_id, + binding.ident, + ty::AssocKind::Fn, + ) { bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).params.iter().map( |param| match param.kind { ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region( @@ -1708,14 +1717,14 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const, }, )); - bound_vars - .extend(self.tcx.fn_sig(assoc_fn.def_id).instantiate_identity().bound_vars()); + bound_vars.extend( + self.tcx.fn_sig(assoc_fn.def_id).instantiate_identity().bound_vars(), + ); bound_vars } else { - self.tcx.sess.delay_span_bug( - binding.ident.span, - "bad return type notation here", - ); + self.tcx + .sess + .delay_span_bug(binding.ident.span, "bad return type notation here"); vec![] }; self.with(scope, |this| { diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index ae62119b182..47a412c2110 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -30,10 +30,10 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) if constant.hir_id() == hir_id => { - return tcx.types.usize + return tcx.types.usize; } Node::Ty(&hir::Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => { - return tcx.typeck(def_id).node_type(e.hir_id) + return tcx.typeck(def_id).node_type(e.hir_id); } Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. }) @@ -43,36 +43,38 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { _ => false, }) => { - return tcx.typeck(def_id).node_type(hir_id) + return tcx.typeck(def_id).node_type(hir_id); } Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => { - return tcx - .adt_def(tcx.hir().get_parent_item(hir_id)) - .repr() - .discr_type() - .to_ty(tcx) + return tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx); } Node::GenericParam(&GenericParam { def_id: param_def_id, kind: GenericParamKind::Const { default: Some(ct), .. }, .. }) if ct.hir_id == hir_id => { - return tcx.type_of(param_def_id) + return tcx + .type_of(param_def_id) .no_bound_vars() - .expect("const parameter types cannot be generic") + .expect("const parameter types cannot be generic"); } - Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. }) - if let Node::TraitRef(trait_ref) = tcx.hir().get( - tcx.hir().parent_id(binding_id) - ) => + Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. }) + if let Node::TraitRef(trait_ref) = tcx.hir().get(tcx.hir().parent_id(binding_id)) => { let Some(trait_def_id) = trait_ref.trait_def_id() else { - return Ty::new_error_with_message(tcx,tcx.def_span(def_id), "Could not find trait"); + return Ty::new_error_with_message( + tcx, + tcx.def_span(def_id), + "Could not find trait", + ); }; let assoc_items = tcx.associated_items(trait_def_id); let assoc_item = assoc_items.find_by_name_and_kind( - tcx, binding.ident, ty::AssocKind::Const, def_id.to_def_id(), + tcx, + binding.ident, + ty::AssocKind::Const, + def_id.to_def_id(), ); return if let Some(assoc_item) = assoc_item { tcx.type_of(assoc_item.def_id) @@ -80,8 +82,12 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { .expect("const parameter types cannot be generic") } else { // FIXME(associated_const_equality): add a useful error message here. - Ty::new_error_with_message(tcx,tcx.def_span(def_id), "Could not find associated const on trait") - } + Ty::new_error_with_message( + tcx, + tcx.def_span(def_id), + "Could not find associated const on trait", + ) + }; } // This match arm is for when the def_id appears in a GAT whose @@ -138,7 +144,8 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { (generics, arg_index) } else { // I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU - return Ty::new_error_with_message(tcx, + return Ty::new_error_with_message( + tcx, tcx.def_span(def_id), "unexpected non-GAT usage of an anon const", ); @@ -155,7 +162,8 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { // As there is no relevant param for `def_id`, we simply return // `None` here. let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else { - return Ty::new_error_with_message(tcx, + return Ty::new_error_with_message( + tcx, tcx.def_span(def_id), format!("unable to find type-dependent def for {parent_node_id:?}"), ); @@ -196,14 +204,16 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) { path } else { - return Ty::new_error_with_message(tcx, + return Ty::new_error_with_message( + tcx, tcx.def_span(def_id), format!("unable to find const parent for {hir_id} in pat {pat:?}"), ); } } _ => { - return Ty::new_error_with_message(tcx, + return Ty::new_error_with_message( + tcx, tcx.def_span(def_id), format!("unexpected const parent path {parent_node:?}"), ); @@ -216,16 +226,20 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { let Some((arg_index, segment)) = path.segments.iter().find_map(|seg| { let args = seg.args?; args.args - .iter() - .filter(|arg| arg.is_ty_or_const()) - .position(|arg| arg.hir_id() == hir_id) - .map(|index| (index, seg)).or_else(|| args.bindings .iter() - .filter_map(TypeBinding::opt_const) - .position(|ct| ct.hir_id == hir_id) - .map(|idx| (idx, seg))) + .filter(|arg| arg.is_ty_or_const()) + .position(|arg| arg.hir_id() == hir_id) + .map(|index| (index, seg)) + .or_else(|| { + args.bindings + .iter() + .filter_map(TypeBinding::opt_const) + .position(|ct| ct.hir_id == hir_id) + .map(|idx| (idx, seg)) + }) }) else { - return Ty::new_error_with_message(tcx, + return Ty::new_error_with_message( + tcx, tcx.def_span(def_id), "no arg matching AnonConst in path", ); @@ -234,7 +248,8 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { let generics = match tcx.res_generics_def_id(segment.res) { Some(def_id) => tcx.generics_of(def_id), None => { - return Ty::new_error_with_message(tcx, + return Ty::new_error_with_message( + tcx, tcx.def_span(def_id), format!("unexpected anon const res {:?} in path: {:?}", segment.res, path), ); @@ -244,10 +259,13 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { (generics, arg_index) } - _ => return Ty::new_error_with_message(tcx, - tcx.def_span(def_id), - format!("unexpected const parent in type_of(): {parent_node:?}"), - ), + _ => { + return Ty::new_error_with_message( + tcx, + tcx.def_span(def_id), + format!("unexpected const parent in type_of(): {parent_node:?}"), + ); + } }; debug!(?parent_node); diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 0efe82b20ee..1120585f1aa 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -226,7 +226,9 @@ impl<'a> IntoDiagnostic<'a> for MissingTypeParams { let mut suggested = false; // Don't suggest setting the type params if there are some already: the order is // tricky to get right and the user will already know what the syntax is. - if let Some(snippet) = self.span_snippet && self.empty_generic_args { + if let Some(snippet) = self.span_snippet + && self.empty_generic_args + { if snippet.ends_with('>') { // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion // we would have to preserve the right order. For now, as clearly the user is diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index b4af321fcc9..7941861fd2f 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -131,7 +131,9 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node } fn check_has_items(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) { - if let Node::Impl(impl2_id) = impl2_node && tcx.associated_item_def_ids(impl1_def_id).is_empty() { + if let Node::Impl(impl2_id) = impl2_node + && tcx.associated_item_def_ids(impl1_def_id).is_empty() + { let base_impl_span = tcx.def_span(impl2_id); tcx.sess.emit_err(errors::EmptySpecialization { span, base_impl_span }); } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 03963925d3d..c7b3648099c 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -57,6 +57,9 @@ This API is completely unstable and subject to change. #![allow(rustc::potential_query_instability)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), allow(internal_features))] #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(if_let_guard)] diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs index 61b182b1be7..2b5f6fd214c 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs @@ -316,12 +316,18 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } // Suggest `'_` when in function parameter or elided function return. - if let Some(fn_decl) = node.fn_decl() && let Some(ty_id) = ty_id { + if let Some(fn_decl) = node.fn_decl() + && let Some(ty_id) = ty_id + { let in_arg = fn_decl.inputs.iter().any(|t| t.hir_id == ty_id); - let in_ret = matches!(fn_decl.output, hir::FnRetTy::Return(ty) if ty.hir_id == ty_id); + let in_ret = + matches!(fn_decl.output, hir::FnRetTy::Return(ty) if ty.hir_id == ty_id); if in_arg || (in_ret && fn_decl.lifetime_elision_allowed) { - return std::iter::repeat("'_".to_owned()).take(num_params_to_take).collect::<Vec<_>>().join(", "); + return std::iter::repeat("'_".to_owned()) + .take(num_params_to_take) + .collect::<Vec<_>>() + .join(", "); } } @@ -730,28 +736,27 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { ); if let Some(parent_node) = self.tcx.hir().opt_parent_id(self.path_segment.hir_id) - && let Some(parent_node) = self.tcx.hir().find(parent_node) - && let hir::Node::Expr(expr) = parent_node { + && let Some(parent_node) = self.tcx.hir().find(parent_node) + && let hir::Node::Expr(expr) = parent_node + { match &expr.kind { - hir::ExprKind::Path(qpath) => { - self.suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path( + hir::ExprKind::Path(qpath) => self + .suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path( err, qpath, msg, num_assoc_fn_excess_args, - num_trait_generics_except_self - ) - }, - hir::ExprKind::MethodCall(..) => { - self.suggest_moving_args_from_assoc_fn_to_trait_for_method_call( + num_trait_generics_except_self, + ), + hir::ExprKind::MethodCall(..) => self + .suggest_moving_args_from_assoc_fn_to_trait_for_method_call( err, trait_, expr, msg, num_assoc_fn_excess_args, - num_trait_generics_except_self - ) - }, + num_trait_generics_except_self, + ), _ => return, } } @@ -766,23 +771,25 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { num_trait_generics_except_self: usize, ) { if let hir::QPath::Resolved(_, path) = qpath - && let Some(trait_path_segment) = path.segments.get(0) { + && let Some(trait_path_segment) = path.segments.get(0) + { let num_generic_args_supplied_to_trait = trait_path_segment.args().num_generic_params(); - if num_generic_args_supplied_to_trait + num_assoc_fn_excess_args == num_trait_generics_except_self + if num_generic_args_supplied_to_trait + num_assoc_fn_excess_args + == num_trait_generics_except_self { if let Some(span) = self.gen_args.span_ext() - && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) + { let sugg = vec![ - (self.path_segment.ident.span, format!("{}::{}", snippet, self.path_segment.ident)), - (span.with_lo(self.path_segment.ident.span.hi()), "".to_owned()) + ( + self.path_segment.ident.span, + format!("{}::{}", snippet, self.path_segment.ident), + ), + (span.with_lo(self.path_segment.ident.span.hi()), "".to_owned()), ]; - err.multipart_suggestion( - msg, - sugg, - Applicability::MaybeIncorrect - ); + err.multipart_suggestion(msg, sugg, Applicability::MaybeIncorrect); } } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 8587b009f25..ab6ab391484 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -52,8 +52,6 @@ pub struct NoAnn; impl PpAnn for NoAnn {} pub const NO_ANN: &dyn PpAnn = &NoAnn; -/// Identical to the `PpAnn` implementation for `hir::Crate`, -/// except it avoids creating a dependency on the whole crate. impl PpAnn for &dyn rustc_hir::intravisit::Map<'_> { fn nested(&self, state: &mut State<'_>, nested: Nested) { match nested { @@ -75,7 +73,11 @@ pub struct State<'a> { } impl<'a> State<'a> { - pub fn print_node(&mut self, node: Node<'_>) { + fn attrs(&self, id: hir::HirId) -> &'a [ast::Attribute] { + (self.attrs)(id) + } + + fn print_node(&mut self, node: Node<'_>) { match node { Node::Param(a) => self.print_param(a), Node::Item(a) => self.print_item(a), @@ -144,7 +146,7 @@ impl<'a> PrintState<'a> for State<'a> { } } -pub const INDENT_UNIT: isize = 4; +const INDENT_UNIT: isize = 4; /// Requires you to pass an input filename and reader so that /// it can scan the input text for comments to copy forward. @@ -156,7 +158,12 @@ pub fn print_crate<'a>( attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute], ann: &'a dyn PpAnn, ) -> String { - let mut s = State::new_from_input(sm, filename, input, attrs, ann); + let mut s = State { + s: pp::Printer::new(), + comments: Some(Comments::new(sm, filename, input)), + attrs, + ann, + }; // When printing the AST, we sometimes need to inject `#[no_std]` here. // Since you can't compile the HIR, it's not necessary. @@ -166,28 +173,7 @@ pub fn print_crate<'a>( s.s.eof() } -impl<'a> State<'a> { - pub fn new_from_input( - sm: &'a SourceMap, - filename: FileName, - input: String, - attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute], - ann: &'a dyn PpAnn, - ) -> State<'a> { - State { - s: pp::Printer::new(), - comments: Some(Comments::new(sm, filename, input)), - attrs, - ann, - } - } - - fn attrs(&self, id: hir::HirId) -> &'a [ast::Attribute] { - (self.attrs)(id) - } -} - -pub fn to_string<F>(ann: &dyn PpAnn, f: F) -> String +fn to_string<F>(ann: &dyn PpAnn, f: F) -> String where F: FnOnce(&mut State<'_>), { @@ -196,52 +182,20 @@ where printer.s.eof() } -pub fn generic_params_to_string(generic_params: &[GenericParam<'_>]) -> String { - to_string(NO_ANN, |s| s.print_generic_params(generic_params)) -} - -pub fn bounds_to_string<'b>(bounds: impl IntoIterator<Item = &'b hir::GenericBound<'b>>) -> String { - to_string(NO_ANN, |s| s.print_bounds("", bounds)) -} - pub fn ty_to_string(ty: &hir::Ty<'_>) -> String { to_string(NO_ANN, |s| s.print_type(ty)) } -pub fn path_segment_to_string(segment: &hir::PathSegment<'_>) -> String { - to_string(NO_ANN, |s| s.print_path_segment(segment)) -} - -pub fn path_to_string(segment: &hir::Path<'_>) -> String { - to_string(NO_ANN, |s| s.print_path(segment, false)) -} - pub fn qpath_to_string(segment: &hir::QPath<'_>) -> String { to_string(NO_ANN, |s| s.print_qpath(segment, false)) } -pub fn fn_to_string( - decl: &hir::FnDecl<'_>, - header: hir::FnHeader, - name: Option<Symbol>, - generics: &hir::Generics<'_>, - arg_names: &[Ident], - body_id: Option<hir::BodyId>, -) -> String { - to_string(NO_ANN, |s| s.print_fn(decl, header, name, generics, arg_names, body_id)) -} - -pub fn enum_def_to_string( - enum_definition: &hir::EnumDef<'_>, - generics: &hir::Generics<'_>, - name: Symbol, - span: rustc_span::Span, -) -> String { - to_string(NO_ANN, |s| s.print_enum_def(enum_definition, generics, name, span)) +pub fn pat_to_string(pat: &hir::Pat<'_>) -> String { + to_string(NO_ANN, |s| s.print_pat(pat)) } impl<'a> State<'a> { - pub fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) { + fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) { self.maybe_print_comment(span.hi()); self.break_offset_if_not_bol(1, -INDENT_UNIT); self.word("}"); @@ -250,11 +204,11 @@ impl<'a> State<'a> { } } - pub fn bclose(&mut self, span: rustc_span::Span) { + fn bclose(&mut self, span: rustc_span::Span) { self.bclose_maybe_open(span, true) } - pub fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G) + fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G) where F: FnMut(&mut State<'_>, &T), G: FnMut(&T) -> rustc_span::Span, @@ -275,25 +229,25 @@ impl<'a> State<'a> { self.end(); } - pub fn commasep_exprs(&mut self, b: Breaks, exprs: &[hir::Expr<'_>]) { + fn commasep_exprs(&mut self, b: Breaks, exprs: &[hir::Expr<'_>]) { self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span); } - pub fn print_mod(&mut self, _mod: &hir::Mod<'_>, attrs: &[ast::Attribute]) { + fn print_mod(&mut self, _mod: &hir::Mod<'_>, attrs: &[ast::Attribute]) { self.print_inner_attributes(attrs); for &item_id in _mod.item_ids { self.ann.nested(self, Nested::Item(item_id)); } } - pub fn print_opt_lifetime(&mut self, lifetime: &hir::Lifetime) { + fn print_opt_lifetime(&mut self, lifetime: &hir::Lifetime) { if !lifetime.is_elided() { self.print_lifetime(lifetime); self.nbsp(); } } - pub fn print_type(&mut self, ty: &hir::Ty<'_>) { + fn print_type(&mut self, ty: &hir::Ty<'_>) { self.maybe_print_comment(ty.span.lo()); self.ibox(0); match ty.kind { @@ -371,7 +325,7 @@ impl<'a> State<'a> { self.end() } - pub fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) { + fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) { self.hardbreak_if_not_bol(); self.maybe_print_comment(item.span.lo()); self.print_outer_attributes(self.attrs(item.hir_id())); @@ -478,8 +432,7 @@ impl<'a> State<'a> { self.end(); // end the outer ibox } - /// Pretty-print an item - pub fn print_item(&mut self, item: &hir::Item<'_>) { + fn print_item(&mut self, item: &hir::Item<'_>) { self.hardbreak_if_not_bol(); self.maybe_print_comment(item.span.lo()); let attrs = self.attrs(item.hir_id()); @@ -704,7 +657,7 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::Item(item)) } - pub fn print_trait_ref(&mut self, t: &hir::TraitRef<'_>) { + fn print_trait_ref(&mut self, t: &hir::TraitRef<'_>) { self.print_path(t.path, false); } @@ -721,7 +674,7 @@ impl<'a> State<'a> { self.print_trait_ref(&t.trait_ref); } - pub fn print_enum_def( + fn print_enum_def( &mut self, enum_definition: &hir::EnumDef<'_>, generics: &hir::Generics<'_>, @@ -736,7 +689,7 @@ impl<'a> State<'a> { self.print_variants(enum_definition.variants, span); } - pub fn print_variants(&mut self, variants: &[hir::Variant<'_>], span: rustc_span::Span) { + fn print_variants(&mut self, variants: &[hir::Variant<'_>], span: rustc_span::Span) { self.bopen(); for v in variants { self.space_if_not_bol(); @@ -751,14 +704,14 @@ impl<'a> State<'a> { self.bclose(span) } - pub fn print_defaultness(&mut self, defaultness: hir::Defaultness) { + fn print_defaultness(&mut self, defaultness: hir::Defaultness) { match defaultness { hir::Defaultness::Default { .. } => self.word_nbsp("default"), hir::Defaultness::Final => (), } } - pub fn print_struct( + fn print_struct( &mut self, struct_def: &hir::VariantData<'_>, generics: &hir::Generics<'_>, @@ -807,7 +760,7 @@ impl<'a> State<'a> { } } - pub fn print_variant(&mut self, v: &hir::Variant<'_>) { + fn print_variant(&mut self, v: &hir::Variant<'_>) { self.head(""); let generics = hir::Generics::empty(); self.print_struct(&v.data, generics, v.ident.name, v.span, false); @@ -817,7 +770,8 @@ impl<'a> State<'a> { self.print_anon_const(d); } } - pub fn print_method_sig( + + fn print_method_sig( &mut self, ident: Ident, m: &hir::FnSig<'_>, @@ -828,7 +782,7 @@ impl<'a> State<'a> { self.print_fn(m.decl, m.header, Some(ident.name), generics, arg_names, body_id); } - pub fn print_trait_item(&mut self, ti: &hir::TraitItem<'_>) { + fn print_trait_item(&mut self, ti: &hir::TraitItem<'_>) { self.ann.pre(self, AnnNode::SubItem(ti.hir_id())); self.hardbreak_if_not_bol(); self.maybe_print_comment(ti.span.lo()); @@ -856,7 +810,7 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::SubItem(ti.hir_id())) } - pub fn print_impl_item(&mut self, ii: &hir::ImplItem<'_>) { + fn print_impl_item(&mut self, ii: &hir::ImplItem<'_>) { self.ann.pre(self, AnnNode::SubItem(ii.hir_id())); self.hardbreak_if_not_bol(); self.maybe_print_comment(ii.span.lo()); @@ -881,7 +835,7 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::SubItem(ii.hir_id())) } - pub fn print_local( + fn print_local( &mut self, init: Option<&hir::Expr<'_>>, els: Option<&hir::Block<'_>>, @@ -914,7 +868,7 @@ impl<'a> State<'a> { self.end() } - pub fn print_stmt(&mut self, st: &hir::Stmt<'_>) { + fn print_stmt(&mut self, st: &hir::Stmt<'_>) { self.maybe_print_comment(st.span.lo()); match st.kind { hir::StmtKind::Local(loc) => { @@ -937,19 +891,19 @@ impl<'a> State<'a> { self.maybe_print_trailing_comment(st.span, None) } - pub fn print_block(&mut self, blk: &hir::Block<'_>) { + fn print_block(&mut self, blk: &hir::Block<'_>) { self.print_block_with_attrs(blk, &[]) } - pub fn print_block_unclosed(&mut self, blk: &hir::Block<'_>) { + fn print_block_unclosed(&mut self, blk: &hir::Block<'_>) { self.print_block_maybe_unclosed(blk, &[], false) } - pub fn print_block_with_attrs(&mut self, blk: &hir::Block<'_>, attrs: &[ast::Attribute]) { + fn print_block_with_attrs(&mut self, blk: &hir::Block<'_>, attrs: &[ast::Attribute]) { self.print_block_maybe_unclosed(blk, attrs, true) } - pub fn print_block_maybe_unclosed( + fn print_block_maybe_unclosed( &mut self, blk: &hir::Block<'_>, attrs: &[ast::Attribute], @@ -1005,7 +959,7 @@ impl<'a> State<'a> { } } - pub fn print_if( + fn print_if( &mut self, test: &hir::Expr<'_>, blk: &hir::Expr<'_>, @@ -1018,14 +972,14 @@ impl<'a> State<'a> { self.print_else(elseopt) } - pub fn print_array_length(&mut self, len: &hir::ArrayLen) { + fn print_array_length(&mut self, len: &hir::ArrayLen) { match len { hir::ArrayLen::Infer(_, _) => self.word("_"), hir::ArrayLen::Body(ct) => self.print_anon_const(ct), } } - pub fn print_anon_const(&mut self, constant: &hir::AnonConst) { + fn print_anon_const(&mut self, constant: &hir::AnonConst) { self.ann.nested(self, Nested::Body(constant.body)) } @@ -1041,7 +995,7 @@ impl<'a> State<'a> { /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in /// `if cond { ... }`. - pub fn print_expr_as_cond(&mut self, expr: &hir::Expr<'_>) { + fn print_expr_as_cond(&mut self, expr: &hir::Expr<'_>) { self.print_expr_cond_paren(expr, Self::cond_needs_par(expr)) } @@ -1360,7 +1314,7 @@ impl<'a> State<'a> { self.pclose(); } - pub fn print_expr(&mut self, expr: &hir::Expr<'_>) { + fn print_expr(&mut self, expr: &hir::Expr<'_>) { self.maybe_print_comment(expr.span.lo()); self.print_outer_attributes(self.attrs(expr.hir_id)); self.ibox(INDENT_UNIT); @@ -1593,7 +1547,7 @@ impl<'a> State<'a> { self.end() } - pub fn print_local_decl(&mut self, loc: &hir::Local<'_>) { + fn print_local_decl(&mut self, loc: &hir::Local<'_>) { self.print_pat(loc.pat); if let Some(ty) = loc.ty { self.word_space(":"); @@ -1601,11 +1555,11 @@ impl<'a> State<'a> { } } - pub fn print_name(&mut self, name: Symbol) { + fn print_name(&mut self, name: Symbol) { self.print_ident(Ident::with_dummy_span(name)) } - pub fn print_path<R>(&mut self, path: &hir::Path<'_, R>, colons_before_params: bool) { + fn print_path<R>(&mut self, path: &hir::Path<'_, R>, colons_before_params: bool) { self.maybe_print_comment(path.span.lo()); for (i, segment) in path.segments.iter().enumerate() { @@ -1619,14 +1573,14 @@ impl<'a> State<'a> { } } - pub fn print_path_segment(&mut self, segment: &hir::PathSegment<'_>) { + fn print_path_segment(&mut self, segment: &hir::PathSegment<'_>) { if segment.ident.name != kw::PathRoot { self.print_ident(segment.ident); self.print_generic_args(segment.args(), false); } } - pub fn print_qpath(&mut self, qpath: &hir::QPath<'_>, colons_before_params: bool) { + fn print_qpath(&mut self, qpath: &hir::QPath<'_>, colons_before_params: bool) { match *qpath { hir::QPath::Resolved(None, path) => self.print_path(path, colons_before_params), hir::QPath::Resolved(Some(qself), path) => { @@ -1743,7 +1697,7 @@ impl<'a> State<'a> { } } - pub fn print_type_binding(&mut self, binding: &hir::TypeBinding<'_>) { + fn print_type_binding(&mut self, binding: &hir::TypeBinding<'_>) { self.print_ident(binding.ident); self.print_generic_args(binding.gen_args, false); self.space(); @@ -1761,7 +1715,7 @@ impl<'a> State<'a> { } } - pub fn print_pat(&mut self, pat: &hir::Pat<'_>) { + fn print_pat(&mut self, pat: &hir::Pat<'_>) { self.maybe_print_comment(pat.span.lo()); self.ann.pre(self, AnnNode::Pat(pat)); // Pat isn't normalized, but the beauty of it @@ -1905,7 +1859,7 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::Pat(pat)) } - pub fn print_patfield(&mut self, field: &hir::PatField<'_>) { + fn print_patfield(&mut self, field: &hir::PatField<'_>) { if self.attrs(field.hir_id).is_empty() { self.space(); } @@ -1919,12 +1873,12 @@ impl<'a> State<'a> { self.end(); } - pub fn print_param(&mut self, arg: &hir::Param<'_>) { + fn print_param(&mut self, arg: &hir::Param<'_>) { self.print_outer_attributes(self.attrs(arg.hir_id)); self.print_pat(arg.pat); } - pub fn print_arm(&mut self, arm: &hir::Arm<'_>) { + fn print_arm(&mut self, arm: &hir::Arm<'_>) { // I have no idea why this check is necessary, but here it // is :( if self.attrs(arm.hir_id).is_empty() { @@ -1976,7 +1930,7 @@ impl<'a> State<'a> { self.end() // close enclosing cbox } - pub fn print_fn( + fn print_fn( &mut self, decl: &hir::FnDecl<'_>, header: hir::FnHeader, @@ -2056,14 +2010,14 @@ impl<'a> State<'a> { } } - pub fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) { + fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) { match capture_clause { hir::CaptureBy::Value => self.word_space("move"), hir::CaptureBy::Ref => {} } } - pub fn print_closure_binder( + fn print_closure_binder( &mut self, binder: hir::ClosureBinder, generic_params: &[GenericParam<'_>], @@ -2083,7 +2037,8 @@ impl<'a> State<'a> { match binder { hir::ClosureBinder::Default => {} - // we need to distinguish `|...| {}` from `for<> |...| {}` as `for<>` adds additional restrictions + // We need to distinguish `|...| {}` from `for<> |...| {}` as `for<>` adds additional + // restrictions. hir::ClosureBinder::For { .. } if generic_params.is_empty() => self.word("for<>"), hir::ClosureBinder::For { .. } => { self.word("for"); @@ -2099,7 +2054,7 @@ impl<'a> State<'a> { } } - pub fn print_bounds<'b>( + fn print_bounds<'b>( &mut self, prefix: &'static str, bounds: impl IntoIterator<Item = &'b hir::GenericBound<'b>>, @@ -2137,7 +2092,7 @@ impl<'a> State<'a> { } } - pub fn print_generic_params(&mut self, generic_params: &[GenericParam<'_>]) { + fn print_generic_params(&mut self, generic_params: &[GenericParam<'_>]) { if !generic_params.is_empty() { self.word("<"); @@ -2147,7 +2102,7 @@ impl<'a> State<'a> { } } - pub fn print_generic_param(&mut self, param: &GenericParam<'_>) { + fn print_generic_param(&mut self, param: &GenericParam<'_>) { if let GenericParamKind::Const { .. } = param.kind { self.word_space("const"); } @@ -2175,11 +2130,11 @@ impl<'a> State<'a> { } } - pub fn print_lifetime(&mut self, lifetime: &hir::Lifetime) { + fn print_lifetime(&mut self, lifetime: &hir::Lifetime) { self.print_ident(lifetime.ident) } - pub fn print_where_clause(&mut self, generics: &hir::Generics<'_>) { + fn print_where_clause(&mut self, generics: &hir::Generics<'_>) { if generics.predicates.is_empty() { return; } @@ -2236,7 +2191,7 @@ impl<'a> State<'a> { } } - pub fn print_mutability(&mut self, mutbl: hir::Mutability, print_const: bool) { + fn print_mutability(&mut self, mutbl: hir::Mutability, print_const: bool) { match mutbl { hir::Mutability::Mut => self.word_nbsp("mut"), hir::Mutability::Not => { @@ -2247,12 +2202,12 @@ impl<'a> State<'a> { } } - pub fn print_mt(&mut self, mt: &hir::MutTy<'_>, print_const: bool) { + fn print_mt(&mut self, mt: &hir::MutTy<'_>, print_const: bool) { self.print_mutability(mt.mutbl, print_const); self.print_type(mt.ty); } - pub fn print_fn_output(&mut self, decl: &hir::FnDecl<'_>) { + fn print_fn_output(&mut self, decl: &hir::FnDecl<'_>) { if let hir::FnRetTy::DefaultReturn(..) = decl.output { return; } @@ -2271,7 +2226,7 @@ impl<'a> State<'a> { } } - pub fn print_ty_fn( + fn print_ty_fn( &mut self, abi: Abi, unsafety: hir::Unsafety, @@ -2299,7 +2254,7 @@ impl<'a> State<'a> { self.end(); } - pub fn print_fn_header_info(&mut self, header: hir::FnHeader) { + fn print_fn_header_info(&mut self, header: hir::FnHeader) { self.print_constness(header.constness); match header.asyncness { @@ -2317,21 +2272,21 @@ impl<'a> State<'a> { self.word("fn") } - pub fn print_constness(&mut self, s: hir::Constness) { + fn print_constness(&mut self, s: hir::Constness) { match s { hir::Constness::NotConst => {} hir::Constness::Const => self.word_nbsp("const"), } } - pub fn print_unsafety(&mut self, s: hir::Unsafety) { + fn print_unsafety(&mut self, s: hir::Unsafety) { match s { hir::Unsafety::Normal => {} hir::Unsafety::Unsafe => self.word_nbsp("unsafe"), } } - pub fn print_is_auto(&mut self, s: hir::IsAuto) { + fn print_is_auto(&mut self, s: hir::IsAuto) { match s { hir::IsAuto::Yes => self.word_nbsp("auto"), hir::IsAuto::No => {} diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 81fe0cc489e..aef880acbe1 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -373,7 +373,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 6 | | }; // | |_____^ expected integer, found `()` // ``` - if block.expr.is_none() && block.stmts.is_empty() + if block.expr.is_none() + && block.stmts.is_empty() && let Some(outer_span) = &mut outer_span && let Some(cond_span) = cond_span.find_ancestor_inside(*outer_span) { diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index f2c58ee2702..78d30f3aa12 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -421,13 +421,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .steal_diagnostic(segment.ident.span, StashKey::CallIntoMethod) { // Try suggesting `foo(a)` -> `a.foo()` if possible. - self.suggest_call_as_method( - &mut diag, - segment, - arg_exprs, - call_expr, - expected - ); + self.suggest_call_as_method(&mut diag, segment, arg_exprs, call_expr, expected); diag.emit(); } @@ -656,7 +650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .sess .source_map() .is_multiline(call_expr.span.with_lo(callee_expr.span.hi())) - && call_expr.span.ctxt() == callee_expr.span.ctxt(); + && call_expr.span.eq_ctxt(callee_expr.span); if call_is_multiline { err.span_suggestion( callee_expr.span.shrink_to_hi(), @@ -792,8 +786,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.consts.false_ } Some(hir::ConstContext::ConstFn) => { - let args = ty::GenericArgs::identity_for_item(tcx, context); - args.host_effect_param().expect("ConstContext::Maybe must have host effect param") + 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_, }; diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 2b1ac7f3537..419e154a17a 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -373,50 +373,49 @@ impl<'a, 'tcx> CastCheck<'tcx> { let mut sugg_mutref = false; if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() { if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind() - && fcx - .can_coerce( - Ty::new_ref(fcx.tcx, - fcx.tcx.lifetimes.re_erased, - TypeAndMut { ty: expr_ty, mutbl }, - ), - self.cast_ty, - ) + && fcx.can_coerce( + Ty::new_ref( + fcx.tcx, + fcx.tcx.lifetimes.re_erased, + TypeAndMut { ty: expr_ty, mutbl }, + ), + self.cast_ty, + ) { sugg = Some((format!("&{}*", mutbl.prefix_str()), cast_ty == expr_ty)); } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind() && expr_mutbl == Mutability::Not && mutbl == Mutability::Mut - && fcx - .can_coerce( - Ty::new_ref(fcx.tcx, - expr_reg, - TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut }, - ), - self.cast_ty, - ) + && fcx.can_coerce( + Ty::new_ref( + fcx.tcx, + expr_reg, + TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut }, + ), + self.cast_ty, + ) { sugg_mutref = true; } if !sugg_mutref && sugg == None - && fcx - .can_coerce( - Ty::new_ref(fcx.tcx,reg, TypeAndMut { ty: self.expr_ty, mutbl }), - self.cast_ty, - ) + && fcx.can_coerce( + Ty::new_ref(fcx.tcx, reg, TypeAndMut { ty: self.expr_ty, mutbl }), + self.cast_ty, + ) { sugg = Some((format!("&{}", mutbl.prefix_str()), false)); } } else if let ty::RawPtr(TypeAndMut { mutbl, .. }) = *self.cast_ty.kind() - && fcx - .can_coerce( - Ty::new_ref(fcx.tcx, - fcx.tcx.lifetimes.re_erased, - TypeAndMut { ty: self.expr_ty, mutbl }, - ), - self.cast_ty, - ) + && fcx.can_coerce( + Ty::new_ref( + fcx.tcx, + fcx.tcx.lifetimes.re_erased, + TypeAndMut { ty: self.expr_ty, mutbl }, + ), + self.cast_ty, + ) { sugg = Some((format!("&{}", mutbl.prefix_str()), false)); } @@ -942,10 +941,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { lint::builtin::CENUM_IMPL_DROP_CAST, self.expr.hir_id, self.span, - errors::CastEnumDrop { - expr_ty, - cast_ty, - } + errors::CastEnumDrop { expr_ty, cast_ty }, ); } } diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index c8ffd7d1506..26ea7b0fdb9 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -55,18 +55,22 @@ pub(super) fn check_fn<'a, 'tcx>( fn_maybe_err(tcx, span, fn_sig.abi); - if let Some(kind) = body.generator_kind && can_be_generator.is_some() { + if let Some(kind) = body.generator_kind + && can_be_generator.is_some() + { let yield_ty = if kind == hir::GeneratorKind::Gen { - let yield_ty = fcx - .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }); + let yield_ty = fcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + }); fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); yield_ty } else { - Ty::new_unit(tcx,) + Ty::new_unit(tcx) }; // Resume type defaults to `()` if the generator has no argument. - let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| Ty::new_unit(tcx,)); + let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| Ty::new_unit(tcx)); fcx.resume_yield_tys = Some((resume_ty, yield_ty)); } @@ -173,7 +177,9 @@ pub(super) fn check_fn<'a, 'tcx>( check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig); } - if let Some(lang_start_defid) = tcx.lang_items().start_fn() && lang_start_defid == fn_def_id.to_def_id() { + if let Some(lang_start_defid) = tcx.lang_items().start_fn() + && lang_start_defid == fn_def_id.to_def_id() + { check_lang_start_fn(tcx, fn_sig, fn_def_id); } diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index e426b937542..06542b0cc24 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -56,7 +56,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // closure sooner rather than later, so first examine the expected // type, and see if can glean a closure kind from there. let (expected_sig, expected_kind) = match expected.to_option(self) { - Some(ty) => self.deduce_closure_signature(ty), + Some(ty) => { + self.deduce_closure_signature(self.try_structurally_resolve_type(expr_span, ty)) + } None => (None, None), }; let body = self.tcx.hir().body(closure.body); @@ -226,7 +228,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Given a Projection predicate, we can potentially infer // the complete signature. if expected_sig.is_none() - && let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj_predicate)) = bound_predicate.skip_binder() + && let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj_predicate)) = + bound_predicate.skip_binder() { let inferred_sig = self.normalize( span, @@ -688,8 +691,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span_bug!(self.tcx.def_span(expr_def_id), "async fn generator outside of a fn") }); + let closure_span = self.tcx.def_span(expr_def_id); let ret_ty = ret_coercion.borrow().expected_ty(); - let ret_ty = self.inh.infcx.shallow_resolve(ret_ty); + let ret_ty = self.try_structurally_resolve_type(closure_span, ret_ty); let get_future_output = |predicate: ty::Predicate<'tcx>, span| { // Search for a pending obligation like @@ -711,8 +715,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - let span = self.tcx.def_span(expr_def_id); - let output_ty = match *ret_ty.kind() { ty::Infer(ty::TyVar(ret_vid)) => { self.obligations_for_self_ty(ret_vid).find_map(|obligation| { @@ -726,17 +728,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?, ty::Error(_) => return None, _ => span_bug!( - span, + closure_span, "async fn generator return type not an inference variable: {ret_ty}" ), }; - let output_ty = self.normalize(span, output_ty); + let output_ty = self.normalize(closure_span, output_ty); // async fn that have opaque types in their return type need to redo the conversion to inference variables // as they fetch the still opaque version from the signature. let InferOk { value: output_ty, obligations } = self - .replace_opaque_types_with_inference_vars(output_ty, body_def_id, span, self.param_env); + .replace_opaque_types_with_inference_vars( + output_ty, + body_def_id, + closure_span, + self.param_env, + ); self.register_predicates(obligations); Some(output_ty) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index fca675ea9d8..6c03bc3b57a 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1619,8 +1619,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { unsized_return = self.is_return_ty_definitely_unsized(fcx); } if let Some(expression) = expression - && let hir::ExprKind::Loop(loop_blk, ..) = expression.kind { - intravisit::walk_block(& mut visitor, loop_blk); + && let hir::ExprKind::Loop(loop_blk, ..) = expression.kind + { + intravisit::walk_block(&mut visitor, loop_blk); } } ObligationCauseCode::ReturnValue(id) => { @@ -1661,7 +1662,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { ); } - if visitor.ret_exprs.len() > 0 && let Some(expr) = expression { + if visitor.ret_exprs.len() > 0 + && let Some(expr) = expression + { self.note_unreachable_loop_return(&mut err, &expr, &visitor.ret_exprs); } @@ -1723,7 +1726,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { let parent_id = fcx.tcx.hir().parent_id(id); let parent = fcx.tcx.hir().get(parent_id); if let Some(expr) = expression - && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { body, .. }), .. }) = parent + && let hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Closure(&hir::Closure { body, .. }), + .. + }) = parent && !matches!(fcx.tcx.hir().body(body).value.kind, hir::ExprKind::Block(..)) { fcx.suggest_missing_semicolon(&mut err, expr, expected, true); @@ -1798,12 +1804,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { && let Some(fn_sig) = fcx.body_fn_sig() && fn_sig.output().is_ty_var() { - err.span_note( - sp, - format!( - "return type inferred to be `{expected}` here" - ), - ); + err.span_note(sp, format!("return type inferred to be `{expected}` here")); } err diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 5c3f2b85966..65ec2f232ae 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -151,7 +151,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let [segment] = path.segments && segment.ident.name.as_str() == name && let Res::Local(hir_id) = path.res - && let Some((_, hir::Node::Expr(match_expr))) = self.tcx.hir().parent_iter(hir_id).nth(2) + && let Some((_, hir::Node::Expr(match_expr))) = + self.tcx.hir().parent_iter(hir_id).nth(2) && let hir::ExprKind::Match(scrutinee, _, _) = match_expr.kind && let hir::ExprKind::Tup(exprs) = scrutinee.kind && let hir::ExprKind::AddrOf(_, _, macro_arg) = exprs[idx].kind @@ -450,20 +451,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If our binding became incompatible while it was a receiver // to a method call, we may be able to make a better guess to // the source of a type mismatch. - let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else { continue; }; + let Some(rcvr_ty) = self.node_ty_opt(rcvr.hir_id) else { + continue; + }; let rcvr_ty = rcvr_ty.fold_with(&mut fudger); - let Ok(method) = - self.lookup_method_for_diagnostic(rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr) - else { + let Ok(method) = self.lookup_method_for_diagnostic( + rcvr_ty, + segment, + DUMMY_SP, + parent_expr, + rcvr, + ) else { continue; }; let ideal_rcvr_ty = rcvr_ty.fold_with(&mut fudger); let ideal_method = self - .lookup_method_for_diagnostic(ideal_rcvr_ty, segment, DUMMY_SP, parent_expr, rcvr) + .lookup_method_for_diagnostic( + ideal_rcvr_ty, + segment, + DUMMY_SP, + parent_expr, + rcvr, + ) .ok() .and_then(|method| { - let _ = self.at(&ObligationCause::dummy(), self.param_env) + let _ = self + .at(&ObligationCause::dummy(), self.param_env) .eq(DefineOpaqueTypes::No, ideal_rcvr_ty, expected_ty) .ok()?; Some(method) @@ -474,15 +488,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for (idx, (expected_arg_ty, arg_expr)) in std::iter::zip(&method.sig.inputs()[1..], args).enumerate() { - let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else { continue; }; + let Some(arg_ty) = self.node_ty_opt(arg_expr.hir_id) else { + continue; + }; let arg_ty = arg_ty.fold_with(&mut fudger); - let _ = self.coerce( - arg_expr, - arg_ty, - *expected_arg_ty, - AllowTwoPhase::No, - None, - ); + let _ = + self.coerce(arg_expr, arg_ty, *expected_arg_ty, AllowTwoPhase::No, None); self.select_obligations_where_possible(|errs| { // Yeet the errors, we're already reporting errors. errs.clear(); @@ -648,10 +659,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None => self.tcx.types.unit, }; if self.can_eq(self.param_env, ty, expected) { - err.span_label( - ex.span, - "expected because of this `break`", - ); + err.span_label(ex.span, "expected because of this `break`"); exit = true; } } @@ -1410,10 +1418,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let bind = self.tcx.hir().find(*bind_hir_id); let parent = self.tcx.hir().find(self.tcx.hir().parent_id(*bind_hir_id)); - if let Some(hir::Node::Pat(hir::Pat { kind: hir::PatKind::Binding(_, _hir_id, _, _), .. })) = bind && - let Some(hir::Node::Pat(hir::Pat { default_binding_modes: false, .. })) = parent { - return true; - } + if let Some(hir::Node::Pat(hir::Pat { + kind: hir::PatKind::Binding(_, _hir_id, _, _), + .. + })) = bind + && let Some(hir::Node::Pat(hir::Pat { default_binding_modes: false, .. })) = parent + { + return true; + } } return false; } @@ -1507,10 +1519,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // ``` let ref_ty = match mutability { hir::Mutability::Mut => { - Ty::new_mut_ref(self.tcx,self.tcx.lifetimes.re_static, checked_ty) + Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, checked_ty) } hir::Mutability::Not => { - Ty::new_imm_ref(self.tcx,self.tcx.lifetimes.re_static, checked_ty) + Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, checked_ty) } }; if self.can_coerce(ref_ty, expected) { @@ -1566,7 +1578,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } - let prefix = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { + let prefix = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) + { Some(ident) => format!("{ident}: "), None => String::new(), }; @@ -1611,8 +1624,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let make_sugg = |start: Span, end: BytePos| { // skip `(` for tuples such as `(c) = (&123)`. // make sure we won't suggest like `(c) = 123)` which is incorrect. - let sp = sm.span_extend_while(start.shrink_to_lo(), |c| c == '(' || c.is_whitespace()) - .map_or(start, |s| s.shrink_to_hi()); + let sp = sm + .span_extend_while(start.shrink_to_lo(), |c| c == '(' || c.is_whitespace()) + .map_or(start, |s| s.shrink_to_hi()); Some(( vec![(sp.with_hi(end), String::new())], "consider removing the borrow".to_string(), @@ -1635,12 +1649,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .find(|&s| sp.contains(s)) && sm.is_span_accessible(call_span) { - return make_sugg(sp, call_span.lo()) + return make_sugg(sp, call_span.lo()); } return None; } if sp.contains(expr.span) && sm.is_span_accessible(expr.span) { - return make_sugg(sp, expr.span.lo()) + return make_sugg(sp, expr.span.lo()); } } ( @@ -1760,10 +1774,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) }; - let prefix = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { - Some(ident) => format!("{ident}: "), - None => String::new(), - }; + let prefix = + match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { + Some(ident) => format!("{ident}: "), + None => String::new(), + }; let (span, suggestion) = if self.is_else_if_block(expr) { // Don't suggest nonsense like `else *if` diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index a00f3c5d0d8..96df0346ac6 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -717,7 +717,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // ... except when we try to 'break rust;'. // ICE this expression in particular (see #43162). if let ExprKind::Path(QPath::Resolved(_, path)) = e.kind { - if let [segment] = path.segments && segment.ident.name == sym::rust { + if let [segment] = path.segments + && segment.ident.name == sym::rust + { fatally_break_rust(self.tcx); } } @@ -826,7 +828,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let ExprKind::Block(body, _) = return_expr.kind && let Some(last_expr) = body.expr { - span = last_expr.span; + span = last_expr.span; } ret_coercion.borrow_mut().coerce( self, @@ -841,7 +843,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Point any obligations that were registered due to opaque type // inference at the return expression. self.select_obligations_where_possible(|errors| { - self.point_at_return_for_opaque_ty_error(errors, span, return_expr_ty, return_expr.span); + self.point_at_return_for_opaque_ty_error( + errors, + span, + return_expr_ty, + return_expr.span, + ); }); } } @@ -1402,7 +1409,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length && let Some(span) = self.tcx.hir().opt_span(hir_id) { - match self.tcx.sess.diagnostic().steal_diagnostic(span, StashKey::UnderscoreForArrayLengths) { + match self + .tcx + .sess + .diagnostic() + .steal_diagnostic(span, StashKey::UnderscoreForArrayLengths) + { Some(mut err) => { err.span_suggestion( span, @@ -1412,7 +1424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); err.emit(); } - None => () + None => (), } } } @@ -1931,11 +1943,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err: &mut Diagnostic, ) { // I don't use 'is_range_literal' because only double-sided, half-open ranges count. - if let ExprKind::Struct( - QPath::LangItem(LangItem::Range, ..), - [range_start, range_end], - _, - ) = last_expr_field.expr.kind + if let ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), [range_start, range_end], _) = + last_expr_field.expr.kind && let variant_field = variant.fields.iter().find(|field| field.ident(self.tcx) == last_expr_field.ident) && let range_def_id = self.tcx.lang_items().range_struct() @@ -1970,13 +1979,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .sess .source_map() .span_extend_while(range_start.span, |c| c.is_whitespace()) - .unwrap_or(range_start.span).shrink_to_hi().to(range_end.span); + .unwrap_or(range_start.span) + .shrink_to_hi() + .to(range_end.span); - err.subdiagnostic(TypeMismatchFruTypo { - expr_span: range_start.span, - fru_span, - expr, - }); + err.subdiagnostic(TypeMismatchFruTypo { expr_span: range_start.span, fru_span, expr }); } } @@ -2293,7 +2300,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some('e') | Some('E') => { chars.next(); if let Some(c) = chars.peek() - && !c.is_numeric() && *c != '-' && *c != '+' + && !c.is_numeric() + && *c != '-' + && *c != '+' { return false; } @@ -2421,7 +2430,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } self.suggest_fn_call(&mut err, base, base_ty, |output_ty| { - if let ty::Adt(def, _) = output_ty.kind() && !def.is_enum() { + if let ty::Adt(def, _) = output_ty.kind() + && !def.is_enum() + { def.non_enum_variant().fields.iter().any(|field| { field.ident(self.tcx) == ident && field.vis.is_accessible_from(expr.hir_id.owner.def_id, self.tcx) @@ -2842,9 +2853,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // fixed expression: if let ExprKind::Lit(ref lit) = idx.kind && let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node - && i < types.len().try_into().expect("expected tuple index to be < usize length") + && i < types + .len() + .try_into() + .expect("expected tuple index to be < usize length") { - err.span_suggestion( brackets_span, "to access tuple elements, use", @@ -2853,7 +2866,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); needs_note = false; } else if let ExprKind::Path(..) = idx.peel_borrows().kind { - err.span_label(idx.span, "cannot access tuple elements at a variable index"); + err.span_label( + idx.span, + "cannot access tuple elements at a variable index", + ); } if needs_note { err.help( diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 952b90d6a35..38b780367e6 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -142,7 +142,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // type, `?T` is not considered unsolved, but `?I` is. The // same is true for float variables.) let fallback = match ty.kind() { - _ if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx,e), + _ if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx, e), ty::Infer(ty::IntVar(_)) => self.tcx.types.i32, ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64, _ => match diverging_fallback.get(&ty) { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 5dae74a1f9b..6e0e02b7814 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -445,7 +445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { match self.typeck_results.borrow().node_types().get(id) { Some(&t) => t, - None if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx,e), + None if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx, e), None => { bug!( "no type for node {} in fcx {}", @@ -459,7 +459,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn node_ty_opt(&self, id: hir::HirId) -> Option<Ty<'tcx>> { match self.typeck_results.borrow().node_types().get(id) { Some(&t) => Some(t), - None if let Some(e) = self.tainted_by_errors() => Some(Ty::new_error(self.tcx,e)), + None if let Some(e) = self.tainted_by_errors() => Some(Ty::new_error(self.tcx, e)), None => None, } } @@ -564,7 +564,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !errors.is_empty() { self.adjust_fulfillment_errors_for_expr_obligation(&mut errors); + let errors_causecode = errors + .iter() + .map(|e| (e.obligation.cause.span, e.root_obligation.cause.code().clone())) + .collect::<Vec<_>>(); self.err_ctxt().report_fulfillment_errors(errors); + self.collect_unused_stmts_for_coerce_return_ty(errors_causecode); } } @@ -713,7 +718,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let ty::GenericArgKind::Type(ty) = ty.unpack() && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind() && let Some(def_id) = def_id.as_local() - && self.opaque_type_origin(def_id).is_some() { + && self.opaque_type_origin(def_id).is_some() + { return None; } } @@ -833,7 +839,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .resolve_fully_qualified_call(span, item_name, ty.normalized, qself.span, hir_id) .and_then(|r| { // lint bare trait if the method is found in the trait - if span.edition().at_least_rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) { + if span.edition().at_least_rust_2021() + && let Some(mut diag) = self + .tcx + .sess + .diagnostic() + .steal_diagnostic(qself.span, StashKey::TraitMissingMethod) + { diag.emit(); } Ok(r) @@ -863,7 +875,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // emit or cancel the diagnostic for bare traits - if span.edition().at_least_rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) { + if span.edition().at_least_rust_2021() + && let Some(mut diag) = self + .tcx + .sess + .diagnostic() + .steal_diagnostic(qself.span, StashKey::TraitMissingMethod) + { if trait_missing_method { // cancel the diag for bare traits when meeting `MyTrait::missing_method` diag.cancel(); @@ -949,12 +967,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind: hir::ItemKind::Fn(ref sig, ..), owner_id, .. - })) = self.tcx.hir().find_parent(hir_id) => Some(( - hir::HirId::make_owner(owner_id.def_id), - &sig.decl, - ident, - ident.name != sym::main, - )), + })) = self.tcx.hir().find_parent(hir_id) => + { + Some(( + hir::HirId::make_owner(owner_id.def_id), + &sig.decl, + ident, + ident.name != sym::main, + )) + } _ => None, } } @@ -1077,11 +1098,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut user_self_ty = None; let mut is_alias_variant_ctor = false; match res { - Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) - if let Some(self_ty) = self_ty => - { + Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) if let Some(self_ty) = self_ty => { let adt_def = self_ty.normalized.ty_adt_def().unwrap(); - user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did(), self_ty: self_ty.raw }); + user_self_ty = + Some(UserSelfTy { impl_def_id: adt_def.did(), self_ty: self_ty.raw }); is_alias_variant_ctor = true; } Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => { @@ -1090,9 +1110,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let container_id = assoc_item.container_id(tcx); debug!(?def_id, ?container, ?container_id); match container { - ty::TraitContainer => { - callee::check_legal_trait_for_method_call(tcx, span, None, span, container_id) - } + ty::TraitContainer => callee::check_legal_trait_for_method_call( + tcx, + span, + None, + span, + container_id, + ), ty::ImplContainer => { if segments.len() == 1 { // `<T>::assoc` will end up here, and so @@ -1478,12 +1502,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(normalized_ty) => normalized_ty, Err(errors) => { let guar = self.err_ctxt().report_fulfillment_errors(errors); - return Ty::new_error(self.tcx,guar); + return Ty::new_error(self.tcx, guar); } } } else { ty - } + } } /// Resolves `ty` by a single level if `ty` is a type variable. diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index 43d4496dd48..522d0e2616b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -129,21 +129,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } - for param in - [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] + for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] .into_iter() .flatten() { if self.blame_specific_arg_if_possible( - error, - def_id, - param, - *call_hir_id, - callee.span, - None, - args, - ) - { + error, + def_id, + param, + *call_hir_id, + callee.span, + None, + args, + ) { return true; } } @@ -346,8 +344,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let TypeVariableOriginKind::TypeParameterDefinition(_, def_id) = origin.kind && let generics = self.0.tcx.generics_of(self.1) && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id) - && let Some(subst) = ty::GenericArgs::identity_for_item(self.0.tcx, self.1) - .get(index as usize) + && let Some(subst) = + ty::GenericArgs::identity_for_item(self.0.tcx, self.1).get(index as usize) { ControlFlow::Break(*subst) } else { @@ -364,11 +362,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, ) -> bool { if let traits::FulfillmentErrorCode::CodeSelectionError( - traits::SelectionError::OutputTypeParameterMismatch(box traits::SelectionOutputTypeParameterMismatch{ - expected_trait_ref, .. - }), + traits::SelectionError::OutputTypeParameterMismatch( + box traits::SelectionOutputTypeParameterMismatch { expected_trait_ref, .. }, + ), ) = error.code - && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected_trait_ref.skip_binder().self_ty().kind() + && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = + expected_trait_ref.skip_binder().self_ty().kind() && span.overlaps(self.tcx.def_span(*def_id)) { true @@ -446,10 +445,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .collect(); // If there's one field that references the given generic, great! if let [(idx, _)] = args_referencing_param.as_slice() - && let Some(arg) = receiver - .map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) { - - error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span); + && let Some(arg) = receiver.map_or(args.get(*idx), |rcvr| { + if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) } + }) + { + error.obligation.cause.span = arg + .span + .find_ancestor_in_same_ctxt(error.obligation.cause.span) + .unwrap_or(arg.span); if let hir::Node::Expr(arg_expr) = self.tcx.hir().get(arg.hir_id) { // This is more specific than pointing at the entire argument. @@ -934,16 +937,16 @@ fn find_param_in_ty<'tcx>( return true; } if let ty::GenericArgKind::Type(ty) = arg.unpack() - && let ty::Alias(ty::Projection | ty::Inherent, ..) = ty.kind() - { - // This logic may seem a bit strange, but typically when - // we have a projection type in a function signature, the - // argument that's being passed into that signature is - // not actually constraining that projection's args in - // a meaningful way. So we skip it, and see improvements - // in some UI tests. - walk.skip_current_subtree(); - } + && let ty::Alias(ty::Projection | ty::Inherent, ..) = ty.kind() + { + // This logic may seem a bit strange, but typically when + // we have a projection type in a function signature, the + // argument that's being passed into that signature is + // not actually constraining that projection's args in + // a meaningful way. So we skip it, and see improvements + // in some UI tests. + walk.skip_current_subtree(); + } } false } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index c0332a48be3..9f1800b45c3 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -11,11 +11,12 @@ use crate::{ use rustc_ast as ast; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{ - pluralize, Applicability, Diagnostic, DiagnosticId, ErrorGuaranteed, MultiSpan, + pluralize, Applicability, Diagnostic, DiagnosticId, ErrorGuaranteed, MultiSpan, StashKey, }; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::intravisit::Visitor; use rustc_hir::{ExprKind, Node, QPath}; use rustc_hir_analysis::astconv::AstConv; use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt; @@ -26,9 +27,10 @@ use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::TypeTrace; use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; +use rustc_middle::traits::ObligationCauseCode::ExprBindingObligation; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::visit::TypeVisitableExt; -use rustc_middle::ty::{self, IsSuggestable, Ty}; +use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt}; use rustc_session::Session; use rustc_span::symbol::{kw, Ident}; use rustc_span::{self, sym, BytePos, Span}; @@ -651,7 +653,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len() { // Wrap up the N provided arguments starting at this position in a tuple. - let provided_as_tuple = Ty::new_tup_from_iter(tcx, + let provided_as_tuple = Ty::new_tup_from_iter( + tcx, provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx).take(tys.len()), ); @@ -722,6 +725,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &mut err, fn_def_id, callee_ty, + call_expr, + None, Some(mismatch_idx), is_method, ); @@ -826,6 +831,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &mut err, fn_def_id, callee_ty, + call_expr, + Some(expected_ty), Some(expected_idx.as_usize()), is_method, ); @@ -879,8 +886,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && self.tcx.def_kind(fn_def_id).is_fn_like() && let self_implicit = matches!(call_expr.kind, hir::ExprKind::MethodCall(..)) as usize - && let Some(arg) = self.tcx.fn_arg_names(fn_def_id) - .get(expected_idx.as_usize() + self_implicit) + && let Some(arg) = + self.tcx.fn_arg_names(fn_def_id).get(expected_idx.as_usize() + self_implicit) && arg.name != kw::SelfLower { format!("/* {} */", arg.name) @@ -941,9 +948,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && error_span.can_be_used_for_suggestions() { if arg_idx.index() > 0 - && let Some((_, prev)) = provided_arg_tys - .get(ProvidedIdx::from_usize(arg_idx.index() - 1) - ) { + && let Some((_, prev)) = + provided_arg_tys.get(ProvidedIdx::from_usize(arg_idx.index() - 1)) + { // Include previous comma span = prev.shrink_to_hi().to(span); } @@ -1208,7 +1215,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Call out where the function is defined - self.label_fn_like(&mut err, fn_def_id, callee_ty, None, is_method); + self.label_fn_like(&mut err, fn_def_id, callee_ty, call_expr, None, None, is_method); // And add a suggestion block for all of the parameters let suggestion_text = match suggestion_text { @@ -1286,7 +1293,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err: &mut rustc_errors::DiagnosticBuilder<'tcx, ErrorGuaranteed>, ) { if let ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Mut, .. }) = expected_ty.kind() - && let ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Not, .. }) = provided_ty.kind() + && let ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Not, .. }) = + provided_ty.kind() && let hir::ExprKind::Call(callee, _) = arg.kind && let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = callee.kind && let Res::Def(_, def_id) = path.res @@ -1294,9 +1302,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { // The user provided `ptr::null()`, but the function expects // `ptr::null_mut()`. - err.subdiagnostic(SuggestPtrNullMut { - span: arg.span - }); + err.subdiagnostic(SuggestPtrNullMut { span: arg.span }); } } @@ -1370,7 +1376,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } _ => bug!("unexpected type: {:?}", ty.normalized), }, - Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) + Res::Def( + DefKind::Struct | DefKind::Union | DefKind::TyAlias { .. } | DefKind::AssocTy, + _, + ) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => match ty.normalized.ty_adt_def() { Some(adt) if !adt.is_enum() => { @@ -1840,6 +1849,55 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + pub(super) fn collect_unused_stmts_for_coerce_return_ty( + &self, + errors_causecode: Vec<(Span, ObligationCauseCode<'tcx>)>, + ) { + for (span, code) in errors_causecode { + let Some(mut diag) = + self.tcx.sess.diagnostic().steal_diagnostic(span, StashKey::MaybeForgetReturn) + else { + continue; + }; + + if let Some(fn_sig) = self.body_fn_sig() + && let ExprBindingObligation(_, _, hir_id, ..) = code + && !fn_sig.output().is_unit() + { + let mut block_num = 0; + let mut found_semi = false; + for (_, node) in self.tcx.hir().parent_iter(hir_id) { + match node { + hir::Node::Stmt(stmt) => if let hir::StmtKind::Semi(ref expr) = stmt.kind { + let expr_ty = self.typeck_results.borrow().expr_ty(expr); + let return_ty = fn_sig.output(); + if !matches!(expr.kind, hir::ExprKind::Ret(..)) && + self.can_coerce(expr_ty, return_ty) { + found_semi = true; + } + }, + hir::Node::Block(_block) => if found_semi { + block_num += 1; + } + hir::Node::Item(item) => if let hir::ItemKind::Fn(..) = item.kind { + break; + } + _ => {} + } + } + if block_num > 1 && found_semi { + diag.span_suggestion_verbose( + span.shrink_to_lo(), + "you might have meant to return this to infer its type parameters", + "return ", + Applicability::MaybeIncorrect, + ); + } + } + diag.emit(); + } + } + /// Given a vector of fulfillment errors, try to adjust the spans of the /// errors to more accurately point at the cause of the failure. /// @@ -1899,6 +1957,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err: &mut Diagnostic, callable_def_id: Option<DefId>, callee_ty: Option<Ty<'tcx>>, + call_expr: &'tcx hir::Expr<'tcx>, + expected_ty: Option<Ty<'tcx>>, // A specific argument should be labeled, instead of all of them expected_idx: Option<usize>, is_method: bool, @@ -1921,8 +1981,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let callee_ty = callee_ty.peel_refs(); match *callee_ty.kind() { ty::Param(param) => { - let param = - self.tcx.generics_of(self.body_id).type_param(¶m, self.tcx); + let param = self.tcx.generics_of(self.body_id).type_param(¶m, self.tcx); if param.kind.is_synthetic() { // if it's `impl Fn() -> ..` then just fall down to the def-id based logic def_id = param.def_id; @@ -1936,8 +1995,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME(compiler-errors): This could be problematic if something has two // fn-like predicates with different args, but callable types really never // do that, so it's OK. - for (predicate, span) in instantiated - { + for (predicate, span) in instantiated { if let ty::ClauseKind::Trait(pred) = predicate.kind().skip_binder() && pred.self_ty().peel_refs() == callee_ty && self.tcx.is_fn_trait(pred.def_id()) @@ -1956,7 +2014,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => { // Look for a user-provided impl of a `Fn` trait, and point to it. let new_def_id = self.probe(|_| { - let trait_ref = ty::TraitRef::new(self.tcx, + let trait_ref = ty::TraitRef::new( + self.tcx, call_kind.to_def_id(self.tcx), [ callee_ty, @@ -1988,7 +2047,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - if let Some(def_span) = self.tcx.def_ident_span(def_id) && !def_span.is_dummy() { + if let Some(def_span) = self.tcx.def_ident_span(def_id) + && !def_span.is_dummy() + { let mut spans: MultiSpan = def_span.into(); let params = self @@ -2015,6 +2076,48 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let param = expected_idx .and_then(|expected_idx| self.tcx.hir().body(*body).params.get(expected_idx)); let (kind, span) = if let Some(param) = param { + // Try to find earlier invocations of this closure to find if the type mismatch + // is because of inference. If we find one, point at them. + let mut call_finder = FindClosureArg { tcx: self.tcx, calls: vec![] }; + let node = self + .tcx + .opt_local_def_id_to_hir_id(self.tcx.hir().get_parent_item(call_expr.hir_id)) + .and_then(|hir_id| self.tcx.hir().find(hir_id)); + match node { + Some(hir::Node::Item(item)) => call_finder.visit_item(item), + Some(hir::Node::TraitItem(item)) => call_finder.visit_trait_item(item), + Some(hir::Node::ImplItem(item)) => call_finder.visit_impl_item(item), + _ => {} + } + let typeck = self.typeck_results.borrow(); + for (rcvr, args) in call_finder.calls { + if rcvr.hir_id.owner == typeck.hir_owner + && let Some(rcvr_ty) = typeck.node_type_opt(rcvr.hir_id) + && let ty::Closure(call_def_id, _) = rcvr_ty.kind() + && def_id == *call_def_id + && let Some(idx) = expected_idx + && let Some(arg) = args.get(idx) + && let Some(arg_ty) = typeck.node_type_opt(arg.hir_id) + && let Some(expected_ty) = expected_ty + && self.can_eq(self.param_env, arg_ty, expected_ty) + { + let mut sp: MultiSpan = vec![arg.span].into(); + sp.push_span_label( + arg.span, + format!("expected because this argument is of type `{arg_ty}`"), + ); + sp.push_span_label(rcvr.span, "in this closure call"); + err.span_note( + sp, + format!( + "expected because the closure was earlier called with an \ + argument of type `{arg_ty}`", + ), + ); + break; + } + } + ("closure parameter", param.span) } else { ("closure", self.tcx.def_span(def_id)) @@ -2028,3 +2131,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } + +struct FindClosureArg<'tcx> { + tcx: TyCtxt<'tcx>, + calls: Vec<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>, +} + +impl<'tcx> Visitor<'tcx> for FindClosureArg<'tcx> { + type NestedFilter = rustc_middle::hir::nested_filter::All; + + fn nested_visit_map(&mut self) -> Self::Map { + self.tcx.hir() + } + + fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { + if let hir::ExprKind::Call(rcvr, args) = ex.kind { + self.calls.push((rcvr, args)); + } + hir::intravisit::walk_expr(self, ex); + } +} diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 4a245d30c8e..7677d6f953b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -221,14 +221,14 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { let item_def_id = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id.to_def_id()]; + // HACK(eddyb) should get the original `Span`. + let span = tcx.def_span(def_id); ty::GenericPredicates { parent: None, predicates: tcx.arena.alloc_from_iter( self.param_env.caller_bounds().iter().filter_map(|predicate| { match predicate.kind().skip_binder() { ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => { - // HACK(eddyb) should get the original `Span`. - let span = tcx.def_span(def_id); Some((predicate, span)) } _ => None, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 9999fa2e59c..14d69141343 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -254,22 +254,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &hir::Expr<'tcx>, expected: Ty<'tcx>, ) -> bool { - if let hir::ExprKind::MethodCall(hir::PathSegment { ident: method, .. }, recv_expr, &[], _) = expr.kind && - let Some(recv_ty) = self.typeck_results.borrow().expr_ty_opt(recv_expr) && - self.can_coerce(recv_ty, expected) { - let span = if let Some(recv_span) = recv_expr.span.find_ancestor_inside(expr.span) { - expr.span.with_lo(recv_span.hi()) - } else { - expr.span.with_lo(method.span.lo() - rustc_span::BytePos(1)) - }; - err.span_suggestion_verbose( - span, - "try removing the method call", - "", - Applicability::MachineApplicable, - ); - return true; - } + if let hir::ExprKind::MethodCall(hir::PathSegment { ident: method, .. }, recv_expr, &[], _) = + expr.kind + && let Some(recv_ty) = self.typeck_results.borrow().expr_ty_opt(recv_expr) + && self.can_coerce(recv_ty, expected) + { + let span = if let Some(recv_span) = recv_expr.span.find_ancestor_inside(expr.span) { + expr.span.with_lo(recv_span.hi()) + } else { + expr.span.with_lo(method.span.lo() - rustc_span::BytePos(1)) + }; + err.span_suggestion_verbose( + span, + "try removing the method call", + "", + Applicability::MachineApplicable, + ); + return true; + } false } @@ -347,10 +349,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let name = self.tcx.item_name(def_id); let kind = self.tcx.def_kind(def_id); if let DefKind::Ctor(of, CtorKind::Fn) = kind { - err.span_label(sp, format!("`{name}` defines {} constructor here, which should be called", match of { - CtorOf::Struct => "a struct", - CtorOf::Variant => "an enum variant", - })); + err.span_label( + sp, + format!( + "`{name}` defines {} constructor here, which should be called", + match of { + CtorOf::Struct => "a struct", + CtorOf::Variant => "an enum variant", + } + ), + ); } else { let descr = self.tcx.def_kind_descr(kind, def_id); err.span_label(sp, format!("{descr} `{name}` defined here")); @@ -370,25 +378,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(method_ident) = receiver_method_ident && method_ident.name == conversion_method.name { - return None // do not suggest code that is already there (#53348) + return None; // do not suggest code that is already there (#53348) } let method_call_list = [sym::to_vec, sym::to_string]; let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind && receiver_method.ident.name == sym::clone && method_call_list.contains(&conversion_method.name) - // If receiver is `.clone()` and found type has one of those methods, - // we guess that the user wants to convert from a slice type (`&[]` or `&str`) - // to an owned type (`Vec` or `String`). These conversions clone internally, - // so we remove the user's `clone` call. - { - vec![( - receiver_method.ident.span, - conversion_method.name.to_string() - )] - } else if expr.precedence().order() - < ExprPrecedence::MethodCall.order() + // If receiver is `.clone()` and found type has one of those methods, + // we guess that the user wants to convert from a slice type (`&[]` or `&str`) + // to an owned type (`Vec` or `String`). These conversions clone internally, + // so we remove the user's `clone` call. { + vec![(receiver_method.ident.span, conversion_method.name.to_string())] + } else if expr.precedence().order() < ExprPrecedence::MethodCall.order() { vec![ (expr.span.shrink_to_lo(), "(".to_string()), (expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)), @@ -431,7 +434,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Given `Result<_, E>`, check our expected ty is `Result<_, &E>` for // `as_ref` and `as_deref` compatibility. let error_tys_equate_as_ref = error_tys.map_or(true, |(found, expected)| { - self.can_eq(self.param_env, Ty::new_imm_ref(self.tcx,self.tcx.lifetimes.re_erased, found), expected) + self.can_eq( + self.param_env, + Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, found), + expected, + ) }); // 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. @@ -604,8 +611,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } let box_found = Ty::new_box(self.tcx, found); - let pin_box_found = Ty::new_lang_item(self.tcx, box_found, LangItem::Pin).unwrap(); - let pin_found = Ty::new_lang_item(self.tcx, found, LangItem::Pin).unwrap(); + let Some(pin_box_found) = Ty::new_lang_item(self.tcx, box_found, LangItem::Pin) else { + return false; + }; + let Some(pin_found) = Ty::new_lang_item(self.tcx, found, LangItem::Pin) else { + return false; + }; match expected.kind() { ty::Adt(def, _) if Some(def.did()) == pin_did => { if self.can_coerce(pin_box_found, expected) { @@ -766,41 +777,54 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => { if let Some(found) = found.make_suggestable(self.tcx, false) { - err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: found.to_string() }); + err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { + span, + found: found.to_string(), + }); return true; } else if let ty::Closure(_, args) = found.kind() // FIXME(compiler-errors): Get better at printing binders... && let closure = args.as_closure() && closure.sig().is_suggestable(self.tcx, false) { - err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: closure.print_as_impl_trait().to_string() }); + err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { + span, + found: closure.print_as_impl_trait().to_string(), + }); return true; } else { // FIXME: if `found` could be `impl Iterator` we should suggest that. err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere { span }); - return true + return true; } } hir::FnRetTy::Return(hir_ty) => { if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind && let hir::Node::Item(hir::Item { - kind: hir::ItemKind::OpaqueTy(op_ty), - .. + kind: hir::ItemKind::OpaqueTy(op_ty), .. }) = self.tcx.hir().get(item_id.hir_id()) - && let [hir::GenericBound::LangItemTrait( - hir::LangItem::Future, _, _, generic_args)] = op_ty.bounds + && let [ + hir::GenericBound::LangItemTrait(hir::LangItem::Future, _, _, generic_args), + ] = op_ty.bounds && let hir::GenericArgs { bindings: [ty_binding], .. } = generic_args - && let hir::TypeBindingKind::Equality { term: hir::Term::Ty(term) } = ty_binding.kind + && let hir::TypeBindingKind::Equality { term: hir::Term::Ty(term) } = + ty_binding.kind { // Check if async function's return type was omitted. // Don't emit suggestions if the found type is `impl Future<...>`. debug!(?found); if found.is_suggestable(self.tcx, false) { if term.span.is_empty() { - err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span: term.span, found: found.to_string() }); + err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { + span: term.span, + found: found.to_string(), + }); return true; } else { - err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { span: term.span, expected }); + err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { + span: term.span, + expected, + }); } } } else { @@ -815,7 +839,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.normalize(hir_ty.span, ty); let ty = self.tcx.erase_late_bound_regions(ty); if self.can_coerce(expected, ty) { - err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { span: hir_ty.span, expected }); + err.subdiagnostic(errors::ExpectedReturnTypeLabel::Other { + span: hir_ty.span, + expected, + }); self.try_suggest_return_impl_trait(err, expected, ty, fn_id); return true; } @@ -1073,13 +1100,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .type_implements_trait( clone_trait_def, [self.tcx.erase_regions(expected_ty)], - self.param_env + self.param_env, ) .must_apply_modulo_regions() - { + { let suggestion = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) { Some(ident) => format!(": {ident}.clone()"), - None => ".clone()".to_string() + None => ".clone()".to_string(), }; diag.span_suggestion_verbose( @@ -1089,7 +1116,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); return true; - } + } false } @@ -1117,31 +1144,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expr_inner_ty = args.type_at(0); let expected_inner_ty = expected_args.type_at(0); if let &ty::Ref(_, ty, _mutability) = expr_inner_ty.kind() - && self.can_eq(self.param_env, ty, expected_inner_ty) + && self.can_eq(self.param_env, ty, expected_inner_ty) + { + let def_path = self.tcx.def_path_str(adt_def.did()); + let span = expr.span.shrink_to_hi(); + let subdiag = if self.type_is_copy_modulo_regions(self.param_env, ty) { + errors::OptionResultRefMismatch::Copied { span, def_path } + } else if let Some(clone_did) = self.tcx.lang_items().clone_trait() + && rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions( + self, + self.param_env, + ty, + clone_did, + ) { - let def_path = self.tcx.def_path_str(adt_def.did()); - let span = expr.span.shrink_to_hi(); - let subdiag = if self.type_is_copy_modulo_regions(self.param_env, ty) { - errors::OptionResultRefMismatch::Copied { - span, def_path - } - } else if let Some(clone_did) = self.tcx.lang_items().clone_trait() - && rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions( - self, - self.param_env, - ty, - clone_did, - ) - { - errors::OptionResultRefMismatch::Cloned { - span, def_path - } - } else { - return false; - }; - diag.subdiagnostic(subdiag); - return true; - } + errors::OptionResultRefMismatch::Cloned { span, def_path } + } else { + return false; + }; + diag.subdiagnostic(subdiag); + return true; + } } false @@ -1177,14 +1200,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx, self.misc(expr.span), self.param_env, - ty::TraitRef::new(self.tcx, - into_def_id, - [expr_ty, expected_ty] - ), + ty::TraitRef::new(self.tcx, into_def_id, [expr_ty, expected_ty]), )) { let mut span = expr.span; - while expr.span.eq_ctxt(span) && let Some(parent_callsite) = span.parent_callsite() + while expr.span.eq_ctxt(span) + && let Some(parent_callsite) = span.parent_callsite() { span = parent_callsite; } @@ -1192,7 +1213,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let sugg = if expr.precedence().order() >= PREC_POSTFIX { vec![(span.shrink_to_hi(), ".into()".to_owned())] } else { - vec![(span.shrink_to_lo(), "(".to_owned()), (span.shrink_to_hi(), ").into()".to_owned())] + vec![ + (span.shrink_to_lo(), "(".to_owned()), + (span.shrink_to_hi(), ").into()".to_owned()), + ] }; diag.multipart_suggestion( format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"), @@ -1234,9 +1258,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // since the user probably just misunderstood how `let else` // and `&&` work together. if let Some((_, hir::Node::Local(local))) = cond_parent - && let hir::PatKind::Path(qpath) | hir::PatKind::TupleStruct(qpath, _, _) = &local.pat.kind + && let hir::PatKind::Path(qpath) | hir::PatKind::TupleStruct(qpath, _, _) = + &local.pat.kind && let hir::QPath::Resolved(None, path) = qpath - && let Some(did) = path.res.opt_def_id() + && let Some(did) = path + .res + .opt_def_id() .and_then(|did| self.tcx.opt_parent(did)) .and_then(|did| self.tcx.opt_parent(did)) && self.tcx.is_diagnostic_item(sym::Option, did) @@ -1603,7 +1630,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .. }) => { let Some(hir::Node::Local(hir::Local { init: Some(init), .. })) = - self.tcx.hir().find(self.tcx.hir().parent_id(*pat_hir_id)) else { + self.tcx.hir().find(self.tcx.hir().parent_id(*pat_hir_id)) + else { return expr; }; @@ -1630,12 +1658,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // to worry if it's a call to a typed function or closure as this would ne handled // previously. hir::ExprKind::Call(Expr { kind: call_expr_kind, .. }, _) => { - if let hir::ExprKind::Path(hir::QPath::Resolved(None, call_expr_path)) = call_expr_kind - && let hir::Path { segments: [_], res: crate::Res::Local(binding), .. } = call_expr_path - && let Some(hir::Node::Pat(hir::Pat { hir_id, .. })) = self.tcx.hir().find(*binding) + if let hir::ExprKind::Path(hir::QPath::Resolved(None, call_expr_path)) = + call_expr_kind + && let hir::Path { segments: [_], res: crate::Res::Local(binding), .. } = + call_expr_path + && let Some(hir::Node::Pat(hir::Pat { hir_id, .. })) = + self.tcx.hir().find(*binding) && let Some(closure) = self.tcx.hir().find(self.tcx.hir().parent_id(*hir_id)) && let hir::Node::Local(hir::Local { init: Some(init), .. }) = closure - && let Expr { kind: hir::ExprKind::Closure(hir::Closure { body: body_id, .. }), ..} = init + && let Expr { + kind: hir::ExprKind::Closure(hir::Closure { body: body_id, .. }), + .. + } = init { let hir::Body { value: body_expr, .. } = self.tcx.hir().body(*body_id); self.note_type_is_not_clone_inner_expr(body_expr) diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs index 7064484a40f..bee79242fd1 100644 --- a/compiler/rustc_hir_typeck/src/inherited.rs +++ b/compiler/rustc_hir_typeck/src/inherited.rs @@ -129,25 +129,29 @@ impl<'tcx> Inherited<'tcx> { let infer_var_info = &mut self.infer_var_info.borrow_mut(); // (*) binder skipped - if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(tpred)) = obligation.predicate.kind().skip_binder() - && let Some(ty) = self.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| self.root_var(t)) + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(tpred)) = + obligation.predicate.kind().skip_binder() + && let Some(ty) = + self.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| self.root_var(t)) && self.tcx.lang_items().sized_trait().is_some_and(|st| st != tpred.trait_ref.def_id) { let new_self_ty = self.tcx.types.unit; // Then construct a new obligation with Self = () added // to the ParamEnv, and see if it holds. - let o = obligation.with(self.tcx, - obligation - .predicate - .kind() - .rebind( - // (*) binder moved here - ty::PredicateKind::Clause(ty::ClauseKind::Trait(tpred.with_self_ty(self.tcx, new_self_ty))) - ), + let o = obligation.with( + self.tcx, + obligation.predicate.kind().rebind( + // (*) binder moved here + ty::PredicateKind::Clause(ty::ClauseKind::Trait( + tpred.with_self_ty(self.tcx, new_self_ty), + )), + ), ); // Don't report overflow errors. Otherwise equivalent to may_hold. - if let Ok(result) = self.probe(|_| self.evaluate_obligation(&o)) && result.may_apply() { + if let Ok(result) = self.probe(|_| self.evaluate_obligation(&o)) + && result.may_apply() + { infer_var_info.entry(ty).or_default().self_in_trait = true; } } diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 4e65182f158..5d516eaf507 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -70,7 +70,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Special-case transmuting from `typeof(function)` and // `Option<typeof(function)>` to present a clearer error. let from = unpack_option_like(tcx, from); - if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer(dl.instruction_address_space).size(&tcx) { + if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) + && size_to == Pointer(dl.instruction_address_space).size(&tcx) + { struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type") .note(format!("source type: {from}")) .note(format!("target type: {to}")) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 7164102a30e..74f469cb39c 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -667,8 +667,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // will still match the original object type, but it won't pollute our // type variables in any form, so just do that! let (QueryResponse { value: generalized_self_ty, .. }, _ignored_var_values) = - self.fcx - .instantiate_canonical_with_fresh_inference_vars(self.span, self_ty); + self.fcx.instantiate_canonical_with_fresh_inference_vars(self.span, self_ty); self.assemble_inherent_candidates_from_object(generalized_self_ty); self.assemble_inherent_impl_candidates_for_type(p.def_id()); @@ -1690,15 +1689,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } - debug!( - "comparing return_ty {:?} with xform ret ty {:?}", - return_ty, xform_ret_ty - ); + debug!("comparing return_ty {:?} with xform ret ty {:?}", return_ty, xform_ret_ty); if let ProbeResult::Match = result && self - .at(&ObligationCause::dummy(), self.param_env) - .sup(DefineOpaqueTypes::No, return_ty, xform_ret_ty) - .is_err() + .at(&ObligationCause::dummy(), self.param_env) + .sup(DefineOpaqueTypes::No, return_ty, xform_ret_ty) + .is_err() { result = ProbeResult::BadReturnType; } @@ -1959,15 +1955,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { if let Some(nested) = v.meta_item_list() { // #[doc(alias("foo", "bar"))] for n in nested { - if let Some(lit) = n.lit() && name.as_str() == lit.symbol.as_str() { + if let Some(lit) = n.lit() + && name.as_str() == lit.symbol.as_str() + { return true; } } } else if let Some(meta) = v.meta_item() && let Some(lit) = meta.name_value_literal() - && name.as_str() == lit.symbol.as_str() { - // #[doc(alias = "foo")] - return true; + && name.as_str() == lit.symbol.as_str() + { + // #[doc(alias = "foo")] + return true; } } } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index a4bbb16026a..6b0dc73d49c 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -305,8 +305,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mode = no_match_data.mode; let tcx = self.tcx; let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty); - let ((mut ty_str, ty_file), short_ty_str) = if trait_missing_method - && let ty::Dynamic(predicates, _, _) = rcvr_ty.kind() { + let ((mut ty_str, ty_file), short_ty_str) = + if trait_missing_method && let ty::Dynamic(predicates, _, _) = rcvr_ty.kind() { ((predicates.to_string(), None), with_forced_trimmed_paths!(predicates.to_string())) } else { (tcx.short_ty_string(rcvr_ty), with_forced_trimmed_paths!(rcvr_ty.to_string())) @@ -377,9 +377,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.is_diagnostic_item(sym::write_macro, def_id) || tcx.is_diagnostic_item(sym::writeln_macro, def_id) }) && item_name.name == Symbol::intern("write_fmt"); - let mut err = if is_write - && let Some(args) = args - { + let mut err = if is_write && let Some(args) = args { self.suggest_missing_writer(rcvr_ty, args) } else { tcx.sess.create_err(NoAssociatedItem { @@ -421,9 +419,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source { + if let Mode::MethodCall = mode + && let SelfSource::MethodCall(cal) = source + { self.suggest_await_before_method( - &mut err, item_name, rcvr_ty, cal, span, expected.only_has_type(self), + &mut err, + item_name, + rcvr_ty, + cal, + span, + expected.only_has_type(self), ); } if let Some(span) = @@ -669,7 +674,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); let quiet_projection_ty = - tcx.mk_alias_ty(projection_ty.def_id, args_with_infer_self); + ty::AliasTy::new(tcx, projection_ty.def_id, args_with_infer_self); let term = pred.skip_binder().term; @@ -863,7 +868,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .filter_map(|(pred, parent_pred, _cause)| { let mut suggested = false; format_pred(*pred).map(|(p, self_ty)| { - if let Some(parent) = parent_pred && suggested_bounds.contains(parent) { + if let Some(parent) = parent_pred + && suggested_bounds.contains(parent) + { // We don't suggest `PartialEq` when we already suggest `Eq`. } else if !suggested_bounds.contains(pred) { if collect_type_param_suggestions(self_ty, *pred, &p) { @@ -967,7 +974,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { unsatisfied_bounds = true; } - } else if let ty::Adt(def, targs) = rcvr_ty.kind() && let Some(args) = args { + } else if let ty::Adt(def, targs) = rcvr_ty.kind() + && let Some(args) = args + { // This is useful for methods on arbitrary self types that might have a simple // mutability difference, like calling a method on `Pin<&mut Self>` that is on // `Pin<&Self>`. @@ -975,16 +984,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut item_segment = hir::PathSegment::invalid(); item_segment.ident = item_name; for t in [Ty::new_mut_ref, Ty::new_imm_ref, |_, _, t| t] { - let new_args = tcx.mk_args_from_iter( - targs - .iter() - .map(|arg| match arg.as_type() { - Some(ty) => ty::GenericArg::from( - t(tcx, tcx.lifetimes.re_erased, ty.peel_refs()), - ), - _ => arg, - }) - ); + let new_args = + tcx.mk_args_from_iter(targs.iter().map(|arg| match arg.as_type() { + Some(ty) => ty::GenericArg::from(t( + tcx, + tcx.lifetimes.re_erased, + ty.peel_refs(), + )), + _ => arg, + })); let rcvr_ty = Ty::new_adt(tcx, *def, new_args); if let Ok(method) = self.lookup_method_for_diagnostic( rcvr_ty, @@ -1088,7 +1096,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for inherent_method in self.tcx.associated_items(inherent_impl_did).in_definition_order() { - if let Some(attr) = self.tcx.get_attr(inherent_method.def_id, sym::rustc_confusables) + if let Some(attr) = self + .tcx + .get_attr(inherent_method.def_id, sym::rustc_confusables) && let Some(candidates) = parse_confusables(attr) && candidates.contains(&item_name.name) { @@ -1250,6 +1260,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Dynamic limit to avoid hiding just one candidate, which is silly. let limit = if sources.len() == 5 { 5 } else { 4 }; + let mut suggs = vec![]; for (idx, source) in sources.iter().take(limit).enumerate() { match *source { CandidateSource::Impl(impl_did) => { @@ -1307,11 +1318,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.note(note_str); } if let Some(sugg_span) = sugg_span - && let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) { + && let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) + { let path = self.tcx.def_path_str(trait_ref.skip_binder().def_id); let ty = match item.kind { - ty::AssocKind::Const | ty::AssocKind::Type => rcvr_ty, + ty::AssocKind::Const | ty::AssocKind::Type => impl_ty, ty::AssocKind::Fn => self .tcx .fn_sig(item.def_id) @@ -1323,19 +1335,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .copied() .unwrap_or(rcvr_ty), }; - print_disambiguation_help( + if let Some(sugg) = print_disambiguation_help( item_name, args, err, path, ty, + Some(impl_ty), item.kind, self.tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id), sugg_span, idx, self.tcx.sess.source_map(), item.fn_has_self_parameter, - ); + ) { + suggs.push(sugg); + } } } CandidateSource::Trait(trait_did) => { @@ -1359,23 +1374,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let Some(sugg_span) = sugg_span { let path = self.tcx.def_path_str(trait_did); - print_disambiguation_help( + if let Some(sugg) = print_disambiguation_help( item_name, args, err, path, rcvr_ty, + None, item.kind, self.tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id), sugg_span, idx, self.tcx.sess.source_map(), item.fn_has_self_parameter, - ); + ) { + suggs.push(sugg); + } } } } } + if !suggs.is_empty() && let Some(span) = sugg_span { + err.span_suggestions( + span.with_hi(item_name.span.lo()), + "use fully-qualified syntax to disambiguate", + suggs, + Applicability::MachineApplicable, + ); + } if sources.len() > limit { err.note(format!("and {} others", sources.len() - limit)); } @@ -1453,10 +1479,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && assoc.kind == ty::AssocKind::Fn { let sig = self.tcx.fn_sig(assoc.def_id).instantiate_identity(); - sig.inputs().skip_binder().get(0).and_then(|first| if first.peel_refs() == rcvr_ty.peel_refs() { - None - } else { - Some(first.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str())) + sig.inputs().skip_binder().get(0).and_then(|first| { + if first.peel_refs() == rcvr_ty.peel_refs() { + None + } else { + Some(first.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str())) + } }) } else { None @@ -1616,7 +1644,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { continue; } - let range_def_id = self.tcx.require_lang_item(lang_item.unwrap(), None); + let Some(range_def_id) = + lang_item.and_then(|lang_item| self.tcx.lang_items().get(lang_item)) + else { + continue; + }; let range_ty = self.tcx.type_of(range_def_id).instantiate(self.tcx, &[actual.into()]); @@ -1725,8 +1757,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let span = tcx.hir().span(hir_id); let filename = tcx.sess.source_map().span_to_filename(span); - let parent_node = - self.tcx.hir().get_parent(hir_id); + let parent_node = self.tcx.hir().get_parent(hir_id); let msg = format!( "you must specify a type for this binding, like `{concrete_type}`", ); @@ -1740,7 +1771,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .. }), ) => { - let type_span = ty.map(|ty| ty.span.with_lo(span.hi())).unwrap_or(span.shrink_to_hi()); + let type_span = ty + .map(|ty| ty.span.with_lo(span.hi())) + .unwrap_or(span.shrink_to_hi()); err.span_suggestion( // account for `let x: _ = 42;` // ^^^ @@ -1839,9 +1872,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return_type: Option<Ty<'tcx>>, ) { if let SelfSource::MethodCall(expr) = source - && let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id() - && let Some((fields, args)) = - self.get_field_candidates_considering_privacy(span, actual, mod_id) + && let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id() + && let Some((fields, args)) = + self.get_field_candidates_considering_privacy(span, actual, mod_id) { let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id)); @@ -2320,7 +2353,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // <&[_]>::len or <&[u32]>::len doesn't need an extra "<>" between // but for Adt type like Vec::function() // we would suggest <[_]>::function(); - _ if self.tcx.sess.source_map().span_wrapped_by_angle_or_parentheses(ty.span) => format!("{deref_ty}"), + _ if self + .tcx + .sess + .source_map() + .span_wrapped_by_angle_or_parentheses(ty.span) => + { + format!("{deref_ty}") + } _ => format!("<{deref_ty}>"), }; err.span_suggestion_verbose( @@ -2539,11 +2579,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(_) => (), } - let pred = ty::TraitRef::new( - self.tcx, - self.tcx.lang_items().unpin_trait().unwrap(), - [*rcvr_ty], - ); + let Some(unpin_trait) = self.tcx.lang_items().unpin_trait() else { + return; + }; + let pred = ty::TraitRef::new(self.tcx, unpin_trait, [*rcvr_ty]); let unpin = self.predicate_must_hold_considering_regions(&Obligation::new( self.tcx, ObligationCause::misc(rcvr.span, self.body_id), @@ -2573,8 +2612,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Explicitly ignore the `Pin::as_ref()` method as `Pin` does not // implement the `AsRef` trait. let skip = skippable.contains(&did) - || (("Pin::new" == *pre) && ((sym::as_ref == item_name.name) || !unpin)) - || inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() != inputs_len); + || (("Pin::new" == *pre) + && ((sym::as_ref == item_name.name) || !unpin)) + || inputs_len.is_some_and(|inputs_len| { + pick.item.kind == ty::AssocKind::Fn + && self + .tcx + .fn_sig(pick.item.def_id) + .skip_binder() + .skip_binder() + .inputs() + .len() + != inputs_len + }); // Make sure the method is defined for the *actual* receiver: we don't // want to treat `Box<Self>` as a receiver if it only works because of // an autoderef to `&self` @@ -2625,7 +2675,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // receiver has the same number of arguments that appear in the user's code. && inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len) { - let indent = self.tcx.sess + let indent = self + .tcx + .sess .source_map() .indentation_before(rcvr.span) .unwrap_or_else(|| " ".to_string()); @@ -2992,14 +3044,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let parent = self.tcx.hir().parent_id(expr.hir_id); - if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) && - let hir::ExprKind::MethodCall( + if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) + && let hir::ExprKind::MethodCall( hir::PathSegment { ident: method_name, .. }, self_expr, args, .., - ) = call_expr.kind && - let Some(self_ty) = self.typeck_results.borrow().expr_ty_opt(self_expr) { + ) = call_expr.kind + && let Some(self_ty) = self.typeck_results.borrow().expr_ty_opt(self_expr) + { let new_name = Ident { name: Symbol::intern(&format!("{}_else", method_name.as_str())), span: method_name.span, @@ -3013,10 +3066,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); // check the method arguments number - if let Ok(pick) = probe && - let fn_sig = self.tcx.fn_sig(pick.item.def_id) && - let fn_args = fn_sig.skip_binder().skip_binder().inputs() && - fn_args.len() == args.len() + 1 { + if let Ok(pick) = probe + && let fn_sig = self.tcx.fn_sig(pick.item.def_id) + && let fn_args = fn_sig.skip_binder().skip_binder().inputs() + && fn_args.len() == args.len() + 1 + { err.span_suggestion_verbose( method_name.span.shrink_to_hi(), format!("try calling `{}` instead", new_name.name.as_str()), @@ -3107,52 +3161,51 @@ fn print_disambiguation_help<'tcx>( err: &mut Diagnostic, trait_name: String, rcvr_ty: Ty<'_>, + impl_self_ty: Option<Ty<'_>>, kind: ty::AssocKind, def_kind_descr: &'static str, span: Span, candidate: Option<usize>, source_map: &source_map::SourceMap, fn_has_self_parameter: bool, -) { - let mut applicability = Applicability::MachineApplicable; - let (span, sugg) = if let ( - ty::AssocKind::Fn, - Some(MethodCallComponents { receiver, args, .. }), - ) = (kind, args) - { - let args = format!( - "({}{})", - rcvr_ty.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()), - std::iter::once(receiver) - .chain(args.iter()) - .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| { - applicability = Applicability::HasPlaceholders; - "_".to_owned() - })) - .collect::<Vec<_>>() - .join(", "), - ); - let trait_name = if !fn_has_self_parameter { - format!("<{rcvr_ty} as {trait_name}>") +) -> Option<String> { + Some( + if let (ty::AssocKind::Fn, Some(MethodCallComponents { receiver, args, .. })) = (kind, args) + { + let args = format!( + "({}{})", + rcvr_ty.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()), + std::iter::once(receiver) + .chain(args.iter()) + .map(|arg| source_map + .span_to_snippet(arg.span) + .unwrap_or_else(|_| { "_".to_owned() })) + .collect::<Vec<_>>() + .join(", "), + ); + let trait_name = if !fn_has_self_parameter && let Some(impl_self_ty) = impl_self_ty { + format!("<{impl_self_ty} as {trait_name}>") } else { trait_name }; - (span, format!("{trait_name}::{item_name}{args}")) - } else { - (span.with_hi(item_name.span.lo()), format!("<{rcvr_ty} as {trait_name}>::")) - }; - err.span_suggestion_verbose( - span, - format!( - "disambiguate the {} for {}", - def_kind_descr, - if let Some(candidate) = candidate { - format!("candidate #{candidate}") - } else { - "the candidate".to_string() - }, - ), - sugg, - applicability, - ); + err.span_suggestion_verbose( + span, + format!( + "disambiguate the {def_kind_descr} for {}", + if let Some(candidate) = candidate { + format!("candidate #{candidate}") + } else { + "the candidate".to_string() + }, + ), + format!("{trait_name}::{item_name}{args}"), + Applicability::HasPlaceholders, + ); + return None; + } else if let Some(impl_self_ty) = impl_self_ty { + format!("<{impl_self_ty} as {trait_name}>::") + } else { + format!("{trait_name}::") + }, + ) } diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index a283cd1abf5..c46e641b10d 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -430,33 +430,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(lhs_new_mutbl) = lhs_new_mutbl && let Some(rhs_new_mutbl) = rhs_new_mutbl && lhs_new_mutbl.is_not() - && rhs_new_mutbl.is_not() { + && rhs_new_mutbl.is_not() + { err.multipart_suggestion_verbose( "consider reborrowing both sides", vec![ (lhs_expr.span.shrink_to_lo(), "&*".to_string()), - (rhs_expr.span.shrink_to_lo(), "&*".to_string()) + (rhs_expr.span.shrink_to_lo(), "&*".to_string()), ], rustc_errors::Applicability::MachineApplicable, ); } else { - let mut suggest_new_borrow = |new_mutbl: ast::Mutability, sp: Span| { - // Can reborrow (&mut -> &) - if new_mutbl.is_not() { - err.span_suggestion_verbose( - sp.shrink_to_lo(), - "consider reborrowing this side", - "&*", - rustc_errors::Applicability::MachineApplicable, - ); - // Works on &mut but have & - } else { - err.span_help( - sp, - "consider making this expression a mutable borrow", - ); - } - }; + let mut suggest_new_borrow = + |new_mutbl: ast::Mutability, sp: Span| { + // Can reborrow (&mut -> &) + if new_mutbl.is_not() { + err.span_suggestion_verbose( + sp.shrink_to_lo(), + "consider reborrowing this side", + "&*", + rustc_errors::Applicability::MachineApplicable, + ); + // Works on &mut but have & + } else { + err.span_help( + sp, + "consider making this expression a mutable borrow", + ); + } + }; if let Some(lhs_new_mutbl) = lhs_new_mutbl { suggest_new_borrow(lhs_new_mutbl, lhs_expr.span); @@ -493,20 +495,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else if is_assign == IsAssign::No && let Ref(region, lhs_deref_ty, mutbl) = lhs_ty.kind() { - if self.type_is_copy_modulo_regions( - self.param_env, - *lhs_deref_ty, - ) { + if self.type_is_copy_modulo_regions(self.param_env, *lhs_deref_ty) { suggest_deref_binop(&mut err, *lhs_deref_ty); } else { let lhs_inv_mutbl = mutbl.invert(); let lhs_inv_mutbl_ty = Ty::new_ref( self.tcx, *region, - ty::TypeAndMut { - ty: *lhs_deref_ty, - mutbl: lhs_inv_mutbl, - }, + ty::TypeAndMut { ty: *lhs_deref_ty, mutbl: lhs_inv_mutbl }, ); suggest_different_borrow( @@ -522,10 +518,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let rhs_inv_mutbl_ty = Ty::new_ref( self.tcx, *region, - ty::TypeAndMut { - ty: *rhs_deref_ty, - mutbl: rhs_inv_mutbl, - }, + ty::TypeAndMut { ty: *rhs_deref_ty, mutbl: rhs_inv_mutbl }, ); suggest_different_borrow( @@ -599,7 +592,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(output_def_id) = output_def_id && let Some(trait_def_id) = trait_def_id && self.tcx.parent(output_def_id) == trait_def_id - && let Some(output_ty) = output_ty.make_suggestable(self.tcx, false) + && let Some(output_ty) = + output_ty.make_suggestable(self.tcx, false) { Some(("Output", output_ty)) } else { diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 3f9c9b3381b..110ec052b35 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -406,16 +406,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .borrow_mut() .treat_byte_string_as_slice .insert(lt.hir_id.local_id); - pat_ty = Ty::new_imm_ref(tcx,tcx.lifetimes.re_static, Ty::new_slice(tcx,tcx.types.u8)); + pat_ty = + Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_slice(tcx, tcx.types.u8)); } } - if self.tcx.features().string_deref_patterns && let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind { + if self.tcx.features().string_deref_patterns + && let hir::ExprKind::Lit(Spanned { node: ast::LitKind::Str(..), .. }) = lt.kind + { let tcx = self.tcx; let expected = self.resolve_vars_if_possible(expected); pat_ty = match expected.kind() { ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().string() => expected, - ty::Str => Ty::new_static_str(tcx,), + ty::Str => Ty::new_static_str(tcx), _ => pat_ty, }; } @@ -707,7 +710,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>) { let tcx = self.tcx; if let PatKind::Ref(inner, mutbl) = pat.kind - && let PatKind::Binding(_, _, binding, ..) = inner.kind { + && let PatKind::Binding(_, _, binding, ..) = inner.kind + { let binding_parent_id = tcx.hir().parent_id(pat.hir_id); let binding_parent = tcx.hir().get(binding_parent_id); debug!(?inner, ?pat, ?binding_parent); @@ -754,7 +758,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("to declare a mutable {ident_kind} use"), format!("mut {binding}"), )) - }; match binding_parent { @@ -777,7 +780,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::Node::Pat(pt) if let PatKind::TupleStruct(_, pat_arr, _) = pt.kind => { for i in pat_arr.iter() { if let PatKind::Ref(the_ref, _) = i.kind - && let PatKind::Binding(mt, _, ident, _) = the_ref.kind { + && let PatKind::Binding(mt, _, ident, _) = the_ref.kind + { let hir::BindingAnnotation(_, mtblty) = mt; err.span_suggestion_verbose( i.span, @@ -1480,7 +1484,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (Some(mut err), None) => { err.emit(); } - (None, None) if let Some(mut err) = + (None, None) + if let Some(mut err) = self.error_tuple_variant_index_shorthand(variant, pat, fields) => { err.emit(); @@ -1504,9 +1509,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let has_shorthand_field_name = field_patterns.iter().any(|field| field.is_shorthand); if has_shorthand_field_name { - let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { - s.print_qpath(qpath, false) - }); + let path = rustc_hir_pretty::qpath_to_string(qpath); let mut err = struct_span_err!( self.tcx.sess, pat.span, @@ -1688,9 +1691,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; } - let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { - s.print_qpath(qpath, false) - }); + let path = rustc_hir_pretty::qpath_to_string(qpath); let mut err = struct_span_err!( self.tcx.sess, pat.span, @@ -1740,9 +1741,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { f } } - Err(_) => rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { - s.print_pat(field.pat) - }), + Err(_) => rustc_hir_pretty::pat_to_string(field.pat), } }) .collect::<Vec<String>>() @@ -2269,7 +2268,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let ty::Array(..) | ty::Slice(..) = ty.kind() { err.help("the semantics of slice patterns changed recently; see issue #62254"); - } else if self.autoderef(span, expected_ty) + } else if self + .autoderef(span, expected_ty) .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..))) && let Some(span) = ti.span && let Some(_) = ti.origin_expr @@ -2290,7 +2290,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); } - _ => () + _ => (), } if is_slice_or_array_or_vector.0 { err.span_suggestion( diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 9c16b486dbc..322859154bb 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -174,7 +174,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } hir::ExprKind::AssignOp(..) - if let Some(a) = self.typeck_results.adjustments_mut().get_mut(lhs.hir_id) => + if let Some(a) = + self.typeck_results.adjustments_mut().get_mut(lhs.hir_id) => { a.pop(); } @@ -247,7 +248,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // Since this is "after" the other adjustment to be // discarded, we do an extra `pop()` if let Some(Adjustment { - kind: Adjust::Pointer(PointerCoercion::Unsize), .. + kind: Adjust::Pointer(PointerCoercion::Unsize), + .. }) = a.pop() { // So the borrow discard actually happens here @@ -568,10 +570,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // Here we only detect impl trait definition conflicts when they // are equal modulo regions. - if let Some(last_opaque_ty) = self - .typeck_results - .concrete_opaque_types - .insert(opaque_type_key, hidden_type) + if let Some(last_opaque_ty) = + self.typeck_results.concrete_opaque_types.insert(opaque_type_key, hidden_type) && last_opaque_ty.ty != hidden_type.ty { assert!(!self.fcx.next_trait_solver()); diff --git a/compiler/rustc_incremental/messages.ftl b/compiler/rustc_incremental/messages.ftl index 9fa4e0fb27c..5d885e07192 100644 --- a/compiler/rustc_incremental/messages.ftl +++ b/compiler/rustc_incremental/messages.ftl @@ -46,8 +46,6 @@ incremental_delete_partial = failed to delete partly initialized session dir `{$ incremental_delete_workproduct = file-system error deleting outdated file `{$path}`: {$err} -incremental_field_associated_value_expected = associated value expected for `{$name}` - incremental_finalize = error finalizing incremental compilation session directory `{$path}`: {$err} incremental_finalized_gc_failed = @@ -63,25 +61,15 @@ incremental_load_dep_graph = could not load dep-graph from `{$path}`: {$err} incremental_lock_unsupported = the filesystem for the incremental path at {$session_dir} does not appear to support locking, consider changing the incremental path to a filesystem that supports locking or disable incremental compilation -incremental_malformed_cgu_name = - found malformed codegen unit name `{$user_path}`. codegen units names must always start with the name of the crate (`{$crate_name}` in this case). incremental_missing_depnode = missing `DepNode` variant incremental_missing_if_this_changed = no `#[rustc_if_this_changed]` annotation detected -incremental_missing_query_depgraph = - found CGU-reuse attribute but `-Zquery-dep-graph` was not specified - incremental_move_dep_graph = failed to move dependency graph from `{$from}` to `{$to}`: {$err} incremental_no_cfg = no cfg attribute -incremental_no_field = no field `{$name}` - -incremental_no_module_named = - no module named `{$user_path}` (mangled: {$cgu_name}). available modules: {$cgu_names} - incremental_no_path = no path from `{$source}` to `{$target}` incremental_not_clean = `{$dep_node_str}` should be clean but is not @@ -107,8 +95,6 @@ incremental_undefined_clean_dirty_assertions_item = incremental_unknown_item = unknown item `{$name}` -incremental_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified - incremental_unrecognized_depnode = unrecognized `DepNode` variant: {$name} incremental_unrecognized_depnode_label = dep-node label `{$label}` not recognized diff --git a/compiler/rustc_incremental/src/errors.rs b/compiler/rustc_incremental/src/errors.rs index deb87678365..05ed4f7598d 100644 --- a/compiler/rustc_incremental/src/errors.rs +++ b/compiler/rustc_incremental/src/errors.rs @@ -41,56 +41,6 @@ pub struct NoPath { } #[derive(Diagnostic)] -#[diag(incremental_unknown_reuse_kind)] -pub struct UnknownReuseKind { - #[primary_span] - pub span: Span, - pub kind: Symbol, -} - -#[derive(Diagnostic)] -#[diag(incremental_missing_query_depgraph)] -pub struct MissingQueryDepGraph { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(incremental_malformed_cgu_name)] -pub struct MalformedCguName { - #[primary_span] - pub span: Span, - pub user_path: String, - pub crate_name: String, -} - -#[derive(Diagnostic)] -#[diag(incremental_no_module_named)] -pub struct NoModuleNamed<'a> { - #[primary_span] - pub span: Span, - pub user_path: &'a str, - pub cgu_name: Symbol, - pub cgu_names: String, -} - -#[derive(Diagnostic)] -#[diag(incremental_field_associated_value_expected)] -pub struct FieldAssociatedValueExpected { - #[primary_span] - pub span: Span, - pub name: Symbol, -} - -#[derive(Diagnostic)] -#[diag(incremental_no_field)] -pub struct NoField { - #[primary_span] - pub span: Span, - pub name: Symbol, -} - -#[derive(Diagnostic)] #[diag(incremental_assertion_auto)] pub struct AssertionAuto<'a> { #[primary_span] diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index 220ea194a6d..bdae07a3946 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -2,6 +2,9 @@ #![deny(missing_docs)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), allow(internal_features))] #![feature(never_type)] #![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] @@ -13,7 +16,6 @@ extern crate rustc_middle; extern crate tracing; mod assert_dep_graph; -pub mod assert_module_sources; mod errors; mod persist; diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index 9276bb0a7b7..57bc14ebcb3 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -60,9 +60,7 @@ impl<'a> DescriptionCtx<'a> { let span = Some(tcx.def_span(scope)); (span, "defined_here", String::new()) } - _ => { - (Some(tcx.def_span(scope)), "defined_here_reg", region.to_string()) - } + _ => (Some(tcx.def_span(scope)), "defined_here_reg", region.to_string()), } } } diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index 665297da20f..5d929394eb0 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -56,7 +56,7 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { // performing trait matching (which then performs equality // unification). - relate::relate_args(self, a_arg, b_arg) + relate::relate_args_invariantly(self, a_arg, b_arg) } fn relate_with_variance<T: Relate<'tcx>>( diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 12dcb711820..496bb1766a7 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -67,7 +67,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_middle::dep_graph::DepContext; -use rustc_middle::ty::print::with_forced_trimmed_paths; +use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError}; use rustc_middle::ty::relate::{self, RelateResult, TypeRelation}; use rustc_middle::ty::{ self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable, @@ -227,8 +227,10 @@ fn msg_span_from_named_region<'tcx>( let scope = region.free_region_binding_scope(tcx).expect_local(); match fr.bound_region { ty::BoundRegionKind::BrNamed(_, name) => { - let span = if let Some(param) = - tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name)) + let span = if let Some(param) = tcx + .hir() + .get_generics(scope) + .and_then(|generics| generics.get_named(name)) { param.span } else { @@ -243,7 +245,7 @@ fn msg_span_from_named_region<'tcx>( } ty::BrAnon => ( "the anonymous lifetime as defined here".to_string(), - Some(tcx.def_span(scope)) + Some(tcx.def_span(scope)), ), _ => ( format!("the lifetime `{region}` as defined here"), @@ -578,76 +580,68 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { struct AbsolutePathPrinter<'tcx> { tcx: TyCtxt<'tcx>, + segments: Vec<String>, } - struct NonTrivialPath; - impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { - type Error = NonTrivialPath; - - type Path = Vec<String>; - type Region = !; - type Type = !; - type DynExistential = !; - type Const = !; - fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { self.tcx } - fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> { - Err(NonTrivialPath) + fn print_region(self, _region: ty::Region<'_>) -> Result<Self, PrintError> { + Err(fmt::Error) } - fn print_type(self, _ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> { - Err(NonTrivialPath) + fn print_type(self, _ty: Ty<'tcx>) -> Result<Self, PrintError> { + Err(fmt::Error) } fn print_dyn_existential( self, _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, - ) -> Result<Self::DynExistential, Self::Error> { - Err(NonTrivialPath) + ) -> Result<Self, PrintError> { + Err(fmt::Error) } - fn print_const(self, _ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { - Err(NonTrivialPath) + fn print_const(self, _ct: ty::Const<'tcx>) -> Result<Self, PrintError> { + Err(fmt::Error) } - fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { - Ok(vec![self.tcx.crate_name(cnum).to_string()]) + fn path_crate(mut self, cnum: CrateNum) -> Result<Self, PrintError> { + self.segments = vec![self.tcx.crate_name(cnum).to_string()]; + Ok(self) } fn path_qualified( self, _self_ty: Ty<'tcx>, _trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { - Err(NonTrivialPath) + ) -> Result<Self, PrintError> { + Err(fmt::Error) } fn path_append_impl( self, - _print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + _print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, _disambiguated_data: &DisambiguatedDefPathData, _self_ty: Ty<'tcx>, _trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { - Err(NonTrivialPath) + ) -> Result<Self, PrintError> { + Err(fmt::Error) } fn path_append( - self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + mut self, + print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, disambiguated_data: &DisambiguatedDefPathData, - ) -> Result<Self::Path, Self::Error> { - let mut path = print_prefix(self)?; - path.push(disambiguated_data.to_string()); - Ok(path) + ) -> Result<Self, PrintError> { + self = print_prefix(self)?; + self.segments.push(disambiguated_data.to_string()); + Ok(self) } fn path_generic_args( self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, _args: &[GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { print_prefix(self) } } @@ -657,12 +651,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // are from a local module we could have false positives, e.g. // let _ = [{struct Foo; Foo}, {struct Foo; Foo}]; if did1.krate != did2.krate { - let abs_path = - |def_id| AbsolutePathPrinter { tcx: self.tcx }.print_def_path(def_id, &[]); + let abs_path = |def_id| { + AbsolutePathPrinter { tcx: self.tcx, segments: vec![] } + .print_def_path(def_id, &[]) + .map(|p| p.segments) + }; // We compare strings because DefPath can be different // for imported and non-imported crates - let same_path = || -> Result<_, NonTrivialPath> { + let same_path = || -> Result<_, PrintError> { Ok(self.tcx.def_path_str(did1) == self.tcx.def_path_str(did2) || abs_path(did1)? == abs_path(did2)?) }; @@ -715,13 +712,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { && let ty::Adt(def, args) = ty.kind() && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option) { - err.span_label(span, format!("this is an iterator with items of type `{}`", args.type_at(0))); + err.span_label( + span, + format!("this is an iterator with items of type `{}`", args.type_at(0)), + ); } else { - err.span_label(span, format!("this expression has type `{ty}`")); - } + err.span_label(span, format!("this expression has type `{ty}`")); + } } if let Some(ty::error::ExpectedFound { found, .. }) = exp_found - && ty.is_box() && ty.boxed_ty() == found + && ty.is_box() + && ty.boxed_ty() == found && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { err.span_suggestion( @@ -743,9 +744,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id); let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind { let arg_expr = args.first().expect("try desugaring call w/out arg"); - self.typeck_results.as_ref().and_then(|typeck_results| { - typeck_results.expr_ty_opt(arg_expr) - }) + self.typeck_results + .as_ref() + .and_then(|typeck_results| typeck_results.expr_ty_opt(arg_expr)) } else { bug!("try desugaring w/out call expr as scrutinee"); }; @@ -763,7 +764,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { _ => {} } } - }, + } ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { arm_block_id, arm_span, @@ -782,9 +783,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id); let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind { let arg_expr = args.first().expect("try desugaring call w/out arg"); - self.typeck_results.as_ref().and_then(|typeck_results| { - typeck_results.expr_ty_opt(arg_expr) - }) + self.typeck_results + .as_ref() + .and_then(|typeck_results| typeck_results.expr_ty_opt(arg_expr)) } else { bug!("try desugaring w/out call expr as scrutinee"); }; @@ -878,8 +879,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } // don't suggest wrapping either blocks in `if .. {} else {}` let is_empty_arm = |id| { - let hir::Node::Block(blk) = self.tcx.hir().get(id) - else { + let hir::Node::Block(blk) = self.tcx.hir().get(id) else { return false; }; if blk.expr.is_some() || !blk.stmts.is_empty() { @@ -908,12 +908,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } _ => { if let ObligationCauseCode::BindingObligation(_, span) - | ObligationCauseCode::ExprBindingObligation(_, span, ..) - = cause.code().peel_derives() + | ObligationCauseCode::ExprBindingObligation(_, span, ..) = + cause.code().peel_derives() && let TypeError::RegionsPlaceholderMismatch = terr { - err.span_note( * span, - "the lifetime requirement is introduced here"); + err.span_note(*span, "the lifetime requirement is introduced here"); } } } @@ -1742,19 +1741,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } let similarity = |ExpectedFound { expected, found }: ExpectedFound<Ty<'tcx>>| { - if let ty::Adt(expected, _) = expected.kind() && let Some(primitive) = found.primitive_symbol() { + if let ty::Adt(expected, _) = expected.kind() + && let Some(primitive) = found.primitive_symbol() + { let path = self.tcx.def_path(expected.did()).data; let name = path.last().unwrap().data.get_opt_name(); if name == Some(primitive) { return Some(Similar::PrimitiveFound { expected: *expected, found }); } - } else if let Some(primitive) = expected.primitive_symbol() && let ty::Adt(found, _) = found.kind() { + } else if let Some(primitive) = expected.primitive_symbol() + && let ty::Adt(found, _) = found.kind() + { let path = self.tcx.def_path(found.did()).data; let name = path.last().unwrap().data.get_opt_name(); if name == Some(primitive) { return Some(Similar::PrimitiveExpected { expected, found: *found }); } - } else if let ty::Adt(expected, _) = expected.kind() && let ty::Adt(found, _) = found.kind() { + } else if let ty::Adt(expected, _) = expected.kind() + && let ty::Adt(found, _) = found.kind() + { if !expected.did().is_local() && expected.did().krate == found.did().krate { // Most likely types from different versions of the same crate // are in play, in which case this message isn't so helpful. @@ -1764,8 +1769,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let f_path = self.tcx.def_path(found.did()).data; let e_path = self.tcx.def_path(expected.did()).data; - if let (Some(e_last), Some(f_last)) = (e_path.last(), f_path.last()) && e_last == f_last { - return Some(Similar::Adts{expected: *expected, found: *found}); + if let (Some(e_last), Some(f_last)) = (e_path.last(), f_path.last()) + && e_last == f_last + { + return Some(Similar::Adts { expected: *expected, found: *found }); } } None @@ -1796,7 +1803,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; let diagnose_adts = - |expected_adt : ty::AdtDef<'tcx>, + |expected_adt: ty::AdtDef<'tcx>, found_adt: ty::AdtDef<'tcx>, diagnostic: &mut Diagnostic| { let found_name = values.found.sort_string(self.tcx); @@ -1816,8 +1823,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .tcx .parent_module_from_def_id(defid.expect_local()) .to_def_id(); - let module_name = self.tcx.def_path(module).to_string_no_crate_verbose(); - format!("{name} is defined in module `crate{module_name}` of the current crate") + let module_name = + self.tcx.def_path(module).to_string_no_crate_verbose(); + format!( + "{name} is defined in module `crate{module_name}` of the current crate" + ) } else if defid.is_local() { format!("{name} is defined in the current crate") } else { @@ -1829,13 +1839,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; match s { - Similar::Adts{expected, found} => { - diagnose_adts(expected, found, diag) - } - Similar::PrimitiveFound{expected, found: prim} => { + Similar::Adts { expected, found } => diagnose_adts(expected, found, diag), + Similar::PrimitiveFound { expected, found: prim } => { diagnose_primitive(prim, values.expected, expected.did(), diag) } - Similar::PrimitiveExpected{expected: prim, found} => { + Similar::PrimitiveExpected { expected: prim, found } => { diagnose_primitive(prim, values.found, found.did(), diag) } } @@ -1877,7 +1885,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } s }; - if !(values.expected.is_simple_text(self.tcx) && values.found.is_simple_text(self.tcx)) + if !(values.expected.is_simple_text(self.tcx) + && values.found.is_simple_text(self.tcx)) || (exp_found.is_some_and(|ef| { // This happens when the type error is a subset of the expectation, // like when you have two references but one is `usize` and the other @@ -1967,13 +1976,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { && let exp_found = TypeError::Sorts(exp_found) && exp_found != terr { - self.note_and_explain_type_err( - diag, - exp_found, - cause, - span, - cause.body_id.to_def_id(), - ); + self.note_and_explain_type_err(diag, exp_found, cause, span, cause.body_id.to_def_id()); } if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values @@ -1983,7 +1986,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { { let span = self.tcx.def_span(def_id); diag.span_note(span, "this closure does not fulfill the lifetime requirements"); - self.suggest_for_all_lifetime_closure(span, self.tcx.hir().get_by_def_id(def_id), &exp_found, diag); + self.suggest_for_all_lifetime_closure( + span, + self.tcx.hir().get_by_def_id(def_id), + &exp_found, + diag, + ); } // It reads better to have the error origin as the final @@ -2009,7 +2017,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // parentheses around it, perhaps the user meant to write `(expr,)` to // build a tuple (issue #86100) (ty::Tuple(fields), _) => { - suggestions.extend(self.suggest_wrap_to_build_a_tuple( span, found, fields)) + suggestions.extend(self.suggest_wrap_to_build_a_tuple(span, found, fields)) } // If a byte was expected and the found expression is a char literal // containing a single ASCII character, perhaps the user meant to write `b'c'` to @@ -2059,8 +2067,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } // For code `if Some(..) = expr `, the type mismatch may be expected `bool` but found `()`, // we try to suggest to add the missing `let` for `if let Some(..) = expr` - (ty::Bool, ty::Tuple(list)) => if list.len() == 0 { - suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span)); + (ty::Bool, ty::Tuple(list)) => { + if list.len() == 0 { + suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span)); + } } (ty::Array(_, _), ty::Array(_, _)) => { suggestions.extend(self.suggest_specify_actual_length(terr, trace, span)) @@ -2070,8 +2080,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } let code = trace.cause.code(); if let &(MatchExpressionArm(box MatchExpressionArmCause { source, .. }) - | BlockTailExpression(.., source) - ) = code + | BlockTailExpression(.., source)) = code && let hir::MatchSource::TryDesugar(_) = source && let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values) { @@ -2108,17 +2117,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // Find a local statement where the initializer has // the same span as the error and the type is specified. if let hir::Stmt { - kind: hir::StmtKind::Local(hir::Local { - init: Some(hir::Expr { - span: init_span, + kind: + hir::StmtKind::Local(hir::Local { + init: Some(hir::Expr { span: init_span, .. }), + ty: Some(array_ty), .. }), - ty: Some(array_ty), - .. - }), .. } = s - && init_span == &self.span { + && init_span == &self.span + { self.result = Some(*array_ty); } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index e45108d1713..5408b99235d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -163,13 +163,13 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte let ty_vars = infcx_inner.type_variables(); let var_origin = ty_vars.var_origin(ty_vid); if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind - && name != kw::SelfUpper && !var_origin.span.from_expansion() + && name != kw::SelfUpper + && !var_origin.span.from_expansion() { let generics = infcx.tcx.generics_of(infcx.tcx.parent(def_id)); let idx = generics.param_def_id_to_index(infcx.tcx, def_id).unwrap(); let generic_param_def = generics.param_at(idx as usize, infcx.tcx); - if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param_def.kind - { + if let ty::GenericParamDefKind::Type { synthetic: true, .. } = generic_param_def.kind { None } else { Some(name) @@ -792,8 +792,9 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { let cost = self.source_cost(&new_source) + self.attempt; debug!(?cost); self.attempt += 1; - if let Some(InferSource { kind: InferSourceKind::GenericArg { def_id: did, ..}, .. }) = self.infer_source - && let InferSourceKind::LetBinding { ref ty, ref mut def_id, ..} = new_source.kind + if let Some(InferSource { kind: InferSourceKind::GenericArg { def_id: did, .. }, .. }) = + self.infer_source + && let InferSourceKind::LetBinding { ref ty, ref mut def_id, .. } = new_source.kind && ty.is_ty_or_numeric_infer() { // Customize the output so we talk about `let x: Vec<_> = iter.collect();` instead of @@ -1242,7 +1243,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { successor, args, def_id, - } + }, }) } } 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 4aec28b051f..d6a3bc32cc9 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 @@ -28,7 +28,7 @@ pub struct Highlighted<'tcx, T> { impl<'tcx, T> IntoDiagnosticArg for Highlighted<'tcx, T> where - T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>, + T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>>, { fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { rustc_errors::DiagnosticArgValue::Str(self.to_string().into()) @@ -43,7 +43,7 @@ impl<'tcx, T> Highlighted<'tcx, T> { impl<'tcx, T> fmt::Display for Highlighted<'tcx, T> where - T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>, + T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 3cfda0cc5c0..e2be6cf4280 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -214,7 +214,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ObligationCauseCode::MatchImpl(parent, ..) => parent.code(), _ => cause.code(), } - && let (&ObligationCauseCode::ItemObligation(item_def_id) | &ObligationCauseCode::ExprItemObligation(item_def_id, ..), None) = (code, override_error_code) + && let ( + &ObligationCauseCode::ItemObligation(item_def_id) + | &ObligationCauseCode::ExprItemObligation(item_def_id, ..), + None, + ) = (code, override_error_code) { // Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static` // lifetime as above, but called using a fully-qualified path to the method: @@ -322,13 +326,27 @@ pub fn suggest_new_region_bound( let existing_lt_name = if let Some(id) = scope_def_id && let Some(generics) = tcx.hir().get_generics(id) && let named_lifetimes = generics - .params - .iter() - .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit })) - .map(|p| { if let hir::ParamName::Plain(name) = p.name {Some(name.to_string())} else {None}}) - .filter(|n| ! matches!(n, None)) - .collect::<Vec<_>>() - && named_lifetimes.len() > 0 { + .params + .iter() + .filter(|p| { + matches!( + p.kind, + GenericParamKind::Lifetime { + kind: hir::LifetimeParamKind::Explicit + } + ) + }) + .map(|p| { + if let hir::ParamName::Plain(name) = p.name { + Some(name.to_string()) + } else { + None + } + }) + .filter(|n| !matches!(n, None)) + .collect::<Vec<_>>() + && named_lifetimes.len() > 0 + { named_lifetimes[0].clone() } else { None @@ -342,30 +360,28 @@ pub fn suggest_new_region_bound( .params .iter() .filter(|p| p.is_elided_lifetime()) - .map(|p| - if p.span.hi() - p.span.lo() == rustc_span::BytePos(1) { // Ampersand (elided without '_) - (p.span.shrink_to_hi(),format!("{name} ")) - } else { // Underscore (elided with '_) - (p.span, name.to_string()) - } - ) + .map(|p| { + if p.span.hi() - p.span.lo() == rustc_span::BytePos(1) { + // Ampersand (elided without '_) + (p.span.shrink_to_hi(), format!("{name} ")) + } else { + // Underscore (elided with '_) + (p.span, name.to_string()) + } + }) .collect::<Vec<_>>() && spans_suggs.len() > 1 { - let use_lt = - if existing_lt_name == None { + let use_lt = if existing_lt_name == None { spans_suggs.push((generics.span.shrink_to_hi(), format!("<{name}>"))); format!("you can introduce a named lifetime parameter `{name}`") } else { // make use the existing named lifetime format!("you can use the named lifetime parameter `{name}`") }; - spans_suggs - .push((fn_return.span.shrink_to_hi(), format!(" + {name} "))); + spans_suggs.push((fn_return.span.shrink_to_hi(), format!(" + {name} "))); err.multipart_suggestion_verbose( - format!( - "{declare} `{ty}` {captures}, {use_lt}", - ), + format!("{declare} `{ty}` {captures}, {use_lt}",), spans_suggs, Applicability::MaybeIncorrect, ); @@ -443,8 +459,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let trait_did = trait_id.to_def_id(); tcx.hir().trait_impls(trait_did).iter().find_map(|&impl_did| { if let Node::Item(Item { - kind: ItemKind::Impl(hir::Impl { self_ty, .. }), - .. + kind: ItemKind::Impl(hir::Impl { self_ty, .. }), .. }) = tcx.hir().find_by_def_id(impl_did)? && trait_objects.iter().all(|did| { // FIXME: we should check `self_ty` against the receiver diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index 5c3beee284f..8ecf63ec665 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -72,32 +72,30 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { #traits-as-parameters", ); } - (ty::Alias(ty::Projection | ty::Inherent, _), ty::Alias(ty::Projection | ty::Inherent, _)) => { + ( + ty::Alias(ty::Projection | ty::Inherent, _), + ty::Alias(ty::Projection | ty::Inherent, _), + ) => { diag.note("an associated type was expected, but a different one was found"); } // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too. - (ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p)) + (ty::Param(p), ty::Alias(ty::Projection, proj)) + | (ty::Alias(ty::Projection, proj), ty::Param(p)) if !tcx.is_impl_trait_in_trait(proj.def_id) => { - let p_def_id = tcx - .generics_of(body_owner_def_id) - .type_param(p, tcx) - .def_id; + let p_def_id = tcx.generics_of(body_owner_def_id).type_param(p, tcx).def_id; let p_span = tcx.def_span(p_def_id); if !sp.contains(p_span) { diag.span_label(p_span, "this type parameter"); } let hir = tcx.hir(); let mut note = true; - let parent = p_def_id - .as_local() - .and_then(|id| { - let local_id = hir.local_def_id_to_hir_id(id); - let generics = tcx.hir().find_parent(local_id)?.generics()?; - Some((id, generics)) - }); - if let Some((local_id, generics)) = parent - { + let parent = p_def_id.as_local().and_then(|id| { + let local_id = hir.local_def_id_to_hir_id(id); + let generics = tcx.hir().find_parent(local_id)?.generics()?; + Some((id, generics)) + }); + if let Some((local_id, generics)) = parent { // Synthesize the associated type restriction `Add<Output = Expected>`. // FIXME: extract this logic for use in other diagnostics. let (trait_ref, assoc_args) = proj.trait_ref_and_own_args(tcx); @@ -112,15 +110,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let mut matching_span = None; let mut matched_end_of_args = false; for bound in generics.bounds_for_param(local_id) { - let potential_spans = bound - .bounds - .iter() - .find_map(|bound| { - let bound_trait_path = bound.trait_ref()?.path; - let def_id = bound_trait_path.res.opt_def_id()?; - let generic_args = bound_trait_path.segments.iter().last().map(|path| path.args()); - (def_id == trait_ref.def_id).then_some((bound_trait_path.span, generic_args)) - }); + let potential_spans = bound.bounds.iter().find_map(|bound| { + let bound_trait_path = bound.trait_ref()?.path; + let def_id = bound_trait_path.res.opt_def_id()?; + let generic_args = bound_trait_path + .segments + .iter() + .last() + .map(|path| path.args()); + (def_id == trait_ref.def_id) + .then_some((bound_trait_path.span, generic_args)) + }); if let Some((end_of_trait, end_of_args)) = potential_spans { let args_span = end_of_args.and_then(|args| args.span()); @@ -223,7 +223,9 @@ impl<T> Trait<T> for X { diag.span_label(p_span, "this type parameter"); } } - (ty::Alias(ty::Projection | ty::Inherent, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => { + (ty::Alias(ty::Projection | ty::Inherent, proj_ty), _) + if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => + { self.expected_projection( diag, proj_ty, @@ -232,11 +234,15 @@ impl<T> Trait<T> for X { cause.code(), ); } - (_, ty::Alias(ty::Projection | ty::Inherent, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => { - let msg = || format!( - "consider constraining the associated type `{}` to `{}`", - values.found, values.expected, - ); + (_, ty::Alias(ty::Projection | ty::Inherent, proj_ty)) + if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => + { + let msg = || { + format!( + "consider constraining the associated type `{}` to `{}`", + values.found, values.expected, + ) + }; if !(self.suggest_constraining_opaque_associated_type( diag, msg, @@ -256,19 +262,40 @@ impl<T> Trait<T> for X { ); } } - (ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if alias.def_id.is_local() && matches!(tcx.def_kind(body_owner_def_id), DefKind::Fn | DefKind::Static(_) | DefKind::Const | DefKind::AssocFn | DefKind::AssocConst) => { + (ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) + if alias.def_id.is_local() + && matches!( + tcx.def_kind(body_owner_def_id), + DefKind::Fn + | DefKind::Static(_) + | DefKind::Const + | DefKind::AssocFn + | DefKind::AssocConst + ) => + { if tcx.is_type_alias_impl_trait(alias.def_id) { - if !tcx.opaque_types_defined_by(body_owner_def_id.expect_local()).contains(&alias.def_id.expect_local()) { - let sp = tcx.def_ident_span(body_owner_def_id).unwrap_or_else(|| tcx.def_span(body_owner_def_id)); - diag.span_note(sp, "\ + if !tcx + .opaque_types_defined_by(body_owner_def_id.expect_local()) + .contains(&alias.def_id.expect_local()) + { + let sp = tcx + .def_ident_span(body_owner_def_id) + .unwrap_or_else(|| tcx.def_span(body_owner_def_id)); + diag.span_note( + sp, + "\ this item must have the opaque type in its signature \ - in order to be able to register hidden types"); + in order to be able to register hidden types", + ); } } } - (ty::FnPtr(sig), ty::FnDef(def_id, _)) | (ty::FnDef(def_id, _), ty::FnPtr(sig)) => { + (ty::FnPtr(sig), ty::FnDef(def_id, _)) + | (ty::FnDef(def_id, _), ty::FnPtr(sig)) => { if tcx.fn_sig(*def_id).skip_binder().unsafety() < sig.unsafety() { - diag.note("unsafe functions cannot be coerced into safe function pointers"); + diag.note( + "unsafe functions cannot be coerced into safe function pointers", + ); } } _ => {} @@ -314,39 +341,48 @@ impl<T> Trait<T> for X { let tcx = self.tcx; let assoc = tcx.associated_item(proj_ty.def_id); let (trait_ref, assoc_args) = proj_ty.trait_ref_and_own_args(tcx); - if let Some(item) = tcx.hir().get_if_local(body_owner_def_id) { - if let Some(hir_generics) = item.generics() { - // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`. - // This will also work for `impl Trait`. - let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() { - let generics = tcx.generics_of(body_owner_def_id); - generics.type_param(param_ty, tcx).def_id - } else { - return false; - }; - let Some(def_id) = def_id.as_local() else { - return false; - }; - - // First look in the `where` clause, as this might be - // `fn foo<T>(x: T) where T: Trait`. - for pred in hir_generics.bounds_for_param(def_id) { - if self.constrain_generic_bound_associated_type_structured_suggestion( - diag, - &trait_ref, - pred.bounds, - assoc, - assoc_args, - ty, - &msg, - false, - ) { - return true; - } - } + let Some(item) = tcx.hir().get_if_local(body_owner_def_id) else { + return false; + }; + let Some(hir_generics) = item.generics() else { + return false; + }; + // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`. + // This will also work for `impl Trait`. + let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() { + let generics = tcx.generics_of(body_owner_def_id); + generics.type_param(param_ty, tcx).def_id + } else { + return false; + }; + let Some(def_id) = def_id.as_local() else { + return false; + }; + + // First look in the `where` clause, as this might be + // `fn foo<T>(x: T) where T: Trait`. + for pred in hir_generics.bounds_for_param(def_id) { + if self.constrain_generic_bound_associated_type_structured_suggestion( + diag, + &trait_ref, + pred.bounds, + assoc, + assoc_args, + ty, + &msg, + false, + ) { + return true; } } - false + // If associated item, look to constrain the params of the trait/impl. + let hir_id = match item { + hir::Node::ImplItem(item) => item.hir_id(), + hir::Node::TraitItem(item) => item.hir_id(), + _ => return false, + }; + let parent = tcx.hir().get_parent_item(hir_id).def_id; + self.suggest_constraint(diag, msg, parent.into(), proj_ty, ty) } /// An associated type was expected and a different type was found. @@ -399,21 +435,26 @@ impl<T> Trait<T> for X { let impl_comparison = matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. }); let assoc = tcx.associated_item(proj_ty.def_id); - if !callable_scope || impl_comparison { + if impl_comparison { // We do not want to suggest calling functions when the reason of the - // type error is a comparison of an `impl` with its `trait` or when the - // scope is outside of a `Body`. + // type error is a comparison of an `impl` with its `trait`. } else { - // If we find a suitable associated function that returns the expected type, we don't - // want the more general suggestion later in this method about "consider constraining - // the associated type or calling a method that returns the associated type". - let point_at_assoc_fn = self.point_at_methods_that_satisfy_associated_type( - diag, - assoc.container_id(tcx), - current_method_ident, - proj_ty.def_id, - values.expected, - ); + let point_at_assoc_fn = if callable_scope + && self.point_at_methods_that_satisfy_associated_type( + diag, + assoc.container_id(tcx), + current_method_ident, + proj_ty.def_id, + values.expected, + ) { + // If we find a suitable associated function that returns the expected type, we + // don't want the more general suggestion later in this method about "consider + // constraining the associated type or calling a method that returns the associated + // type". + true + } else { + false + }; // Possibly suggest constraining the associated type to conform to the // found type. if self.suggest_constraint(diag, &msg, body_owner_def_id, proj_ty, values.found) @@ -616,7 +657,8 @@ fn foo(&self) -> Self::T { String::new() } for item in &items[..] { if let hir::AssocItemKind::Type = item.kind { let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity(); - if let hir::Defaultness::Default { has_value: true } = tcx.defaultness(item.id.owner_id) + if let hir::Defaultness::Default { has_value: true } = + tcx.defaultness(item.id.owner_id) && self.infcx.can_eq(param_env, assoc_ty, found) { diag.span_label( diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index f1d53cb59cd..fe18d00293a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -491,12 +491,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) { if let hir::StmtKind::Local(hir::Local { - span, pat: hir::Pat{..}, ty: None, init: Some(_), .. - }) = &ex.kind - && self.found_if - && span.eq(&self.err_span) { - self.result = true; - } + span, + pat: hir::Pat { .. }, + ty: None, + init: Some(_), + .. + }) = &ex.kind + && self.found_if + && span.eq(&self.err_span) + { + self.result = true; + } walk_stmt(self, ex); } @@ -546,45 +551,59 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let expected = expected.unpack(); let found = found.unpack(); // 3. Extract the tuple type from Fn trait and suggest the change. - if let GenericArgKind::Type(expected) = expected && - let GenericArgKind::Type(found) = found && - let ty::Tuple(expected) = expected.kind() && - let ty::Tuple(found)= found.kind() && - expected.len() == found.len() { + if let GenericArgKind::Type(expected) = expected + && let GenericArgKind::Type(found) = found + && let ty::Tuple(expected) = expected.kind() + && let ty::Tuple(found) = found.kind() + && expected.len() == found.len() + { let mut suggestion = "|".to_string(); let mut is_first = true; let mut has_suggestion = false; - for (((expected, found), param_hir), arg_hir) in expected.iter() - .zip(found.iter()) - .zip(params.iter()) - .zip(fn_decl.inputs.iter()) { + for (((expected, found), param_hir), arg_hir) in + expected.iter().zip(found.iter()).zip(params.iter()).zip(fn_decl.inputs.iter()) + { if is_first { is_first = false; } else { suggestion += ", "; } - if let ty::Ref(expected_region, _, _) = expected.kind() && - let ty::Ref(found_region, _, _) = found.kind() && - expected_region.is_late_bound() && - !found_region.is_late_bound() && - let hir::TyKind::Infer = arg_hir.kind { + if let ty::Ref(expected_region, _, _) = expected.kind() + && let ty::Ref(found_region, _, _) = found.kind() + && expected_region.is_late_bound() + && !found_region.is_late_bound() + && let hir::TyKind::Infer = arg_hir.kind + { // If the expected region is late bound, the found region is not, and users are asking compiler // to infer the type, we can suggest adding `: &_`. if param_hir.pat.span == param_hir.ty_span { // for `|x|`, `|_|`, `|x: impl Foo|` - let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; }; + let Ok(pat) = + self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) + else { + return; + }; suggestion += &format!("{pat}: &_"); } else { // for `|x: ty|`, `|_: ty|` - let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; }; - let Ok(ty) = self.tcx.sess.source_map().span_to_snippet(param_hir.ty_span) else { return; }; + let Ok(pat) = + self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) + else { + return; + }; + let Ok(ty) = self.tcx.sess.source_map().span_to_snippet(param_hir.ty_span) + else { + return; + }; suggestion += &format!("{pat}: &{ty}"); } has_suggestion = true; } else { - let Ok(arg) = self.tcx.sess.source_map().span_to_snippet(param_hir.span) else { return; }; + let Ok(arg) = self.tcx.sess.source_map().span_to_snippet(param_hir.span) else { + return; + }; // Otherwise, keep it as-is. suggestion += &arg; } diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs index 86c2c2be4a8..2f371c4fe31 100644 --- a/compiler/rustc_infer/src/infer/fudge.rs +++ b/compiler/rustc_infer/src/infer/fudge.rs @@ -220,7 +220,9 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> { } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - if let ty::ReVar(vid) = *r && self.region_vars.0.contains(&vid) { + if let ty::ReVar(vid) = *r + && self.region_vars.0.contains(&vid) + { let idx = vid.index() - self.region_vars.0.start.index(); let origin = self.region_vars.1[idx]; return self.infcx.next_region_var(origin); diff --git a/compiler/rustc_infer/src/infer/generalize.rs b/compiler/rustc_infer/src/infer/generalize.rs index dd7f8d35441..c1e65ffe0a6 100644 --- a/compiler/rustc_infer/src/infer/generalize.rs +++ b/compiler/rustc_infer/src/infer/generalize.rs @@ -183,7 +183,7 @@ where // Avoid fetching the variance if we are in an invariant // context; no need, and it can induce dependency cycles // (e.g., #41849). - relate::relate_args(self, a_subst, b_subst) + relate::relate_args_invariantly(self, a_subst, b_subst) } else { let tcx = self.tcx(); let opt_variances = tcx.variances_of(item_def_id); diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index cb651363982..bee0a978ad0 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -346,7 +346,9 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // tighter bound than `'static`. // // (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.) - if let ty::RePlaceholder(p) = *lub && b_universe.cannot_name(p.universe) { + if let ty::RePlaceholder(p) = *lub + && b_universe.cannot_name(p.universe) + { lub = self.tcx().lifetimes.re_static; } diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 09df93fcc2f..1c3a5c36076 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -145,25 +145,7 @@ impl<'tcx> InferCtxt<'tcx> { return None; } } - DefiningAnchor::Bubble => { - if let ty::Alias(ty::Opaque, _) = b.kind() { - // In bubble mode we don't know which of the two opaque types is supposed to have the other - // as a hidden type (both, none or either one of them could be in its defining scope). - let predicate = ty::PredicateKind::AliasRelate( - a.into(), - b.into(), - ty::AliasRelationDirection::Equate, - ); - let obligation = traits::Obligation::new( - self.tcx, - cause.clone(), - param_env, - predicate, - ); - let obligations = vec![obligation]; - return Some(Ok(InferOk { value: (), obligations })); - } - } + DefiningAnchor::Bubble => {} DefiningAnchor::Error => return None, }; if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() { diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index 2d6b88226ad..6f973ee37f5 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -177,7 +177,9 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> { value: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { debug!("self.pattern_depth = {:?}", self.pattern_depth); - if let ty::RegionKind::ReLateBound(depth, br) = pattern.kind() && depth == self.pattern_depth { + if let ty::RegionKind::ReLateBound(depth, br) = pattern.kind() + && depth == self.pattern_depth + { self.bind(br, value) } else if pattern == value { Ok(pattern) diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 4279d0ab7ab..7f0a4717d88 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -108,20 +108,20 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { let alias_ty_as_ty = alias_ty.to_ty(self.tcx); // Search the env for where clauses like `P: 'a`. - let env_bounds = self - .approx_declared_bounds_from_env(alias_ty) - .into_iter() - .map(|binder| { - if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == alias_ty_as_ty { - // Micro-optimize if this is an exact match (this - // occurs often when there are no region variables - // involved). - VerifyBound::OutlivedBy(r) - } else { - let verify_if_eq_b = binder.map_bound(|ty::OutlivesPredicate(ty, bound)| VerifyIfEq { ty, bound }); - VerifyBound::IfEq(verify_if_eq_b) - } - }); + let env_bounds = self.approx_declared_bounds_from_env(alias_ty).into_iter().map(|binder| { + if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() + && ty == alias_ty_as_ty + { + // Micro-optimize if this is an exact match (this + // occurs often when there are no region variables + // involved). + VerifyBound::OutlivedBy(r) + } else { + let verify_if_eq_b = + binder.map_bound(|ty::OutlivesPredicate(ty, bound)| VerifyIfEq { ty, bound }); + VerifyBound::IfEq(verify_if_eq_b) + } + }); // Extend with bounds that we can find from the definition. let definition_bounds = diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 708c51cabeb..3fa9a7333a4 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -457,7 +457,9 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { debug!("RegionConstraintCollector: add_verify({:?})", verify); // skip no-op cases known to be satisfied - if let VerifyBound::AllBounds(ref bs) = verify.bound && bs.is_empty() { + if let VerifyBound::AllBounds(ref bs) = verify.bound + && bs.is_empty() + { return; } diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index e92ba05aa67..4a6d1bc682b 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -13,6 +13,9 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), allow(internal_features))] #![feature(associated_type_bounds)] #![feature(box_patterns)] #![feature(control_flow_enum)] diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index e72a43630e9..7a335827f37 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -62,7 +62,9 @@ pub fn report_object_safety_error<'tcx>( let mut multi_span = vec![]; let mut messages = vec![]; for violation in violations { - if let ObjectSafetyViolation::SizedSelf(sp) = &violation && !sp.is_empty() { + if let ObjectSafetyViolation::SizedSelf(sp) = &violation + && !sp.is_empty() + { // Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations // with a `Span`. reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into())); diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 1c330c064ab..d2ce77ad535 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -5,6 +5,7 @@ use rustc_ast::{self as ast, LitKind, MetaItemKind}; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::defer; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::sync::Lrc; use rustc_errors::registry::Registry; use rustc_errors::{ErrorGuaranteed, Handler}; @@ -124,8 +125,13 @@ pub fn parse_cfgspecs( /// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`. pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> CheckCfg { rustc_span::create_default_session_if_not_set_then(move |_| { - let mut check_cfg = CheckCfg::default(); + // If any --check-cfg is passed then exhaustive_values and exhaustive_names + // are enabled by default. + let exhaustive_names = !specs.is_empty(); + let exhaustive_values = !specs.is_empty(); + let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg::default() }; + let mut old_syntax = None; for s in specs { let sess = ParseSess::with_silent_emitter(Some(format!( "this error occurred on the command line: `--check-cfg={s}`" @@ -141,18 +147,21 @@ pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> Check }; } - let expected_error = || { - error!( - "expected `names(name1, name2, ... nameN)` or \ - `values(name, \"value1\", \"value2\", ... \"valueN\")`" - ) - }; + let expected_error = + || error!("expected `cfg(name, values(\"value1\", \"value2\", ... \"valueN\"))`"); match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) { Ok(mut parser) => match parser.parse_meta_item() { Ok(meta_item) if parser.token == token::Eof => { if let Some(args) = meta_item.meta_item_list() { if meta_item.has_name(sym::names) { + // defaults are flipped for the old syntax + if old_syntax == None { + check_cfg.exhaustive_names = false; + check_cfg.exhaustive_values = false; + } + old_syntax = Some(true); + check_cfg.exhaustive_names = true; for arg in args { if arg.is_word() && arg.ident().is_some() { @@ -166,6 +175,13 @@ pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> Check } } } else if meta_item.has_name(sym::values) { + // defaults are flipped for the old syntax + if old_syntax == None { + check_cfg.exhaustive_names = false; + check_cfg.exhaustive_values = false; + } + old_syntax = Some(true); + if let Some((name, values)) = args.split_first() { if name.is_word() && name.ident().is_some() { let ident = name.ident().expect("multi-segment cfg key"); @@ -215,6 +231,116 @@ pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> Check } else { expected_error(); } + } else if meta_item.has_name(sym::cfg) { + old_syntax = Some(false); + + let mut names = Vec::new(); + let mut values: FxHashSet<_> = Default::default(); + + let mut any_specified = false; + let mut values_specified = false; + let mut values_any_specified = false; + + for arg in args { + if arg.is_word() && let Some(ident) = arg.ident() { + if values_specified { + error!("`cfg()` names cannot be after values"); + } + names.push(ident); + } else if arg.has_name(sym::any) + && let Some(args) = arg.meta_item_list() + { + if any_specified { + error!("`any()` cannot be specified multiple times"); + } + any_specified = true; + if !args.is_empty() { + error!("`any()` must be empty"); + } + } else if arg.has_name(sym::values) + && let Some(args) = arg.meta_item_list() + { + if names.is_empty() { + error!( + "`values()` cannot be specified before the names" + ); + } else if values_specified { + error!( + "`values()` cannot be specified multiple times" + ); + } + values_specified = true; + + for arg in args { + if let Some(LitKind::Str(s, _)) = + arg.lit().map(|lit| &lit.kind) + { + values.insert(Some(s.to_string())); + } else if arg.has_name(sym::any) + && let Some(args) = arg.meta_item_list() + { + if values_any_specified { + error!( + "`any()` in `values()` cannot be specified multiple times" + ); + } + values_any_specified = true; + if !args.is_empty() { + error!("`any()` must be empty"); + } + } else { + error!( + "`values()` arguments must be string literals or `any()`" + ); + } + } + } else { + error!( + "`cfg()` arguments must be simple identifiers, `any()` or `values(...)`" + ); + } + } + + if values.is_empty() && !values_any_specified && !any_specified { + values.insert(None); + } else if !values.is_empty() && values_any_specified { + error!( + "`values()` arguments cannot specify string literals and `any()` at the same time" + ); + } + + if any_specified { + if !names.is_empty() + || !values.is_empty() + || values_any_specified + { + error!("`cfg(any())` can only be provided in isolation"); + } + + check_cfg.exhaustive_names = false; + } else { + for name in names { + check_cfg + .expecteds + .entry(name.to_string()) + .and_modify(|v| match v { + ExpectedValues::Some(v) + if !values_any_specified => + { + v.extend(values.clone()) + } + ExpectedValues::Some(_) => *v = ExpectedValues::Any, + ExpectedValues::Any => {} + }) + .or_insert_with(|| { + if values_any_specified { + ExpectedValues::Any + } else { + ExpectedValues::Some(values.clone()) + } + }); + } + } } else { expected_error(); } @@ -260,6 +386,12 @@ pub struct Config { /// This is a callback from the driver that is called when [`ParseSess`] is created. pub parse_sess_created: Option<Box<dyn FnOnce(&mut ParseSess) + Send>>, + /// This is a callback to hash otherwise untracked state used by the caller, if the + /// hash changes between runs the incremental cache will be cleared. + /// + /// e.g. used by Clippy to hash its config file + pub hash_untracked_state: Option<Box<dyn FnOnce(&Session, &mut StableHasher) + Send>>, + /// This is a callback from the driver that is called when we're registering lints; /// it is called during plugin registration when we have the LintStore in a non-shared state. /// @@ -269,8 +401,6 @@ pub struct Config { /// This is a callback from the driver that is called just after we have populated /// the list of queries. - /// - /// The second parameter is local providers and the third parameter is external providers. pub override_queries: Option<fn(&Session, &mut Providers)>, /// This is a callback from the driver that is called to create a codegen backend. @@ -330,6 +460,12 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se parse_sess_created(&mut sess.parse_sess); } + if let Some(hash_untracked_state) = config.hash_untracked_state { + let mut hasher = StableHasher::new(); + hash_untracked_state(&sess, &mut hasher); + sess.opts.untracked_state_hash = hasher.finish() + } + let compiler = Compiler { sess: Lrc::new(sess), codegen_backend: Lrc::from(codegen_backend), diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 76131c1ad69..ffa2667a351 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -3,6 +3,7 @@ #![feature(internal_output_capture)] #![feature(thread_spawn_unchecked)] #![feature(lazy_cell)] +#![feature(let_chains)] #![feature(try_blocks)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 0e8f93cef17..718dbaaafcc 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -957,10 +957,9 @@ pub fn start_codegen<'tcx>( codegen_backend.codegen_crate(tcx, metadata, need_metadata_module) }); - // Don't run these test assertions when not doing codegen. Compiletest tries to build + // Don't run this test assertions when not doing codegen. Compiletest tries to build // build-fail tests in check mode first and expects it to not give an error in that case. if tcx.sess.opts.output_types.should_codegen() { - rustc_incremental::assert_module_sources::assert_module_sources(tcx); rustc_symbol_mangling::test::report_symbol_names(tcx); } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 2510ce71460..ec4fd78994e 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -9,6 +9,7 @@ use rustc_session::config::DebugInfo; use rustc_session::config::Input; use rustc_session::config::InstrumentXRay; use rustc_session::config::LinkSelfContained; +use rustc_session::config::Polonius; use rustc_session::config::TraitSolver; use rustc_session::config::{build_configuration, build_session_options, to_crate_config}; use rustc_session::config::{ @@ -769,6 +770,7 @@ fn test_unstable_options_tracking_hash() { ); tracked!(codegen_backend, Some("abc".to_string())); tracked!(crate_attr, vec!["abc".to_string()]); + tracked!(cross_crate_inline_threshold, Some(200)); tracked!(debug_info_for_profiling, true); tracked!(debug_macros, true); tracked!(dep_info_omit_d_target, true); @@ -814,7 +816,7 @@ fn test_unstable_options_tracking_hash() { tracked!(panic_abort_tests, true); tracked!(panic_in_drop, PanicStrategy::Abort); tracked!(plt, Some(true)); - tracked!(polonius, true); + tracked!(polonius, Polonius::Legacy); tracked!(precise_enum_drop_elaboration, false); tracked!(print_fuel, Some("abc".to_string())); tracked!(profile, true); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index fa4b8e4c36b..4c4d2933bf4 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -7,7 +7,7 @@ lint_array_into_iter = lint_async_fn_in_trait = use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified .note = you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future` - .suggestion = you can alternatively desugar to a normal `fn` that returns `impl Future` and add any desired bounds such as `Send` + .suggestion = you can alternatively desugar to a normal `fn` that returns `impl Future` and add any desired bounds such as `Send`, but these cannot be relaxed without a breaking API change lint_atomic_ordering_fence = memory fences cannot have `Relaxed` ordering .help = consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst` @@ -494,6 +494,8 @@ lint_renamed_lint = lint `{$name}` has been renamed to `{$replace}` lint_requested_level = requested on the command line with `{$level} {$lint_name}` +lint_span_use_eq_ctxt = use `.eq_ctxt()` instead of `.ctxt() == .ctxt()` + lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target .label = target type is set here diff --git a/compiler/rustc_lint/src/async_fn_in_trait.rs b/compiler/rustc_lint/src/async_fn_in_trait.rs index ff4c81e2fc9..2a49a003da1 100644 --- a/compiler/rustc_lint/src/async_fn_in_trait.rs +++ b/compiler/rustc_lint/src/async_fn_in_trait.rs @@ -11,7 +11,6 @@ declare_lint! { /// ### Example /// /// ```rust - /// # #![feature(async_fn_in_trait)] /// pub trait Trait { /// async fn method(&self); /// } @@ -33,7 +32,6 @@ declare_lint! { /// For example, this code is invalid: /// /// ```rust,compile_fail - /// # #![feature(async_fn_in_trait)] /// pub trait Trait { /// async fn method(&self) {} /// } @@ -51,7 +49,6 @@ declare_lint! { /// For example, instead of: /// /// ```rust - /// # #![feature(async_fn_in_trait)] /// pub trait Trait { /// async fn method(&self) {} /// } @@ -120,9 +117,12 @@ impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait { def.owner_id.def_id, " + Send", ); - cx.tcx.emit_spanned_lint(ASYNC_FN_IN_TRAIT, item.hir_id(), async_span, AsyncFnInTraitDiag { - sugg - }); + cx.tcx.emit_spanned_lint( + ASYNC_FN_IN_TRAIT, + item.hir_id(), + async_span, + AsyncFnInTraitDiag { sugg }, + ); } } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 536f78a73ed..f6c7f4071dc 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -121,16 +121,14 @@ impl EarlyLintPass for WhileTrue { { let condition_span = e.span.with_hi(cond.span.hi()); let replace = format!( - "{}loop", - label.map_or_else(String::new, |label| format!( - "{}: ", - label.ident, - )) - ); - cx.emit_spanned_lint(WHILE_TRUE, condition_span, BuiltinWhileTrue { - suggestion: condition_span, - replace, - }); + "{}loop", + label.map_or_else(String::new, |label| format!("{}: ", label.ident,)) + ); + cx.emit_spanned_lint( + WHILE_TRUE, + condition_span, + BuiltinWhileTrue { suggestion: condition_span, replace }, + ); } } } @@ -164,7 +162,9 @@ declare_lint_pass!(BoxPointers => [BOX_POINTERS]); impl BoxPointers { fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) { for leaf in ty.walk() { - if let GenericArgKind::Type(leaf_ty) = leaf.unpack() && leaf_ty.is_box() { + if let GenericArgKind::Type(leaf_ty) = leaf.unpack() + && leaf_ty.is_box() + { cx.emit_spanned_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty }); } } @@ -677,11 +677,17 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { if type_implements_negative_copy_modulo_regions(cx.tcx, ty, param_env) { return; } + if def.is_variant_list_non_exhaustive() + || def.variants().iter().any(|variant| variant.is_field_list_non_exhaustive()) + { + return; + } // We shouldn't recommend implementing `Copy` on stateful things, // such as iterators. if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator) - && cx.tcx + && cx + .tcx .infer_ctxt() .build() .type_implements_trait(iter_trait, [ty], param_env) @@ -1298,10 +1304,14 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { // Now, check if the function has the `#[track_caller]` attribute && let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller) { - cx.emit_spanned_lint(UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller { - label: span, - parse_sess: &cx.tcx.sess.parse_sess, - }); + cx.emit_spanned_lint( + UNGATED_ASYNC_FN_TRACK_CALLER, + attr.span, + BuiltinUngatedAsyncFnTrackCaller { + label: span, + parse_sess: &cx.tcx.sess.parse_sess, + }, + ); } } } @@ -2244,7 +2254,7 @@ declare_lint! { } declare_lint_pass!( - /// Check for used feature gates in `INCOMPLETE_FEATURES` in `rustc_feature/src/active.rs`. + /// Check for used feature gates in `INCOMPLETE_FEATURES` in `rustc_feature/src/unstable.rs`. IncompleteInternalFeatures => [INCOMPLETE_FEATURES, INTERNAL_FEATURES] ); @@ -2258,23 +2268,19 @@ impl EarlyLintPass for IncompleteInternalFeatures { .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span))) .filter(|(&name, _)| features.incomplete(name) || features.internal(name)) .for_each(|(&name, &span)| { - let note = rustc_feature::find_feature_issue(name, GateIssue::Language) - .map(|n| BuiltinFeatureIssueNote { n }); - if features.incomplete(name) { + let note = rustc_feature::find_feature_issue(name, GateIssue::Language) + .map(|n| BuiltinFeatureIssueNote { n }); let help = HAS_MIN_FEATURES.contains(&name).then_some(BuiltinIncompleteFeaturesHelp); + cx.emit_spanned_lint( INCOMPLETE_FEATURES, span, BuiltinIncompleteFeatures { name, note, help }, ); } else { - cx.emit_spanned_lint( - INTERNAL_FEATURES, - span, - BuiltinInternalFeatures { name, note }, - ); + cx.emit_spanned_lint(INTERNAL_FEATURES, span, BuiltinInternalFeatures { name }); } }); } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 3c5cde4309b..1f08db30860 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -31,7 +31,7 @@ use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::middle::stability; use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout}; -use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::print::{with_no_trimmed_paths, PrintError}; use rustc_middle::ty::{self, print::Printer, GenericArg, RegisteredTools, Ty, TyCtxt}; use rustc_session::config::ExpectedValues; use rustc_session::lint::{BuiltinLintDiagnostics, LintExpectationId}; @@ -727,11 +727,14 @@ pub trait LintContext: Sized { .collect::<Vec<_>>(); possibilities.sort(); + let mut should_print_possibilities = true; if let Some((value, value_span)) = value { if best_match_values.contains(&Some(value)) { db.span_suggestion(name_span, "there is a config with a similar name and value", best_match, Applicability::MaybeIncorrect); + should_print_possibilities = false; } else if best_match_values.contains(&None) { db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and no value", best_match, Applicability::MaybeIncorrect); + should_print_possibilities = false; } else if let Some(first_value) = possibilities.first() { db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and different values", format!("{best_match} = \"{first_value}\""), Applicability::MaybeIncorrect); } else { @@ -741,13 +744,25 @@ pub trait LintContext: Sized { db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect); } - if !possibilities.is_empty() { + if !possibilities.is_empty() && should_print_possibilities { let possibilities = possibilities.join("`, `"); db.help(format!("expected values for `{best_match}` are: `{possibilities}`")); } } else { db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect); } + } else if !possibilities.is_empty() { + let mut possibilities = possibilities.iter() + .map(Symbol::as_str) + .collect::<Vec<_>>(); + possibilities.sort(); + let possibilities = possibilities.join("`, `"); + + // The list of expected names can be long (even by default) and + // so the diagnostic produced can take a lot of space. To avoid + // cloging the user output we only want to print that diagnostic + // once. + db.help_once(format!("expected names are: `{possibilities}`")); } }, BuiltinLintDiagnostics::UnexpectedCfgValue((name, name_span), value) => { @@ -1185,51 +1200,45 @@ impl<'tcx> LateContext<'tcx> { /// } /// ``` pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> { - pub struct AbsolutePathPrinter<'tcx> { - pub tcx: TyCtxt<'tcx>, + struct AbsolutePathPrinter<'tcx> { + tcx: TyCtxt<'tcx>, + path: Vec<Symbol>, } impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { - type Error = !; - - type Path = Vec<Symbol>; - type Region = (); - type Type = (); - type DynExistential = (); - type Const = (); - fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } - fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> { - Ok(()) + fn print_region(self, _region: ty::Region<'_>) -> Result<Self, PrintError> { + Ok(self) } - fn print_type(self, _ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> { - Ok(()) + fn print_type(self, _ty: Ty<'tcx>) -> Result<Self, PrintError> { + Ok(self) } fn print_dyn_existential( self, _predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, - ) -> Result<Self::DynExistential, Self::Error> { - Ok(()) + ) -> Result<Self, PrintError> { + Ok(self) } - fn print_const(self, _ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { - Ok(()) + fn print_const(self, _ct: ty::Const<'tcx>) -> Result<Self, PrintError> { + Ok(self) } - fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { - Ok(vec![self.tcx.crate_name(cnum)]) + fn path_crate(mut self, cnum: CrateNum) -> Result<Self, PrintError> { + self.path = vec![self.tcx.crate_name(cnum)]; + Ok(self) } fn path_qualified( - self, + mut self, self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { if trait_ref.is_none() { if let ty::Adt(def, args) = self_ty.kind() { return self.print_def_path(def.did(), args); @@ -1238,24 +1247,25 @@ impl<'tcx> LateContext<'tcx> { // This shouldn't ever be needed, but just in case: with_no_trimmed_paths!({ - Ok(vec![match trait_ref { + self.path = vec![match trait_ref { Some(trait_ref) => Symbol::intern(&format!("{trait_ref:?}")), None => Symbol::intern(&format!("<{self_ty}>")), - }]) + }]; + Ok(self) }) } fn path_append_impl( self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, _disambiguated_data: &DisambiguatedDefPathData, self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { let mut path = print_prefix(self)?; // This shouldn't ever be needed, but just in case: - path.push(match trait_ref { + path.path.push(match trait_ref { Some(trait_ref) => { with_no_trimmed_paths!(Symbol::intern(&format!( "<impl {} for {}>", @@ -1273,9 +1283,9 @@ impl<'tcx> LateContext<'tcx> { fn path_append( self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, disambiguated_data: &DisambiguatedDefPathData, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { let mut path = print_prefix(self)?; // Skip `::{{extern}}` blocks and `::{{constructor}}` on tuple/unit structs. @@ -1283,20 +1293,23 @@ impl<'tcx> LateContext<'tcx> { return Ok(path); } - path.push(Symbol::intern(&disambiguated_data.data.to_string())); + path.path.push(Symbol::intern(&disambiguated_data.data.to_string())); Ok(path) } fn path_generic_args( self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, _args: &[GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { print_prefix(self) } } - AbsolutePathPrinter { tcx: self.tcx }.print_def_path(def_id, &[]).unwrap() + AbsolutePathPrinter { tcx: self.tcx, path: vec![] } + .print_def_path(def_id, &[]) + .unwrap() + .path } /// Returns the associated type `name` for `self_ty` as an implementation of `trait_id`. @@ -1342,7 +1355,7 @@ impl<'tcx> LateContext<'tcx> { && let Some(init) = match parent_node { hir::Node::Expr(expr) => Some(expr), hir::Node::Local(hir::Local { init, .. }) => *init, - _ => None + _ => None, } { expr = init.peel_blocks(); @@ -1391,9 +1404,9 @@ impl<'tcx> LateContext<'tcx> { hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => { Some(self.tcx.hir().body(body_id).value) } - _ => None - } - _ => None + _ => None, + }, + _ => None, } { expr = init.peel_blocks(); diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs index 9be2edf8453..bc11082d278 100644 --- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -75,14 +75,16 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait { && supertraits(cx.tcx, t_principal.with_self_ty(cx.tcx, cx.tcx.types.trait_object_dummy_self)) .any(|sup| sup.map_bound(|x| ty::ExistentialTraitRef::erase_self_ty(cx.tcx, x)) == target_principal) { - let label = impl_.items.iter().find_map(|i| (i.ident.name == sym::Target).then_some(i.span)).map(|label| SupertraitAsDerefTargetLabel { - label, - }); - cx.emit_spanned_lint(DEREF_INTO_DYN_SUPERTRAIT, cx.tcx.def_span(item.owner_id.def_id), SupertraitAsDerefTarget { - t, - target_principal, - label, - }); + let label = impl_ + .items + .iter() + .find_map(|i| (i.ident.name == sym::Target).then_some(i.span)) + .map(|label| SupertraitAsDerefTargetLabel { label }); + cx.emit_spanned_lint( + DEREF_INTO_DYN_SUPERTRAIT, + cx.tcx.def_span(item.owner_id.def_id), + SupertraitAsDerefTarget { t, target_principal, label }, + ); } } } diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs index 467f53d445c..390a1620a2a 100644 --- a/compiler/rustc_lint/src/drop_forget_useless.rs +++ b/compiler/rustc_lint/src/drop_forget_useless.rs @@ -149,18 +149,37 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless { let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr); match fn_name { sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => { - cx.emit_spanned_lint(DROPPING_REFERENCES, expr.span, DropRefDiag { arg_ty, label: arg.span }); - }, + cx.emit_spanned_lint( + DROPPING_REFERENCES, + expr.span, + DropRefDiag { arg_ty, label: arg.span }, + ); + } sym::mem_forget if arg_ty.is_ref() => { - cx.emit_spanned_lint(FORGETTING_REFERENCES, expr.span, ForgetRefDiag { arg_ty, label: arg.span }); - }, + cx.emit_spanned_lint( + FORGETTING_REFERENCES, + expr.span, + ForgetRefDiag { arg_ty, label: arg.span }, + ); + } sym::mem_drop if is_copy && !drop_is_single_call_in_arm => { - cx.emit_spanned_lint(DROPPING_COPY_TYPES, expr.span, DropCopyDiag { arg_ty, label: arg.span }); + cx.emit_spanned_lint( + DROPPING_COPY_TYPES, + expr.span, + DropCopyDiag { arg_ty, label: arg.span }, + ); } sym::mem_forget if is_copy => { - cx.emit_spanned_lint(FORGETTING_COPY_TYPES, expr.span, ForgetCopyDiag { arg_ty, label: arg.span }); + cx.emit_spanned_lint( + FORGETTING_COPY_TYPES, + expr.span, + ForgetCopyDiag { arg_ty, label: arg.span }, + ); } - sym::mem_drop if let ty::Adt(adt, _) = arg_ty.kind() && adt.is_manually_drop() => { + sym::mem_drop + if let ty::Adt(adt, _) = arg_ty.kind() + && adt.is_manually_drop() => + { cx.emit_spanned_lint( UNDROPPED_MANUALLY_DROPS, expr.span, @@ -169,9 +188,9 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless { label: arg.span, suggestion: UndroppedManuallyDropsSuggestion { start_span: arg.span.shrink_to_lo(), - end_span: arg.span.shrink_to_hi() - } - } + end_span: arg.span.shrink_to_hi(), + }, + }, ); } _ => return, diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index b1266b58a61..740c90757e6 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -11,7 +11,7 @@ pub(crate) fn provide(providers: &mut Providers) { } fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) { - if !tcx.features().enabled(sym::lint_reasons) { + if !tcx.features().active(sym::lint_reasons) { return; } diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index c299e38842a..c8ec0458ba4 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -59,13 +59,20 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles { _ => return, }; - let sub = if let Some(recv) = extract_iterator_next_call(cx, arg) + let sub = if let Some(recv) = extract_iterator_next_call(cx, arg) && let Ok(recv_snip) = cx.sess().source_map().span_to_snippet(recv.span) - { - ForLoopsOverFalliblesLoopSub::RemoveNext { suggestion: recv.span.between(arg.span.shrink_to_hi()), recv_snip } - } else { - ForLoopsOverFalliblesLoopSub::UseWhileLet { start_span: expr.span.with_hi(pat.span.lo()), end_span: pat.span.between(arg.span), var } - } ; + { + ForLoopsOverFalliblesLoopSub::RemoveNext { + suggestion: recv.span.between(arg.span.shrink_to_hi()), + recv_snip, + } + } else { + ForLoopsOverFalliblesLoopSub::UseWhileLet { + start_span: expr.span.with_hi(pat.span.lo()), + end_span: pat.span.between(arg.span), + var, + } + }; let question_mark = suggest_question_mark(cx, adt, args, expr.span) .then(|| ForLoopsOverFalliblesQuestionMark { suggestion: arg.span.shrink_to_hi() }); let suggestion = ForLoopsOverFalliblesSuggestion { @@ -84,13 +91,13 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles { fn extract_for_loop<'tcx>(expr: &Expr<'tcx>) -> Option<(&'tcx Pat<'tcx>, &'tcx Expr<'tcx>)> { if let hir::ExprKind::DropTemps(e) = expr.kind - && let hir::ExprKind::Match(iterexpr, [arm], hir::MatchSource::ForLoopDesugar) = e.kind - && let hir::ExprKind::Call(_, [arg]) = iterexpr.kind - && let hir::ExprKind::Loop(block, ..) = arm.body.kind - && let [stmt] = block.stmts - && let hir::StmtKind::Expr(e) = stmt.kind - && let hir::ExprKind::Match(_, [_, some_arm], _) = e.kind - && let hir::PatKind::Struct(_, [field], _) = some_arm.pat.kind + && let hir::ExprKind::Match(iterexpr, [arm], hir::MatchSource::ForLoopDesugar) = e.kind + && let hir::ExprKind::Call(_, [arg]) = iterexpr.kind + && let hir::ExprKind::Loop(block, ..) = arm.body.kind + && let [stmt] = block.stmts + && let hir::StmtKind::Expr(e) = stmt.kind + && let hir::ExprKind::Match(_, [_, some_arm], _) = e.kind + && let hir::PatKind::Struct(_, [field], _) = some_arm.pat.kind { Some((field.pat, arg)) } else { @@ -104,11 +111,11 @@ fn extract_iterator_next_call<'tcx>( ) -> Option<&'tcx Expr<'tcx>> { // This won't work for `Iterator::next(iter)`, is this an issue? if let hir::ExprKind::MethodCall(_, recv, _, _) = expr.kind - && cx.typeck_results().type_dependent_def_id(expr.hir_id) == cx.tcx.lang_items().next_fn() + && cx.typeck_results().type_dependent_def_id(expr.hir_id) == cx.tcx.lang_items().next_fn() { Some(recv) } else { - return None + return None; } } diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 4b803621f71..2d86129c480 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -3,14 +3,14 @@ use crate::lints::{ BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistentDocKeyword, - QueryInstability, TyQualified, TykindDiag, TykindKind, UntranslatableDiag, + QueryInstability, SpanUseEqCtxtDiag, TyQualified, TykindDiag, TykindKind, UntranslatableDiag, UntranslatableDiagnosticTrivial, }; use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_hir::def::Res; use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath}; -use rustc_hir::{HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind}; +use rustc_hir::{BinOp, BinOpKind, HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::hygiene::{ExpnKind, MacroKind}; @@ -62,13 +62,11 @@ fn typeck_results_of_method_fn<'tcx>( if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => { Some((segment.ident.span, def_id, cx.typeck_results().node_args(expr.hir_id))) - }, - _ => { - match cx.typeck_results().node_type(expr.hir_id).kind() { - &ty::FnDef(def_id, args) => Some((expr.span, def_id, args)), - _ => None, - } } + _ => match cx.typeck_results().node_type(expr.hir_id).kind() { + &ty::FnDef(def_id, args) => Some((expr.span, def_id, args)), + _ => None, + }, } } @@ -134,14 +132,11 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { _: rustc_hir::HirId, ) { if let Some(segment) = path.segments.iter().nth_back(1) - && lint_ty_kind_usage(cx, &segment.res) + && lint_ty_kind_usage(cx, &segment.res) { - let span = path.span.with_hi( - segment.args.map_or(segment.ident.span, |a| a.span_ext).hi() - ); - cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind { - suggestion: span, - }); + let span = + path.span.with_hi(segment.args.map_or(segment.ident.span, |a| a.span_ext).hi()); + cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind { suggestion: span }); } } @@ -166,10 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { None } } - Some(Node::Expr(Expr { - kind: ExprKind::Path(qpath), - .. - })) => { + Some(Node::Expr(Expr { kind: ExprKind::Path(qpath), .. })) => { if let QPath::TypeRelative(qpath_ty, ..) = qpath && qpath_ty.hir_id == ty.hir_id { @@ -180,10 +172,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { } // Can't unify these two branches because qpath below is `&&` and above is `&` // and `A | B` paths don't play well together with adjustments, apparently. - Some(Node::Expr(Expr { - kind: ExprKind::Struct(qpath, ..), - .. - })) => { + Some(Node::Expr(Expr { kind: ExprKind::Struct(qpath, ..), .. })) => { if let QPath::TypeRelative(qpath_ty, ..) = qpath && qpath_ty.hir_id == ty.hir_id { @@ -192,22 +181,28 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { None } } - _ => None + _ => None, }; match span { Some(span) => { - cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind { - suggestion: span, - }); - }, + cx.emit_spanned_lint( + USAGE_OF_TY_TYKIND, + path.span, + TykindKind { suggestion: span }, + ); + } None => cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindDiag), } - } else if !ty.span.from_expansion() && path.segments.len() > 1 && let Some(ty) = is_ty_or_ty_ctxt(cx, &path) { - cx.emit_spanned_lint(USAGE_OF_QUALIFIED_TY, path.span, TyQualified { - ty, - suggestion: path.span, - }); + } else if !ty.span.from_expansion() + && path.segments.len() > 1 + && let Some(ty) = is_ty_or_ty_ctxt(cx, &path) + { + cx.emit_spanned_lint( + USAGE_OF_QUALIFIED_TY, + path.span, + TyQualified { ty, suggestion: path.span }, + ); } } _ => {} @@ -398,11 +393,11 @@ impl LateLintPass<'_> for Diagnostics { } debug!(?parent); - if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent && - let Impl { of_trait: Some(of_trait), .. } = impl_ && - let Some(def_id) = of_trait.trait_def_id() && - let Some(name) = cx.tcx.get_diagnostic_name(def_id) && - matches!(name, sym::IntoDiagnostic | sym::AddToDiagnostic | sym::DecorateLint) + if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent + && let Impl { of_trait: Some(of_trait), .. } = impl_ + && let Some(def_id) = of_trait.trait_def_id() + && let Some(name) = cx.tcx.get_diagnostic_name(def_id) + && matches!(name, sym::IntoDiagnostic | sym::AddToDiagnostic | sym::DecorateLint) { found_impl = true; break; @@ -416,9 +411,9 @@ impl LateLintPass<'_> for Diagnostics { let mut found_diagnostic_message = false; for ty in args.types() { debug!(?ty); - if let Some(adt_def) = ty.ty_adt_def() && - let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did()) && - matches!(name, sym::DiagnosticMessage | sym::SubdiagnosticMessage) + if let Some(adt_def) = ty.ty_adt_def() + && let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did()) + && matches!(name, sym::DiagnosticMessage | sym::SubdiagnosticMessage) { found_diagnostic_message = true; break; @@ -486,8 +481,9 @@ impl EarlyLintPass for Diagnostics { } }; if let ast::ExprKind::Lit(lit) = arg.kind - && let ast::token::LitKind::Str = lit.kind { - true + && let ast::token::LitKind::Str = lit.kind + { + true } else { false } @@ -524,17 +520,50 @@ impl LateLintPass<'_> for BadOptAccess { } for field in adt_def.all_fields() { - if field.name == target.name && - let Some(attr) = cx.tcx.get_attr(field.did, sym::rustc_lint_opt_deny_field_access) && - let Some(items) = attr.meta_item_list() && - let Some(item) = items.first() && - let Some(lit) = item.lit() && - let ast::LitKind::Str(val, _) = lit.kind + if field.name == target.name + && let Some(attr) = + cx.tcx.get_attr(field.did, sym::rustc_lint_opt_deny_field_access) + && let Some(items) = attr.meta_item_list() + && let Some(item) = items.first() + && let Some(lit) = item.lit() + && let ast::LitKind::Str(val, _) = lit.kind { - cx.emit_spanned_lint(BAD_OPT_ACCESS, expr.span, BadOptAccessDiag { - msg: val.as_str(), - }); + cx.emit_spanned_lint( + BAD_OPT_ACCESS, + expr.span, + BadOptAccessDiag { msg: val.as_str() }, + ); } } } } + +declare_tool_lint! { + pub rustc::SPAN_USE_EQ_CTXT, + Allow, + "forbid uses of `==` with `Span::ctxt`, suggest `Span::eq_ctxt` instead", + report_in_external_macro: true +} + +declare_lint_pass!(SpanUseEqCtxt => [SPAN_USE_EQ_CTXT]); + +impl<'tcx> LateLintPass<'tcx> for SpanUseEqCtxt { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { + if let ExprKind::Binary(BinOp { node: BinOpKind::Eq, .. }, lhs, rhs) = expr.kind { + if is_span_ctxt_call(cx, lhs) && is_span_ctxt_call(cx, rhs) { + cx.emit_spanned_lint(SPAN_USE_EQ_CTXT, expr.span, SpanUseEqCtxtDiag); + } + } + } +} + +fn is_span_ctxt_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + match &expr.kind { + ExprKind::MethodCall(..) => cx + .typeck_results() + .type_dependent_def_id(expr.hir_id) + .is_some_and(|call_did| cx.tcx.is_diagnostic_item(sym::SpanCtxt, call_did)), + + _ => false, + } +} diff --git a/compiler/rustc_lint/src/invalid_from_utf8.rs b/compiler/rustc_lint/src/invalid_from_utf8.rs index e398059ade9..0b91b77a9f2 100644 --- a/compiler/rustc_lint/src/invalid_from_utf8.rs +++ b/compiler/rustc_lint/src/invalid_from_utf8.rs @@ -64,8 +64,13 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { && let ExprKind::Path(ref qpath) = path.kind && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id) - && [sym::str_from_utf8, sym::str_from_utf8_mut, - sym::str_from_utf8_unchecked, sym::str_from_utf8_unchecked_mut].contains(&diag_item) + && [ + sym::str_from_utf8, + sym::str_from_utf8_mut, + sym::str_from_utf8_unchecked, + sym::str_from_utf8_unchecked_mut, + ] + .contains(&diag_item) { let lint = |label, utf8_error: Utf8Error| { let method = diag_item.as_str().strip_prefix("str_").unwrap(); @@ -74,13 +79,17 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { let is_unchecked_variant = diag_item.as_str().contains("unchecked"); cx.emit_spanned_lint( - if is_unchecked_variant { INVALID_FROM_UTF8_UNCHECKED } else { INVALID_FROM_UTF8 }, + if is_unchecked_variant { + INVALID_FROM_UTF8_UNCHECKED + } else { + INVALID_FROM_UTF8 + }, expr.span, if is_unchecked_variant { InvalidFromUtf8Diag::Unchecked { method, valid_up_to, label } } else { InvalidFromUtf8Diag::Checked { method, valid_up_to, label } - } + }, ) }; @@ -95,18 +104,19 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 { { lint(init.span, utf8_error); } - }, + } ExprKind::Array(args) => { - let elements = args.iter().map(|e|{ - match &e.kind { + let elements = args + .iter() + .map(|e| match &e.kind { ExprKind::Lit(Spanned { node: lit, .. }) => match lit { LitKind::Byte(b) => Some(*b), LitKind::Int(b, _) => Some(*b as u8), - _ => None - } - _ => None - } - }).collect::<Option<Vec<_>>>(); + _ => None, + }, + _ => None, + }) + .collect::<Option<Vec<_>>>(); if let Some(elements) = elements && let Err(utf8_error) = std::str::from_utf8(&elements) diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index ba521b969ce..0d20f6232db 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -634,7 +634,9 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { /// diagnostic with no change to `specs`. fn insert_spec(&mut self, id: LintId, (mut level, src): LevelAndSource) { let (old_level, old_src) = self.provider.get_lint_level(id.lint, &self.sess); - if let Level::Expect(id) = &mut level && let LintExpectationId::Stable { .. } = id { + if let Level::Expect(id) = &mut level + && let LintExpectationId::Stable { .. } = id + { *id = id.normalize(); } // Setting to a non-forbid level is an error if the lint previously had @@ -706,7 +708,9 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { // The lint `unfulfilled_lint_expectations` can't be expected, as it would suppress itself. // Handling expectations of this lint would add additional complexity with little to no // benefit. The expect level for this lint will therefore be ignored. - if let Level::Expect(_) = level && id == LintId::of(UNFULFILLED_LINT_EXPECTATIONS) { + if let Level::Expect(_) = level + && id == LintId::of(UNFULFILLED_LINT_EXPECTATIONS) + { return; } @@ -747,8 +751,9 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { None => continue, // This is the only lint level with a `LintExpectationId` that can be created from an attribute Some(Level::Expect(unstable_id)) if let Some(hir_id) = source_hir_id => { - let LintExpectationId::Unstable { attr_id, lint_index } = unstable_id - else { bug!("stable id Level::from_attr") }; + let LintExpectationId::Unstable { attr_id, lint_index } = unstable_id else { + bug!("stable id Level::from_attr") + }; let stable_id = LintExpectationId::Stable { hir_id, @@ -1057,7 +1062,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { #[track_caller] fn check_gated_lint(&self, lint_id: LintId, span: Span, lint_from_cli: bool) -> bool { if let Some(feature) = lint_id.lint.feature_gate { - if !self.features.enabled(feature) { + if !self.features.active(feature) { let lint = builtin::UNKNOWN_LINTS; let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS); struct_lint_level( diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index af2132fb899..d61c59af1e0 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -27,6 +27,8 @@ #![allow(rustc::potential_query_instability)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![feature(array_windows)] #![feature(box_patterns)] #![feature(control_flow_enum)] @@ -504,6 +506,11 @@ fn register_builtins(store: &mut LintStore) { "replaced with another group of lints, see RFC \ <https://rust-lang.github.io/rfcs/2145-type-privacy.html> for more information", ); + store.register_removed( + "invalid_alignment", + "converted into hard error, see PR #104616 \ + <https://github.com/rust-lang/rust/pull/104616> for more information", + ); } fn register_internals(store: &mut LintStore) { @@ -524,6 +531,8 @@ fn register_internals(store: &mut LintStore) { store.register_late_mod_pass(|_| Box::new(BadOptAccess)); store.register_lints(&PassByValue::get_lints()); store.register_late_mod_pass(|_| Box::new(PassByValue)); + store.register_lints(&SpanUseEqCtxt::get_lints()); + store.register_late_mod_pass(|_| Box::new(SpanUseEqCtxt)); // FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and // `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and // these lints will trigger all of the time - change this once migration to diagnostic structs @@ -541,6 +550,7 @@ fn register_internals(store: &mut LintStore) { LintId::of(USAGE_OF_QUALIFIED_TY), LintId::of(EXISTING_DOC_KEYWORD), LintId::of(BAD_OPT_ACCESS), + LintId::of(SPAN_USE_EQ_CTXT), ], ); } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index c776d3bb7fe..4eaf8bbf5de 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -412,8 +412,6 @@ pub struct BuiltinIncompleteFeatures { #[note] pub struct BuiltinInternalFeatures { pub name: Symbol, - #[subdiagnostic] - pub note: Option<BuiltinFeatureIssueNote>, } #[derive(Subdiagnostic)] @@ -903,6 +901,10 @@ pub struct QueryInstability { } #[derive(LintDiagnostic)] +#[diag(lint_span_use_eq_ctxt)] +pub struct SpanUseEqCtxtDiag; + +#[derive(LintDiagnostic)] #[diag(lint_tykind_kind)] pub struct TykindKind { #[suggestion(code = "ty", applicability = "maybe-incorrect")] diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index 84558ee1f02..dfefaf82fd7 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -42,18 +42,17 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { if let hir::ItemKind::Trait(_, _, _, _, _) = item.kind && cx.tcx.object_safety_violations(def_id).is_empty() { - let direct_super_traits_iter = cx.tcx - .super_predicates_of(def_id) - .predicates - .into_iter() - .filter_map(|(pred, _)| pred.as_trait_clause()); + let direct_super_traits_iter = cx + .tcx + .super_predicates_of(def_id) + .predicates + .into_iter() + .filter_map(|(pred, _)| pred.as_trait_clause()); if direct_super_traits_iter.count() > 1 { cx.emit_spanned_lint( MULTIPLE_SUPERTRAIT_UPCASTABLE, cx.tcx.def_span(def_id), - crate::lints::MultipleSupertraitUpcastable { - ident: item.ident - }, + crate::lints::MultipleSupertraitUpcastable { ident: item.ident }, ); } } diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 145de494835..66dc726df89 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -511,7 +511,9 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { } fn check_impl_item(&mut self, cx: &LateContext<'_>, ii: &hir::ImplItem<'_>) { - if let hir::ImplItemKind::Const(..) = ii.kind && !assoc_item_in_trait_impl(cx, ii) { + if let hir::ImplItemKind::Const(..) = ii.kind + && !assoc_item_in_trait_impl(cx, ii) + { NonUpperCaseGlobals::check_upper_case(cx, "associated constant", &ii.ident); } } diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs index 0de72d8d3db..4ac8a5ceb85 100644 --- a/compiler/rustc_lint/src/ptr_nulls.rs +++ b/compiler/rustc_lint/src/ptr_nulls.rs @@ -46,22 +46,26 @@ fn incorrect_check<'a, 'tcx: 'a>( if let ExprKind::MethodCall(_, _expr, [], _) = e.kind && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) && cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr) - && let Some(fn_name) = cx.tcx.opt_item_ident(def_id) { + && let Some(fn_name) = cx.tcx.opt_item_ident(def_id) + { return Some(PtrNullChecksDiag::FnRet { fn_name }); } else if let ExprKind::Call(path, _args) = e.kind && let ExprKind::Path(ref qpath) = path.kind && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() && cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr) - && let Some(fn_name) = cx.tcx.opt_item_ident(def_id) { + && let Some(fn_name) = cx.tcx.opt_item_ident(def_id) + { return Some(PtrNullChecksDiag::FnRet { fn_name }); } e = if let ExprKind::Cast(expr, t) = e.kind - && let TyKind::Ptr(_) = t.kind { + && let TyKind::Ptr(_) = t.kind + { had_at_least_one_cast = true; expr } else if let ExprKind::MethodCall(_, expr, [], _) = e.kind && let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) - && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_cast | sym::ptr_cast_mut)) { + && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_cast | sym::ptr_cast_mut)) + { had_at_least_one_cast = true; expr } else if had_at_least_one_cast { @@ -127,10 +131,11 @@ impl<'tcx> LateLintPass<'tcx> for PtrNullChecks { // (fn_ptr as *<const/mut> <ty>) == (0 as <ty>) ExprKind::Cast(cast_expr, _) if let ExprKind::Lit(spanned) = cast_expr.kind - && let LitKind::Int(v, _) = spanned.node && v == 0 => + && let LitKind::Int(v, _) = spanned.node + && v == 0 => { cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag) - }, + } // Catching: // (fn_ptr as *<const/mut> <ty>) == std::ptr::null() @@ -141,9 +146,9 @@ impl<'tcx> LateLintPass<'tcx> for PtrNullChecks { && (diag_item == sym::ptr_null || diag_item == sym::ptr_null_mut) => { cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag) - }, + } - _ => {}, + _ => {} } } _ => {} diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs index 0c52fbaf78c..d44691b5e9b 100644 --- a/compiler/rustc_lint/src/reference_casting.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -93,7 +93,10 @@ fn is_operation_we_care_about<'tcx>( if let ExprKind::Call(path, [arg_ptr, _arg_val]) = e.kind && let ExprKind::Path(ref qpath) = path.kind && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() - && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_write | sym::ptr_write_volatile | sym::ptr_write_unaligned)) + && matches!( + cx.tcx.get_diagnostic_name(def_id), + Some(sym::ptr_write | sym::ptr_write_volatile | sym::ptr_write_unaligned) + ) { Some((true, arg_ptr)) } else { diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 44cf1591c7d..f89b63e6f9f 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -140,13 +140,15 @@ declare_lint! { pub struct TypeLimits { /// Id of the last visited negated expression negated_expr_id: Option<hir::HirId>, + /// Span of the last visited negated expression + negated_expr_span: Option<Span>, } impl_lint_pass!(TypeLimits => [UNUSED_COMPARISONS, OVERFLOWING_LITERALS, INVALID_NAN_COMPARISONS]); impl TypeLimits { pub fn new() -> TypeLimits { - TypeLimits { negated_expr_id: None } + TypeLimits { negated_expr_id: None, negated_expr_span: None } } } @@ -161,8 +163,10 @@ fn lint_overflowing_range_endpoint<'tcx>( ty: &str, ) -> bool { // Look past casts to support cases like `0..256 as u8` - let (expr, lit_span) = if let Node::Expr(par_expr) = cx.tcx.hir().get(cx.tcx.hir().parent_id(expr.hir_id)) - && let ExprKind::Cast(_, _) = par_expr.kind { + let (expr, lit_span) = if let Node::Expr(par_expr) = + cx.tcx.hir().get(cx.tcx.hir().parent_id(expr.hir_id)) + && let ExprKind::Cast(_, _) = par_expr.kind + { (par_expr, expr.span) } else { (expr, expr.span) @@ -426,17 +430,15 @@ fn lint_int_literal<'tcx>( return; } - let lit = cx - .sess() - .source_map() - .span_to_snippet(lit.span) - .expect("must get snippet from literal"); + let span = if negative { type_limits.negated_expr_span.unwrap() } else { e.span }; + let lit = + cx.sess().source_map().span_to_snippet(span).expect("must get snippet from literal"); let help = get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative) .map(|suggestion_ty| OverflowingIntHelp { suggestion_ty }); cx.emit_spanned_lint( OVERFLOWING_LITERALS, - e.span, + span, OverflowingInt { ty: t.name_str(), lit, min, max, help }, ); } @@ -580,8 +582,8 @@ fn lint_nan<'tcx>( ) -> InvalidNanComparisons { // FIXME(#72505): This suggestion can be restored if `f{32,64}::is_nan` is made const. let suggestion = (!cx.tcx.hir().is_inside_const_context(e.hir_id)).then(|| { - if let Some(l_span) = l.span.find_ancestor_inside(e.span) && - let Some(r_span) = r.span.find_ancestor_inside(e.span) + if let Some(l_span) = l.span.find_ancestor_inside(e.span) + && let Some(r_span) = r.span.find_ancestor_inside(e.span) { f(l_span, r_span) } else { @@ -622,9 +624,10 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) { match e.kind { hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => { - // propagate negation, if the negation itself isn't negated + // Propagate negation, if the negation itself isn't negated if self.negated_expr_id != Some(e.hir_id) { self.negated_expr_id = Some(expr.hir_id); + self.negated_expr_span = Some(e.span); } } hir::ExprKind::Binary(binop, ref l, ref r) => { @@ -1292,11 +1295,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { CItemKind::Definition => "fn", }; let span_note = if let ty::Adt(def, _) = ty.kind() - && let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) { - Some(sp) - } else { - None - }; + && let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) + { + Some(sp) + } else { + None + }; self.cx.emit_spanned_lint( lint, sp, @@ -1459,7 +1463,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { type BreakTy = Ty<'tcx>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { - if let ty::FnPtr(sig) = ty.kind() && !self.visitor.is_internal_abi(sig.abi()) { + if let ty::FnPtr(sig) = ty.kind() + && !self.visitor.is_internal_abi(sig.abi()) + { self.tys.push(ty); } @@ -1733,7 +1739,8 @@ impl InvalidAtomicOrdering { } fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) { - if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store]) + if let Some((method, args)) = + Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store]) && let Some((ordering_arg, invalid_ordering)) = match method { sym::load => Some((&args[0], sym::Release)), sym::store => Some((&args[1], sym::Acquire)), @@ -1743,9 +1750,17 @@ impl InvalidAtomicOrdering { && (ordering == invalid_ordering || ordering == sym::AcqRel) { if method == sym::load { - cx.emit_spanned_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, AtomicOrderingLoad); + cx.emit_spanned_lint( + INVALID_ATOMIC_ORDERING, + ordering_arg.span, + AtomicOrderingLoad, + ); } else { - cx.emit_spanned_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, AtomicOrderingStore); + cx.emit_spanned_lint( + INVALID_ATOMIC_ORDERING, + ordering_arg.span, + AtomicOrderingStore, + ); }; } } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index d5beff4f101..65de7e10272 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -353,7 +353,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ty::Generator(def_id, ..) => { // async fn should be treated as "implementor of `Future`" let must_use = if cx.tcx.generator_is_async(def_id) { - let def_id = cx.tcx.lang_items().future_trait().unwrap(); + let def_id = cx.tcx.lang_items().future_trait()?; is_def_must_use(cx, def_id, span) .map(|inner| MustUsePath::Opaque(Box::new(inner))) } else { @@ -782,21 +782,23 @@ trait UnusedDelimLint { }; let suggestion = spans.map(|(lo, hi)| { let sm = cx.sess().source_map(); - let lo_replace = - if (keep_space.0 || is_kw) && - let Ok(snip) = sm.span_to_prev_source(lo) && !snip.ends_with(' ') { - " " - } else { - "" - }; + let lo_replace = if (keep_space.0 || is_kw) + && let Ok(snip) = sm.span_to_prev_source(lo) + && !snip.ends_with(' ') + { + " " + } else { + "" + }; - let hi_replace = - if keep_space.1 && - let Ok(snip) = sm.span_to_next_source(hi) && !snip.starts_with(' ') { - " " - } else { - "" - }; + let hi_replace = if keep_space.1 + && let Ok(snip) = sm.span_to_next_source(hi) + && !snip.starts_with(' ') + { + " " + } else { + "" + }; UnusedDelimSuggestion { start_span: lo, start_replace: lo_replace, @@ -1056,10 +1058,10 @@ impl UnusedParens { impl EarlyLintPass for UnusedParens { #[inline] fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { - if let ExprKind::Binary(op, lhs, _rhs) = &e.kind && - (op.node == ast::BinOpKind::Lt || op.node == ast::BinOpKind::Shl) && - let ExprKind::Cast(_expr, ty) = &lhs.kind && - let ast::TyKind::Paren(_) = &ty.kind + if let ExprKind::Binary(op, lhs, _rhs) = &e.kind + && (op.node == ast::BinOpKind::Lt || op.node == ast::BinOpKind::Shl) + && let ExprKind::Cast(_expr, ty) = &lhs.kind + && let ast::TyKind::Paren(_) = &ty.kind { self.parens_in_cast_in_lt.push(ty.id); } @@ -1111,13 +1113,19 @@ impl EarlyLintPass for UnusedParens { } fn check_expr_post(&mut self, _cx: &EarlyContext<'_>, e: &ast::Expr) { - if let ExprKind::Binary(op, lhs, _rhs) = &e.kind && - (op.node == ast::BinOpKind::Lt || op.node == ast::BinOpKind::Shl) && - let ExprKind::Cast(_expr, ty) = &lhs.kind && - let ast::TyKind::Paren(_) = &ty.kind + if let ExprKind::Binary(op, lhs, _rhs) = &e.kind + && (op.node == ast::BinOpKind::Lt || op.node == ast::BinOpKind::Shl) + && let ExprKind::Cast(_expr, ty) = &lhs.kind + && let ast::TyKind::Paren(_) = &ty.kind { - let id = self.parens_in_cast_in_lt.pop().expect("check_expr and check_expr_post must balance"); - assert_eq!(id, ty.id, "check_expr, check_ty, and check_expr_post are called, in that order, by the visitor"); + let id = self + .parens_in_cast_in_lt + .pop() + .expect("check_expr and check_expr_post must balance"); + assert_eq!( + id, ty.id, + "check_expr, check_ty, and check_expr_post are called, in that order, by the visitor" + ); } } @@ -1161,8 +1169,8 @@ impl EarlyLintPass for UnusedParens { } fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) { - if let ast::TyKind::Paren(_) = ty.kind && - Some(&ty.id) == self.parens_in_cast_in_lt.last() + if let ast::TyKind::Paren(_) = ty.kind + && Some(&ty.id) == self.parens_in_cast_in_lt.last() { return; } @@ -1206,13 +1214,14 @@ impl EarlyLintPass for UnusedParens { fn enter_where_predicate(&mut self, _: &EarlyContext<'_>, pred: &ast::WherePredicate) { use rustc_ast::{WhereBoundPredicate, WherePredicate}; if let WherePredicate::BoundPredicate(WhereBoundPredicate { - bounded_ty, - bound_generic_params, - .. - }) = pred && - let ast::TyKind::Paren(_) = &bounded_ty.kind && - bound_generic_params.is_empty() { - self.with_self_ty_parens = true; + bounded_ty, + bound_generic_params, + .. + }) = pred + && let ast::TyKind::Paren(_) = &bounded_ty.kind + && bound_generic_params.is_empty() + { + self.with_self_ty_parens = true; } } @@ -1516,9 +1525,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAllocation { match e.kind { hir::ExprKind::Call(path_expr, [_]) if let hir::ExprKind::Path(qpath) = &path_expr.kind - && let Some(did) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id() - && cx.tcx.is_diagnostic_item(sym::box_new, did) - => {} + && let Some(did) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id() + && cx.tcx.is_diagnostic_item(sym::box_new, did) => {} _ => return, } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 69b462d32bd..c8d42937f7b 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -987,45 +987,6 @@ declare_lint! { } declare_lint! { - /// The `invalid_alignment` lint detects dereferences of misaligned pointers during - /// constant evaluation. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #![feature(const_mut_refs)] - /// const FOO: () = unsafe { - /// let x = &[0_u8; 4]; - /// let y = x.as_ptr().cast::<u32>(); - /// let mut z = 123; - /// y.copy_to_nonoverlapping(&mut z, 1); // the address of a `u8` array is unknown - /// // and thus we don't know if it is aligned enough for copying a `u32`. - /// }; - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// The compiler allowed dereferencing raw pointers irrespective of alignment - /// during const eval due to the const evaluator at the time not making it easy - /// or cheap to check. Now that it is both, this is not accepted anymore. - /// - /// Since it was undefined behaviour to begin with, this breakage does not violate - /// Rust's stability guarantees. Using undefined behaviour can cause arbitrary - /// behaviour, including failure to build. - /// - /// [future-incompatible]: ../index.md#future-incompatible-lints - pub INVALID_ALIGNMENT, - Deny, - "raw pointers must be aligned before dereferencing", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, - reference: "issue #68585 <https://github.com/rust-lang/rust/issues/104616>", - }; -} - -declare_lint! { /// The `exported_private_dependencies` lint detects private dependencies /// that are exposed in a public interface. /// @@ -3430,7 +3391,6 @@ declare_lint_pass! { INDIRECT_STRUCTURAL_MATCH, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, INLINE_NO_SANITIZE, - INVALID_ALIGNMENT, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, INVALID_TYPE_PARAM_DEFAULT, @@ -4489,11 +4449,11 @@ declare_lint! { /// on itself), the blanket impl is not considered to hold for `u8`. This will /// change in a future release. pub COINDUCTIVE_OVERLAP_IN_COHERENCE, - Warn, + Deny, "impls that are not considered to overlap may be considered to \ overlap in the future", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, reference: "issue #114040 <https://github.com/rust-lang/rust/issues/114040>", }; } @@ -4574,7 +4534,6 @@ declare_lint! { /// ### Example /// /// ```rust,compile_fail - /// #![feature(return_position_impl_trait_in_trait)] /// #![deny(refining_impl_trait)] /// /// use std::fmt::Display; diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index eb70961503d..518c20c9fa8 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -1,6 +1,9 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), allow(internal_features))] // NOTE: This crate only exists to allow linking on mingw targets. diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs index 3e43bcb3b8f..0c9ec556549 100644 --- a/compiler/rustc_log/src/lib.rs +++ b/compiler/rustc_log/src/lib.rs @@ -74,6 +74,11 @@ pub fn init_env_logger(env: &str) -> Result<(), Error> { Some(v) => &v != "0", }; + let verbose_thread_ids = match env::var_os(String::from(env) + "_THREAD_IDS") { + None => false, + Some(v) => &v == "1", + }; + let layer = tracing_tree::HierarchicalLayer::default() .with_writer(io::stderr) .with_indent_lines(true) @@ -81,9 +86,9 @@ pub fn init_env_logger(env: &str) -> Result<(), Error> { .with_targets(true) .with_verbose_exit(verbose_entry_exit) .with_verbose_entry(verbose_entry_exit) - .with_indent_amount(2); - #[cfg(all(parallel_compiler, debug_assertions))] - let layer = layer.with_thread_ids(true).with_thread_names(true); + .with_indent_amount(2) + .with_thread_ids(verbose_thread_ids) + .with_thread_names(verbose_thread_ids); let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer); match env::var(format!("{env}_BACKTRACE")) { diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index 04b7c5feebe..1a8174bfd96 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -42,19 +42,20 @@ impl<'a> DiagnosticDerive<'a> { let init = match builder.slug.value_ref() { None => { span_err(builder.span, "diagnostic slug not specified") - .help("specify the slug as the first argument to the `#[diag(...)]` \ - attribute, such as `#[diag(hir_analysis_example_error)]`") + .help( + "specify the slug as the first argument to the `#[diag(...)]` \ + attribute, such as `#[diag(hir_analysis_example_error)]`", + ) .emit(); return DiagnosticDeriveError::ErrorHandled.to_compile_error(); } - Some(slug) if let Some( Mismatch { slug_name, crate_name, slug_prefix }) = Mismatch::check(slug) => { + Some(slug) + if let Some(Mismatch { slug_name, crate_name, slug_prefix }) = + Mismatch::check(slug) => + { span_err(slug.span().unwrap(), "diagnostic slug and crate name do not match") - .note(format!( - "slug is `{slug_name}` but the crate name is `{crate_name}`" - )) - .help(format!( - "expected a slug starting with `{slug_prefix}_...`" - )) + .note(format!("slug is `{slug_name}` but the crate name is `{crate_name}`")) + .help(format!("expected a slug starting with `{slug_prefix}_...`")) .emit(); return DiagnosticDeriveError::ErrorHandled.to_compile_error(); } @@ -141,19 +142,20 @@ impl<'a> LintDiagnosticDerive<'a> { match builder.slug.value_ref() { None => { span_err(builder.span, "diagnostic slug not specified") - .help("specify the slug as the first argument to the attribute, such as \ - `#[diag(compiletest_example)]`") + .help( + "specify the slug as the first argument to the attribute, such as \ + `#[diag(compiletest_example)]`", + ) .emit(); DiagnosticDeriveError::ErrorHandled.to_compile_error() } - Some(slug) if let Some( Mismatch { slug_name, crate_name, slug_prefix }) = Mismatch::check(slug) => { + Some(slug) + if let Some(Mismatch { slug_name, crate_name, slug_prefix }) = + Mismatch::check(slug) => + { span_err(slug.span().unwrap(), "diagnostic slug and crate name do not match") - .note(format!( - "slug is `{slug_name}` but the crate name is `{crate_name}`" - )) - .help(format!( - "expected a slug starting with `{slug_prefix}_...`" - )) + .note(format!("slug is `{slug_name}` but the crate name is `{crate_name}`")) + .help(format!("expected a slug starting with `{slug_prefix}_...`")) .emit(); DiagnosticDeriveError::ErrorHandled.to_compile_error() } diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 877e9745054..877271ff077 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -577,7 +577,9 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { } } _ => { - if let Some(span) = span_field && !no_span { + if let Some(span) = span_field + && !no_span + { quote! { #diag.#name(#span, #message); } } else { quote! { #diag.#name(#message); } diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index 783d35ac7e6..cb057cd39e2 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -396,11 +396,14 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { continue; } - if let Some(found_strategy) = tcx.required_panic_strategy(cnum) && desired_strategy != found_strategy { + if let Some(found_strategy) = tcx.required_panic_strategy(cnum) + && desired_strategy != found_strategy + { sess.emit_err(RequiredPanicStrategy { crate_name: tcx.crate_name(cnum), found_strategy, - desired_strategy}); + desired_strategy, + }); } let found_drop_strategy = tcx.panic_in_drop_strategy(cnum); diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 91220629fb6..59b35a6406d 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -419,7 +419,9 @@ impl<'a> MissingNativeLibrary<'a> { // if it looks like the user has provided a complete filename rather just the bare lib name, // then provide a note that they might want to try trimming the name let suggested_name = if !verbatim { - if let Some(libname) = libname.strip_prefix("lib") && let Some(libname) = libname.strip_suffix(".a") { + if let Some(libname) = libname.strip_prefix("lib") + && let Some(libname) = libname.strip_suffix(".a") + { // this is a unix style filename so trim prefix & suffix Some(libname) } else if let Some(libname) = libname.strip_suffix(".lib") { diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index fa77b36c4c5..ddeb39669dc 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -1,4 +1,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), allow(internal_features))] #![feature(decl_macro)] #![feature(extract_if)] #![feature(generators)] diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 098c411c8d6..ab135851b8e 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -383,7 +383,9 @@ impl<'tcx> Collector<'tcx> { // First, check for errors let mut renames = FxHashSet::default(); for lib in &self.tcx.sess.opts.libs { - if let NativeLibKind::Framework { .. } = lib.kind && !self.tcx.sess.target.is_like_osx { + if let NativeLibKind::Framework { .. } = lib.kind + && !self.tcx.sess.target.is_like_osx + { // Cannot check this when parsing options because the target is not yet available. self.tcx.sess.emit_err(errors::LibFrameworkApple); } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index b189e79df56..d6ceaa8a091 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1273,6 +1273,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.root.tables.optimized_mir.get(self, id).is_some() } + fn cross_crate_inlinable(self, id: DefIndex) -> bool { + self.root.tables.cross_crate_inlinable.get(self, id).unwrap_or(false) + } + fn get_fn_has_self_parameter(self, id: DefIndex, sess: &'a Session) -> bool { self.root .tables @@ -1692,17 +1696,22 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { // `try_to_translate_virtual_to_real` don't have to worry about how the // compiler is bootstrapped. if let Some(virtual_dir) = &sess.opts.unstable_opts.simulate_remapped_rust_src_base - && let Some(real_dir) = &sess.opts.real_rust_source_base_dir - && let rustc_span::FileName::Real(ref mut old_name) = name { + && let Some(real_dir) = &sess.opts.real_rust_source_base_dir + && let rustc_span::FileName::Real(ref mut old_name) = name + { let relative_path = match old_name { - rustc_span::RealFileName::LocalPath(local) => local.strip_prefix(real_dir).ok(), + rustc_span::RealFileName::LocalPath(local) => { + local.strip_prefix(real_dir).ok() + } rustc_span::RealFileName::Remapped { virtual_name, .. } => { - option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").and_then(|virtual_dir| virtual_name.strip_prefix(virtual_dir).ok()) + option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR") + .and_then(|virtual_dir| virtual_name.strip_prefix(virtual_dir).ok()) } }; debug!(?relative_path, ?virtual_dir, "simulate_remapped_rust_src_base"); for subdir in ["library", "compiler"] { - if let Some(rest) = relative_path.and_then(|p| p.strip_prefix(subdir).ok()) { + if let Some(rest) = relative_path.and_then(|p| p.strip_prefix(subdir).ok()) + { *old_name = rustc_span::RealFileName::Remapped { local_path: None, // FIXME: maybe we should preserve this? virtual_name: virtual_dir.join(subdir).join(rest), diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index f27eee0d79a..6b6c0d52742 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -287,6 +287,7 @@ provide! { tcx, def_id, other, cdata, item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) } is_mir_available => { cdata.is_item_mir_available(def_id.index) } is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) } + cross_crate_inlinable => { cdata.cross_crate_inlinable(def_id.index) } dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) } is_private_dep => { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a4ba943275e..7c406f9bdda 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1046,7 +1046,7 @@ fn should_encode_mir( || (tcx.sess.opts.output_types.should_codegen() && reachable_set.contains(&def_id) && (generics.requires_monomorphization(tcx) - || tcx.codegen_fn_attrs(def_id).requests_inline())); + || tcx.cross_crate_inlinable(def_id))); // The function has a `const` modifier or is in a `#[const_trait]`. let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id()) || tcx.is_const_default_method(def_id.to_def_id()); @@ -1155,7 +1155,8 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> DefKind::OpaqueTy => { let origin = tcx.opaque_type_origin(def_id); - if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin + if let hir::OpaqueTyOrigin::FnReturn(fn_def_id) + | hir::OpaqueTyOrigin::AsyncFn(fn_def_id) = origin && let hir::Node::TraitItem(trait_item) = tcx.hir().get_by_def_id(fn_def_id) && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() { @@ -1357,7 +1358,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if should_encode_expn_that_defined(def_kind) { record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id)); } - if should_encode_span(def_kind) && let Some(ident_span) = tcx.def_ident_span(def_id) { + if should_encode_span(def_kind) + && let Some(ident_span) = tcx.def_ident_span(def_id) + { record!(self.tables.def_ident_span[def_id] <- ident_span); } if def_kind.has_codegen_attrs() { @@ -1612,6 +1615,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { debug!("EntryBuilder::encode_mir({:?})", def_id); if encode_opt { record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id)); + self.tables + .cross_crate_inlinable + .set(def_id.to_def_id().index, Some(self.tcx.cross_crate_inlinable(def_id))); record!(self.tables.closure_saved_names_of_captured_variables[def_id.to_def_id()] <- tcx.closure_saved_names_of_captured_variables(def_id)); @@ -1958,8 +1964,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.impl_trait_ref[def_id] <- trait_ref); let trait_ref = trait_ref.instantiate_identity(); - let simplified_self_ty = - fast_reject::simplify_type(self.tcx, trait_ref.self_ty(), TreatParams::AsCandidateKey); + let simplified_self_ty = fast_reject::simplify_type( + self.tcx, + trait_ref.self_ty(), + TreatParams::AsCandidateKey, + ); fx_hash_map .entry(trait_ref.def_id) .or_default() @@ -2372,8 +2381,9 @@ pub fn rendered_const<'tcx>(tcx: TyCtxt<'tcx>, body: hir::BodyId) -> String { let classification = classify(value); if classification == Literal - && !value.span.from_expansion() - && let Ok(snippet) = tcx.sess.source_map().span_to_snippet(value.span) { + && !value.span.from_expansion() + && let Ok(snippet) = tcx.sess.source_map().span_to_snippet(value.span) + { // For literals, we avoid invoking the pretty-printer and use the source snippet instead to // preserve certain stylistic choices the user likely made for the sake legibility like // diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 42764af52c4..2609767a85c 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -427,6 +427,7 @@ define_tables! { object_lifetime_default: Table<DefIndex, LazyValue<ObjectLifetimeDefault>>, optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>, mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>, + cross_crate_inlinable: Table<DefIndex, bool>, closure_saved_names_of_captured_variables: Table<DefIndex, LazyValue<IndexVec<FieldIdx, Symbol>>>, mir_generator_witnesses: Table<DefIndex, LazyValue<mir::GeneratorLayout<'static>>>, promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'static>>>>, diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index bb1320942b0..34118e9e8a3 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -299,6 +299,30 @@ impl FixedSizeEncoding for bool { } } +impl FixedSizeEncoding for Option<bool> { + type ByteArray = [u8; 1]; + + #[inline] + fn from_bytes(b: &[u8; 1]) -> Self { + match b[0] { + 0 => Some(false), + 1 => Some(true), + 2 => None, + _ => unreachable!(), + } + } + + #[inline] + fn write_to_bytes(self, b: &mut [u8; 1]) { + debug_assert!(!self.is_default()); + b[0] = match self { + Some(false) => 0, + Some(true) => 1, + None => 2, + }; + } +} + impl FixedSizeEncoding for UnusedGenericParams { type ByteArray = [u8; 4]; diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 41beca072bf..c8f3c2a20a6 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -104,7 +104,7 @@ impl CanonicalVarValues<'_> { } else { // It's ok if this region var isn't unique } - }, + } ty::GenericArgKind::Type(ty) => { if let ty::Bound(ty::INNERMOST, bt) = *ty.kind() && var == bt.var diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index fe4fc3761b3..dee18dc1162 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -23,6 +23,8 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![feature(allocator_api)] #![feature(array_windows)] #![feature(assert_matches)] diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 4e5725876c4..f758c1d5e6f 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -126,14 +126,6 @@ impl CodegenFnAttrs { } } - /// Returns `true` if `#[inline]` or `#[inline(always)]` is present. - pub fn requests_inline(&self) -> bool { - match self.inline { - InlineAttr::Hint | InlineAttr::Always => true, - InlineAttr::None | InlineAttr::Never => false, - } - } - /// Returns `true` if it looks like this symbol needs to be exported, for example: /// /// * `#[no_mangle]` is present diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 1913421f54c..500536a9e9e 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -244,7 +244,9 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> { if !(inherited_effective_vis_at_prev_level == inherited_effective_vis_at_level && level != l) { - calculated_effective_vis = if let Some(max_vis) = max_vis && !max_vis.is_at_least(inherited_effective_vis_at_level, tcx) { + calculated_effective_vis = if let Some(max_vis) = max_vis + && !max_vis.is_at_least(inherited_effective_vis_at_level, tcx) + { max_vis } else { inherited_effective_vis_at_level diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index c66f64dde32..84893b8e627 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -455,7 +455,9 @@ impl<'tcx> TyCtxt<'tcx> { // If this item was previously part of a now-stabilized feature which is still // active (i.e. the user hasn't removed the attribute for the stabilized feature // yet) then allow use of this item. - if let Some(implied_by) = implied_by && self.features().declared(implied_by) { + if let Some(implied_by) = implied_by + && self.features().declared(implied_by) + { return EvalResult::Allow; } diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index a6d6f6f5df4..08d377a8695 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -1,5 +1,6 @@ //! Metadata from source code coverage analysis and instrumentation. +use rustc_index::IndexVec; use rustc_macros::HashStable; use rustc_span::Symbol; @@ -8,6 +9,11 @@ use std::fmt::{self, Debug, Formatter}; rustc_index::newtype_index! { /// ID of a coverage counter. Values ascend from 0. /// + /// Before MIR inlining, counter IDs are local to their enclosing function. + /// After MIR inlining, coverage statements may have been inlined into + /// another function, so use the statement's source-scope to find which + /// function/instance its IDs are meaningful for. + /// /// Note that LLVM handles counter IDs as `uint32_t`, so there is no need /// to use a larger representation on the Rust side. #[derive(HashStable)] @@ -23,6 +29,11 @@ impl CounterId { rustc_index::newtype_index! { /// ID of a coverage-counter expression. Values ascend from 0. /// + /// Before MIR inlining, expression IDs are local to their enclosing function. + /// After MIR inlining, coverage statements may have been inlined into + /// another function, so use the statement's source-scope to find which + /// function/instance its IDs are meaningful for. + /// /// Note that LLVM handles expression IDs as `uint32_t`, so there is no need /// to use a larger representation on the Rust side. #[derive(HashStable)] @@ -35,19 +46,21 @@ impl ExpressionId { pub const START: Self = Self::from_u32(0); } -/// Operand of a coverage-counter expression. +/// Enum that can hold a constant zero value, the ID of an physical coverage +/// counter, or the ID of a coverage-counter expression. /// -/// Operands can be a constant zero value, an actual coverage counter, or another -/// expression. Counter/expression operands are referred to by ID. +/// This was originally only used for expression operands (and named `Operand`), +/// but the zero/counter/expression distinction is also useful for representing +/// the value of code/gap mappings, and the true/false arms of branch mappings. #[derive(Copy, Clone, PartialEq, Eq)] #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] -pub enum Operand { +pub enum CovTerm { Zero, Counter(CounterId), Expression(ExpressionId), } -impl Debug for Operand { +impl Debug for CovTerm { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Self::Zero => write!(f, "Zero"), @@ -59,40 +72,31 @@ impl Debug for Operand { #[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] pub enum CoverageKind { - Counter { - function_source_hash: u64, - /// ID of this counter within its enclosing function. - /// Expressions in the same function can refer to it as an operand. - id: CounterId, - }, - Expression { - /// ID of this coverage-counter expression within its enclosing function. - /// Other expressions in the same function can refer to it as an operand. - id: ExpressionId, - lhs: Operand, - op: Op, - rhs: Operand, - }, - Unreachable, + /// Marks the point in MIR control flow represented by a coverage counter. + /// + /// This is eventually lowered to `llvm.instrprof.increment` in LLVM IR. + /// + /// If this statement does not survive MIR optimizations, any mappings that + /// refer to this counter can have those references simplified to zero. + CounterIncrement { id: CounterId }, + + /// Marks the point in MIR control-flow represented by a coverage expression. + /// + /// If this statement does not survive MIR optimizations, any mappings that + /// refer to this expression can have those references simplified to zero. + /// + /// (This is only inserted for expression IDs that are directly used by + /// mappings. Intermediate expressions with no direct mappings are + /// retained/zeroed based on whether they are transitively used.) + ExpressionUsed { id: ExpressionId }, } impl Debug for CoverageKind { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { use CoverageKind::*; match self { - Counter { id, .. } => write!(fmt, "Counter({:?})", id.index()), - Expression { id, lhs, op, rhs } => write!( - fmt, - "Expression({:?}) = {:?} {} {:?}", - id.index(), - lhs, - match op { - Op::Add => "+", - Op::Subtract => "-", - }, - rhs, - ), - Unreachable => write!(fmt, "Unreachable"), + CounterIncrement { id } => write!(fmt, "CounterIncrement({:?})", id.index()), + ExpressionUsed { id } => write!(fmt, "ExpressionUsed({:?})", id.index()), } } } @@ -133,3 +137,38 @@ impl Op { matches!(self, Self::Subtract) } } + +#[derive(Clone, Debug)] +#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] +pub struct Expression { + pub lhs: CovTerm, + pub op: Op, + pub rhs: CovTerm, +} + +#[derive(Clone, Debug)] +#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] +pub struct Mapping { + pub code_region: CodeRegion, + + /// Indicates whether this mapping uses a counter value, expression value, + /// or zero value. + /// + /// FIXME: When we add support for mapping kinds other than `Code` + /// (e.g. branch regions, expansion regions), replace this with a dedicated + /// mapping-kind enum. + pub term: CovTerm, +} + +/// Stores per-function coverage information attached to a `mir::Body`, +/// to be used in conjunction with the individual coverage statements injected +/// into the function's basic blocks. +#[derive(Clone, Debug)] +#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] +pub struct FunctionCoverageInfo { + pub function_source_hash: u64, + pub num_counters: usize, + + pub expressions: IndexVec<ExpressionId, Expression>, + pub mappings: Vec<Mapping>, +} diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index c787481bfbe..aded3e495d9 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -32,23 +32,16 @@ pub use init_mask::{InitChunk, InitChunkIter}; pub trait AllocBytes: Clone + fmt::Debug + Eq + PartialEq + Hash + Deref<Target = [u8]> + DerefMut<Target = [u8]> { - /// Adjust the bytes to the specified alignment -- by default, this is a no-op. - fn adjust_to_align(self, _align: Align) -> Self; - /// Create an `AllocBytes` from a slice of `u8`. fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, _align: Align) -> Self; - /// Create a zeroed `AllocBytes` of the specified size and alignment; - /// call the callback error handler if there is an error in allocating the memory. + /// Create a zeroed `AllocBytes` of the specified size and alignment. + /// Returns `None` if we ran out of memory on the host. fn zeroed(size: Size, _align: Align) -> Option<Self>; } // Default `bytes` for `Allocation` is a `Box<[u8]>`. impl AllocBytes for Box<[u8]> { - fn adjust_to_align(self, _align: Align) -> Self { - self - } - fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, _align: Align) -> Self { Box::<[u8]>::from(slice.into()) } @@ -299,6 +292,7 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> { } fn uninit_inner<R>(size: Size, align: Align, fail: impl FnOnce() -> R) -> Result<Self, R> { + // We raise an error if we cannot create the allocation on the host. // This results in an error that can happen non-deterministically, since the memory // available to the compiler can change between runs. Normally queries are always // deterministic. However, we can be non-deterministic here because all uses of const @@ -351,10 +345,8 @@ impl<Bytes: AllocBytes> Allocation<AllocId, (), Bytes> { extra: Extra, mut adjust_ptr: impl FnMut(Pointer<AllocId>) -> Result<Pointer<Prov>, Err>, ) -> Result<Allocation<Prov, Extra, Bytes>, Err> { - // Compute new pointer provenance, which also adjusts the bytes, and realign the pointer if - // necessary. - let mut bytes = self.bytes.adjust_to_align(self.align); - + let mut bytes = self.bytes; + // Adjust provenance of pointers stored in this allocation. let mut new_provenance = Vec::with_capacity(self.provenance.ptrs().len()); let ptr_size = cx.data_layout().pointer_size.bytes_usize(); let endian = cx.data_layout().endian; diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs index 0243fc4513a..d504af6b7ea 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -315,7 +315,9 @@ impl<Prov: Provenance> ProvenanceMap<Prov> { self.ptrs.insert_presorted(dest_ptrs.into()); } if Prov::OFFSET_IS_ADDR { - if let Some(dest_bytes) = copy.dest_bytes && !dest_bytes.is_empty() { + if let Some(dest_bytes) = copy.dest_bytes + && !dest_bytes.is_empty() + { self.bytes.get_or_insert_with(Box::default).insert_presorted(dest_bytes.into()); } } else { diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 9de40b3f974..44b22e2d383 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -216,10 +216,8 @@ pub enum InvalidProgramInfo<'tcx> { } /// Details of why a pointer had to be in-bounds. -#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)] +#[derive(Debug, Copy, Clone)] pub enum CheckInAllocMsg { - /// We are dereferencing a pointer (i.e., creating a place). - DerefTest, /// We are access memory. MemoryAccessTest, /// We are doing pointer arithmetic. @@ -230,7 +228,16 @@ pub enum CheckInAllocMsg { InboundsTest, } -#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)] +/// Details of which pointer is not aligned. +#[derive(Debug, Copy, Clone)] +pub enum CheckAlignMsg { + /// The accessed pointer did not have proper alignment. + AccessedPtr, + /// The access ocurred with a place that was based on a misaligned pointer. + BasedOn, +} + +#[derive(Debug, Copy, Clone)] pub enum InvalidMetaKind { /// Size of a `[T]` is too big SliceTooBig, @@ -263,6 +270,13 @@ pub struct ScalarSizeMismatch { pub data_size: u64, } +/// Information about a misaligned pointer. +#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] +pub struct Misalignment { + pub has: Align, + pub required: Align, +} + macro_rules! impl_into_diagnostic_arg_through_debug { ($($ty:ty),*$(,)?) => {$( impl IntoDiagnosticArg for $ty { @@ -324,7 +338,7 @@ pub enum UndefinedBehaviorInfo<'tcx> { /// Using an integer as a pointer in the wrong way. DanglingIntPointer(u64, CheckInAllocMsg), /// Used a pointer with bad alignment. - AlignmentCheckFailed { required: Align, has: Align }, + AlignmentCheckFailed(Misalignment, CheckAlignMsg), /// Writing to read-only memory. WriteToReadOnly(AllocId), /// Trying to access the data behind a function pointer. diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index d21f82f04f6..e360fb3eaaf 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -142,11 +142,12 @@ use crate::ty::GenericArgKind; use crate::ty::{self, Instance, Ty, TyCtxt}; pub use self::error::{ - struct_error, BadBytesAccess, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, - EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, InterpError, InterpErrorInfo, - InterpResult, InvalidMetaKind, InvalidProgramInfo, MachineStopType, PointerKind, - ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, - UnsupportedOpInfo, ValidationErrorInfo, ValidationErrorKind, + struct_error, BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, + EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, + InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind, InvalidProgramInfo, + MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo, + ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, + ValidationErrorKind, }; pub use self::value::Scalar; diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index f979f736b15..3a5ff4dc91f 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -345,6 +345,14 @@ pub struct Body<'tcx> { pub injection_phase: Option<MirPhase>, pub tainted_by_errors: Option<ErrorGuaranteed>, + + /// Per-function coverage information added by the `InstrumentCoverage` + /// pass, to be used in conjunction with the coverage statements injected + /// into this body's blocks. + /// + /// If `-Cinstrument-coverage` is not active, or if an individual function + /// is not eligible for coverage, then this should always be `None`. + pub function_coverage_info: Option<Box<coverage::FunctionCoverageInfo>>, } impl<'tcx> Body<'tcx> { @@ -392,6 +400,7 @@ impl<'tcx> Body<'tcx> { is_polymorphic: false, injection_phase: None, tainted_by_errors, + function_coverage_info: None, }; body.is_polymorphic = body.has_non_region_param(); body @@ -420,6 +429,7 @@ impl<'tcx> Body<'tcx> { is_polymorphic: false, injection_phase: None, tainted_by_errors: None, + function_coverage_info: None, }; body.is_polymorphic = body.has_non_region_param(); body diff --git a/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs index ce2ddec0116..eb4aa9eb95c 100644 --- a/compiler/rustc_middle/src/mir/patch.rs +++ b/compiler/rustc_middle/src/mir/patch.rs @@ -99,7 +99,9 @@ impl<'tcx> MirPatch<'tcx> { } pub fn terminate_block(&mut self, reason: UnwindTerminateReason) -> BasicBlock { - if let Some((cached_bb, cached_reason)) = self.terminate_block && reason == cached_reason { + if let Some((cached_bb, cached_reason)) = self.terminate_block + && reason == cached_reason + { return cached_bb; } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index c5e3ee575e1..3b3b61e4e21 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -493,6 +493,27 @@ pub fn write_mir_intro<'tcx>( // Add an empty line before the first block is printed. writeln!(w)?; + if let Some(function_coverage_info) = &body.function_coverage_info { + write_function_coverage_info(function_coverage_info, w)?; + } + + Ok(()) +} + +fn write_function_coverage_info( + function_coverage_info: &coverage::FunctionCoverageInfo, + w: &mut dyn io::Write, +) -> io::Result<()> { + let coverage::FunctionCoverageInfo { expressions, mappings, .. } = function_coverage_info; + + for (id, expression) in expressions.iter_enumerated() { + writeln!(w, "{INDENT}coverage {id:?} => {expression:?};")?; + } + for coverage::Mapping { term, code_region } in mappings { + writeln!(w, "{INDENT}coverage {term:?} => {code_region:?};")?; + } + writeln!(w)?; + Ok(()) } @@ -685,13 +706,7 @@ impl Debug for Statement<'_> { AscribeUserType(box (ref place, ref c_ty), ref variance) => { write!(fmt, "AscribeUserType({place:?}, {variance:?}, {c_ty:?})") } - Coverage(box mir::Coverage { ref kind, ref code_regions }) => { - if code_regions.is_empty() { - write!(fmt, "Coverage::{kind:?}") - } else { - write!(fmt, "Coverage::{kind:?} for {code_regions:?}") - } - } + Coverage(box mir::Coverage { ref kind }) => write!(fmt, "Coverage::{kind:?}"), Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"), ConstEvalCounter => write!(fmt, "ConstEvalCounter"), Nop => write!(fmt, "nop"), diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index c74a9536b63..f407dc4d7ae 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -1,5 +1,6 @@ //! Values computed by queries that use MIR. +use crate::mir; use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::UnordSet; @@ -445,14 +446,19 @@ pub struct DestructuredConstant<'tcx> { pub fields: &'tcx [(ConstValue<'tcx>, Ty<'tcx>)], } -/// Coverage information summarized from a MIR if instrumented for source code coverage (see -/// compiler option `-Cinstrument-coverage`). This information is generated by the -/// `InstrumentCoverage` MIR pass and can be retrieved via the `coverageinfo` query. +/// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass +/// (for compiler option `-Cinstrument-coverage`), after MIR optimizations +/// have had a chance to potentially remove some of them. +/// +/// Used by the `coverage_ids_info` query. #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable)] -pub struct CoverageInfo { - /// The total number of coverage region counters added to the MIR `Body`. - pub num_counters: u32, - - /// The total number of coverage region counter expressions added to the MIR `Body`. - pub num_expressions: u32, +pub struct CoverageIdsInfo { + /// Coverage codegen needs to know the highest counter ID that is ever + /// incremented within a function, so that it can set the `num-counters` + /// argument of the `llvm.instrprof.increment` intrinsic. + /// + /// This may be less than the highest counter ID emitted by the + /// InstrumentCoverage MIR pass, if the highest-numbered counter increments + /// were removed by MIR optimizations. + pub max_counter_id: mir::coverage::CounterId, } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 30fc69caa3b..7a645fb5d62 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -5,7 +5,7 @@ use super::{BasicBlock, Const, Local, UserTypeProjection}; -use crate::mir::coverage::{CodeRegion, CoverageKind}; +use crate::mir::coverage::CoverageKind; use crate::traits::Reveal; use crate::ty::adjustment::PointerCoercion; use crate::ty::GenericArgsRef; @@ -361,11 +361,16 @@ pub enum StatementKind<'tcx> { /// Disallowed after drop elaboration. AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance), - /// Marks the start of a "coverage region", injected with '-Cinstrument-coverage'. A - /// `Coverage` statement carries metadata about the coverage region, used to inject a coverage - /// map into the binary. If `Coverage::kind` is a `Counter`, the statement also generates - /// executable code, to increment a counter variable at runtime, each time the code region is - /// executed. + /// Carries control-flow-sensitive information injected by `-Cinstrument-coverage`, + /// such as where to generate physical coverage-counter-increments during codegen. + /// + /// Coverage statements are used in conjunction with the coverage mappings and other + /// information stored in the function's + /// [`mir::Body::function_coverage_info`](crate::mir::Body::function_coverage_info). + /// (For inlined MIR, take care to look up the *original function's* coverage info.) + /// + /// Interpreters and codegen backends that don't support coverage instrumentation + /// can usually treat this as a no-op. Coverage(Box<Coverage>), /// Denotes a call to an intrinsic that does not require an unwind path and always returns. @@ -514,7 +519,6 @@ pub enum FakeReadCause { #[derive(TypeFoldable, TypeVisitable)] pub struct Coverage { pub kind: CoverageKind, - pub code_regions: Vec<CodeRegion>, } #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] @@ -986,18 +990,15 @@ pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>; /// pointee's type. The resulting address is the address that was stored in the pointer. If the /// pointee type is unsized, the pointer additionally stored the value of the metadata. /// -/// Computing a place may cause UB. One possibility is that the pointer used for a `Deref` may not -/// be suitably aligned. Another possibility is that the place is not in bounds, meaning it does not -/// point to an actual allocation. -/// -/// However, if this is actually UB and when the UB kicks in is undecided. This is being discussed -/// in [UCG#319]. The options include that every place must obey those rules, that only some places -/// must obey them, or that places impose no rules of their own. -/// -/// [UCG#319]: https://github.com/rust-lang/unsafe-code-guidelines/issues/319 -/// -/// Rust currently requires that every place obey those two rules. This is checked by Miri and taken -/// advantage of by codegen (via `gep inbounds`). That is possibly subject to change. +/// The "validity invariant" of places is the same as that of raw pointers, meaning that e.g. +/// `*ptr` on a dangling or unaligned pointer is never UB. (Later doing a load/store on that place +/// or turning it into a reference can be UB though!) The only ways for a place computation can +/// cause UB are: +/// - On a `Deref` projection, we do an actual load of the inner place, with all the usual +/// consequences (the inner place must be based on an aligned pointer, it must point to allocated +/// memory, the aliasig model must allow reads, this must not be a data race). +/// - For the projections that perform pointer arithmetic, the offset must in-bounds of an +/// allocation (i.e., the preconditions of `ptr::offset` must be met). #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, HashStable, TypeFoldable, TypeVisitable)] pub struct Place<'tcx> { pub local: Local, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 340c5a769db..afe94d10752 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -573,24 +573,14 @@ rustc_queries! { separate_provide_extern } - /// Returns coverage summary info for a function, after executing the `InstrumentCoverage` - /// MIR pass (assuming the -Cinstrument-coverage option is enabled). - query coverageinfo(key: ty::InstanceDef<'tcx>) -> &'tcx mir::CoverageInfo { - desc { |tcx| "retrieving coverage info from MIR for `{}`", tcx.def_path_str(key.def_id()) } + /// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass + /// (for compiler option `-Cinstrument-coverage`), after MIR optimizations + /// have had a chance to potentially remove some of them. + query coverage_ids_info(key: ty::InstanceDef<'tcx>) -> &'tcx mir::CoverageIdsInfo { + desc { |tcx| "retrieving coverage IDs info from MIR for `{}`", tcx.def_path_str(key.def_id()) } arena_cache } - /// Returns the `CodeRegions` for a function that has instrumented coverage, in case the - /// function was optimized out before codegen, and before being added to the Coverage Map. - query covered_code_regions(key: DefId) -> &'tcx Vec<&'tcx mir::coverage::CodeRegion> { - desc { - |tcx| "retrieving the covered `CodeRegion`s, if instrumented, for `{}`", - tcx.def_path_str(key) - } - arena_cache - cache_on_disk_if { key.is_local() } - } - /// The `DefId` is the `DefId` of the containing MIR body. Promoteds do not have their own /// `DefId`. This function returns all promoteds in the specified body. The body references /// promoteds by the `DefId` and the `mir::Promoted` index. This is necessary, because @@ -2202,6 +2192,11 @@ rustc_queries! { query generics_require_sized_self(def_id: DefId) -> bool { desc { "check whether the item has a `where Self: Sized` bound" } } + + query cross_crate_inlinable(def_id: DefId) -> bool { + desc { "whether the item should be made inlinable across crates" } + separate_provide_extern + } } rustc_query_append! { define_callbacks! } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 89934e4350e..67804998a32 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -19,11 +19,12 @@ use rustc_middle::middle::region; use rustc_middle::mir::interpret::AllocId; use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Mutability, UnOp}; use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::GenericArgsRef; -use rustc_middle::ty::{self, AdtDef, FnSig, List, Ty, UpvarArgs}; -use rustc_middle::ty::{CanonicalUserType, CanonicalUserTypeAnnotation}; +use rustc_middle::ty::{ + self, AdtDef, CanonicalUserType, CanonicalUserTypeAnnotation, FnSig, GenericArgsRef, List, Ty, + UpvarArgs, +}; use rustc_span::def_id::LocalDefId; -use rustc_span::{sym, Span, Symbol, DUMMY_SP}; +use rustc_span::{sym, ErrorGuaranteed, Span, Symbol, DUMMY_SP}; use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_target::asm::InlineAsmRegOrRegClass; use std::fmt; @@ -581,13 +582,13 @@ pub enum BindingMode { ByRef(BorrowKind), } -#[derive(Clone, Debug, HashStable)] +#[derive(Clone, Debug, HashStable, TypeVisitable)] pub struct FieldPat<'tcx> { pub field: FieldIdx, pub pattern: Box<Pat<'tcx>>, } -#[derive(Clone, Debug, HashStable)] +#[derive(Clone, Debug, HashStable, TypeVisitable)] pub struct Pat<'tcx> { pub ty: Ty<'tcx>, pub span: Span, @@ -632,7 +633,7 @@ impl<'tcx> Pat<'tcx> { use PatKind::*; match &self.kind { - Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } => {} + Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } | Error(_) => {} AscribeUserType { subpattern, .. } | Binding { subpattern: Some(subpattern), .. } | Deref { subpattern } => subpattern.walk_(it), @@ -647,6 +648,21 @@ impl<'tcx> Pat<'tcx> { } } + /// Whether the pattern has a `PatKind::Error` nested within. + pub fn pat_error_reported(&self) -> Result<(), ErrorGuaranteed> { + let mut error = None; + self.walk(|pat| { + if let PatKind::Error(e) = pat.kind && error.is_none() { + error = Some(e); + } + error.is_none() + }); + match error { + None => Ok(()), + Some(e) => Err(e), + } + } + /// Walk the pattern in left-to-right order. /// /// If you always want to recurse, prefer this method over `walk`. @@ -664,7 +680,7 @@ impl<'tcx> IntoDiagnosticArg for Pat<'tcx> { } } -#[derive(Clone, Debug, HashStable)] +#[derive(Clone, Debug, HashStable, TypeVisitable)] pub struct Ascription<'tcx> { pub annotation: CanonicalUserTypeAnnotation<'tcx>, /// Variance to use when relating the `user_ty` to the **type of the value being @@ -688,7 +704,7 @@ pub struct Ascription<'tcx> { pub variance: ty::Variance, } -#[derive(Clone, Debug, HashStable)] +#[derive(Clone, Debug, HashStable, TypeVisitable)] pub enum PatKind<'tcx> { /// A wildcard pattern: `_`. Wild, @@ -702,7 +718,9 @@ pub enum PatKind<'tcx> { Binding { mutability: Mutability, name: Symbol, + #[type_visitable(ignore)] mode: BindingMode, + #[type_visitable(ignore)] var: LocalVarId, ty: Ty<'tcx>, subpattern: Option<Box<Pat<'tcx>>>, @@ -769,12 +787,17 @@ pub enum PatKind<'tcx> { Or { pats: Box<[Box<Pat<'tcx>>]>, }, + + /// An error has been encountered during lowering. We probably shouldn't report more lints + /// related to this pattern. + Error(ErrorGuaranteed), } -#[derive(Clone, Debug, PartialEq, HashStable)] +#[derive(Clone, Debug, PartialEq, HashStable, TypeVisitable)] pub struct PatRange<'tcx> { pub lo: mir::Const<'tcx>, pub hi: mir::Const<'tcx>, + #[type_visitable(ignore)] pub end: RangeEnd, } @@ -931,6 +954,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { } Ok(()) } + PatKind::Error(_) => write!(f, "<error>"), } } } diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index b84e1568884..afb58438519 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -226,7 +226,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 => {} + Binding { .. } | Wild | 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/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 1ccb81dcb9b..05706e331f3 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1126,7 +1126,11 @@ impl<'tcx> TyCtxt<'tcx> { { v.visit_ty(alias_ty); if !v.0.is_empty() { - return Some((v.0, alias_generics.span, alias_generics.span_for_lifetime_suggestion())); + return Some(( + v.0, + alias_generics.span, + alias_generics.span_for_lifetime_suggestion(), + )); } } return None; @@ -1683,7 +1687,6 @@ impl<'tcx> TyCtxt<'tcx> { && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(_def_id)) { // If this is an inherent projection. - generics.params.len() + 1 } else { generics.count() @@ -1893,15 +1896,6 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_args_from_iter(iter::once(self_ty.into()).chain(rest)) } - pub fn mk_alias_ty( - self, - def_id: DefId, - args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>, - ) -> ty::AliasTy<'tcx> { - let args = self.check_and_mk_args(def_id, args); - ty::AliasTy { def_id, args, _use_mk_alias_ty_instead: () } - } - pub fn mk_bound_variable_kinds_from_iter<I, T>(self, iter: I) -> T::Output where I: Iterator<Item = T>, diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index f03813a459b..49014c60a6d 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -494,7 +494,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsSuggestableVisitor<'tcx> { let parent = self.tcx.parent(def_id); let parent_ty = self.tcx.type_of(parent).instantiate_identity(); if let DefKind::TyAlias | DefKind::AssocTy = self.tcx.def_kind(parent) - && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = *parent_ty.kind() + && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = + *parent_ty.kind() && parent_opaque_def_id == def_id { // Okay @@ -577,8 +578,10 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for MakeSuggestableFolder<'tcx> { Alias(Opaque, AliasTy { def_id, .. }) => { let parent = self.tcx.parent(def_id); let parent_ty = self.tcx.type_of(parent).instantiate_identity(); - if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = self.tcx.def_kind(parent) - && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = *parent_ty.kind() + if let hir::def::DefKind::TyAlias | hir::def::DefKind::AssocTy = + self.tcx.def_kind(parent) + && let Alias(Opaque, AliasTy { def_id: parent_opaque_def_id, .. }) = + *parent_ty.kind() && parent_opaque_def_id == def_id { t diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 459c8dfb596..0fe1284eed9 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -253,7 +253,13 @@ impl<'tcx> Ty<'tcx> { ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(), ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(), ty::Param(p) => format!("type parameter `{p}`").into(), - ty::Alias(ty::Opaque, ..) => if tcx.ty_is_opaque_future(self) { "future".into() } else { "opaque type".into() }, + ty::Alias(ty::Opaque, ..) => { + if tcx.ty_is_opaque_future(self) { + "future".into() + } else { + "opaque type".into() + } + } ty::Error(_) => "type error".into(), _ => { let width = tcx.sess.diagnostic_width(); diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 72390e4bbb0..a861af47859 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -11,7 +11,6 @@ use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_serialize::{self, Decodable, Encodable}; -use rustc_span::sym; use rustc_type_ir::WithCachedTypeInfo; use smallvec::SmallVec; @@ -452,10 +451,6 @@ impl<'tcx> GenericArgs<'tcx> { tcx.mk_args_from_iter(self.iter().take(generics.count())) } - pub fn host_effect_param(&'tcx self) -> Option<ty::Const<'tcx>> { - self.consts().rfind(|x| matches!(x.kind(), ty::ConstKind::Param(p) if p.name == sym::host)) - } - pub fn print_as_list(&self) -> String { let v = self.iter().map(|arg| arg.to_string()).collect::<Vec<_>>(); format!("[{}]", v.join(", ")) diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 8e6c1cd4bbb..44e88d3e230 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -79,6 +79,10 @@ impl GenericParamDef { } } + pub fn is_host_effect(&self) -> bool { + matches!(self.kind, GenericParamDefKind::Const { is_host_effect: true, .. }) + } + pub fn default_value<'tcx>( &self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 0a425be52ff..0b308d5dec1 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -245,16 +245,15 @@ impl<'tcx> InstanceDef<'tcx> { // drops of `Option::None` before LTO. We also respect the intent of // `#[inline]` on `Drop::drop` implementations. return ty.ty_adt_def().map_or(true, |adt_def| { - adt_def.destructor(tcx).map_or_else( - || adt_def.is_enum(), - |dtor| tcx.codegen_fn_attrs(dtor.did).requests_inline(), - ) + adt_def + .destructor(tcx) + .map_or_else(|| adt_def.is_enum(), |dtor| tcx.cross_crate_inlinable(dtor.did)) }); } if let ty::InstanceDef::ThreadLocalShim(..) = *self { return false; } - tcx.codegen_fn_attrs(self.def_id()).requests_inline() + tcx.cross_crate_inlinable(self.def_id()) } pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index bccf5e83987..5ef7ee52636 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -868,7 +868,7 @@ where { let metadata = tcx.normalize_erasing_regions( cx.param_env(), - Ty::new_projection(tcx,metadata_def_id, [pointee]), + Ty::new_projection(tcx, metadata_def_id, [pointee]), ); // Map `Metadata = DynMetadata<dyn Trait>` back to a vtable, since it diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index b7d2e3d9493..e6cd3dd4d82 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1023,7 +1023,7 @@ impl<'tcx> Term<'tcx> { _ => None, }, TermKind::Const(ct) => match ct.kind() { - ConstKind::Unevaluated(uv) => Some(tcx.mk_alias_ty(uv.def, uv.args)), + ConstKind::Unevaluated(uv) => Some(AliasTy::new(tcx, uv.def, uv.args)), _ => None, }, } diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index aa8e2e30715..107b44285ac 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -10,13 +10,12 @@ use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; mod pretty; pub use self::pretty::*; +pub type PrintError = std::fmt::Error; + // FIXME(eddyb) false positive, the lifetime parameters are used with `P: Printer<...>`. #[allow(unused_lifetimes)] pub trait Print<'tcx, P> { - type Output; - type Error; - - fn print(&self, cx: P) -> Result<Self::Output, Self::Error>; + fn print(&self, cx: P) -> Result<P, PrintError>; } /// Interface for outputting user-facing "type-system entities" @@ -29,21 +28,13 @@ pub trait Print<'tcx, P> { // // FIXME(eddyb) find a better name; this is more general than "printing". pub trait Printer<'tcx>: Sized { - type Error; - - type Path; - type Region; - type Type; - type DynExistential; - type Const; - fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; fn print_def_path( self, def_id: DefId, args: &'tcx [GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { self.default_print_def_path(def_id, args) } @@ -53,48 +44,48 @@ pub trait Printer<'tcx>: Sized { args: &'tcx [GenericArg<'tcx>], self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { self.default_print_impl_path(impl_def_id, args, self_ty, trait_ref) } - fn print_region(self, region: ty::Region<'tcx>) -> Result<Self::Region, Self::Error>; + fn print_region(self, region: ty::Region<'tcx>) -> Result<Self, PrintError>; - fn print_type(self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>; + fn print_type(self, ty: Ty<'tcx>) -> Result<Self, PrintError>; fn print_dyn_existential( self, predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, - ) -> Result<Self::DynExistential, Self::Error>; + ) -> Result<Self, PrintError>; - fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error>; + fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self, PrintError>; - fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error>; + fn path_crate(self, cnum: CrateNum) -> Result<Self, PrintError>; fn path_qualified( self, self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error>; + ) -> Result<Self, PrintError>; fn path_append_impl( self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, disambiguated_data: &DisambiguatedDefPathData, self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error>; + ) -> Result<Self, PrintError>; fn path_append( self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, disambiguated_data: &DisambiguatedDefPathData, - ) -> Result<Self::Path, Self::Error>; + ) -> Result<Self, PrintError>; fn path_generic_args( self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, args: &[GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error>; + ) -> Result<Self, PrintError>; // Defaults (should not be overridden): @@ -103,7 +94,7 @@ pub trait Printer<'tcx>: Sized { self, def_id: DefId, args: &'tcx [GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { let key = self.tcx().def_key(def_id); debug!(?key); @@ -194,7 +185,7 @@ pub trait Printer<'tcx>: Sized { _args: &'tcx [GenericArg<'tcx>], self_ty: Ty<'tcx>, impl_trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { debug!( "default_print_impl_path: impl_def_id={:?}, self_ty={}, impl_trait_ref={:?}", impl_def_id, self_ty, impl_trait_ref @@ -295,34 +286,25 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> { } impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Region<'tcx> { - type Output = P::Region; - type Error = P::Error; - fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { + fn print(&self, cx: P) -> Result<P, PrintError> { cx.print_region(*self) } } impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for Ty<'tcx> { - type Output = P::Type; - type Error = P::Error; - - fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { + fn print(&self, cx: P) -> Result<P, PrintError> { cx.print_type(*self) } } impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> { - type Output = P::DynExistential; - type Error = P::Error; - fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { + fn print(&self, cx: P) -> Result<P, PrintError> { cx.print_dyn_existential(self) } } impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Const<'tcx> { - type Output = P::Const; - type Error = P::Error; - fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { + fn print(&self, cx: P) -> Result<P, PrintError> { cx.print_const(*self) } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 2d7350387ca..d8010c71497 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -205,29 +205,19 @@ impl<'tcx> RegionHighlightMode<'tcx> { } /// Trait for printers that pretty-print using `fmt::Write` to the printer. -pub trait PrettyPrinter<'tcx>: - Printer< - 'tcx, - Error = fmt::Error, - Path = Self, - Region = Self, - Type = Self, - DynExistential = Self, - Const = Self, - > + fmt::Write -{ +pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { /// Like `print_def_path` but for value paths. fn print_value_path( self, def_id: DefId, args: &'tcx [GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { self.print_def_path(def_id, args) } - fn in_binder<T>(self, value: &ty::Binder<'tcx, T>) -> Result<Self, Self::Error> + fn in_binder<T>(self, value: &ty::Binder<'tcx, T>) -> Result<Self, PrintError> where - T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<TyCtxt<'tcx>>, + T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>, { value.as_ref().skip_binder().print(self) } @@ -236,17 +226,17 @@ pub trait PrettyPrinter<'tcx>: self, value: &ty::Binder<'tcx, T>, f: F, - ) -> Result<Self, Self::Error> + ) -> Result<Self, PrintError> where - T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<TyCtxt<'tcx>>, + T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>, { f(value.as_ref().skip_binder(), self) } /// Prints comma-separated elements. - fn comma_sep<T>(mut self, mut elems: impl Iterator<Item = T>) -> Result<Self, Self::Error> + fn comma_sep<T>(mut self, mut elems: impl Iterator<Item = T>) -> Result<Self, PrintError> where - T: Print<'tcx, Self, Output = Self, Error = Self::Error>, + T: Print<'tcx, Self>, { if let Some(first) = elems.next() { self = first.print(self)?; @@ -261,10 +251,10 @@ pub trait PrettyPrinter<'tcx>: /// Prints `{f: t}` or `{f as t}` depending on the `cast` argument fn typed_value( mut self, - f: impl FnOnce(Self) -> Result<Self, Self::Error>, - t: impl FnOnce(Self) -> Result<Self, Self::Error>, + f: impl FnOnce(Self) -> Result<Self, PrintError>, + t: impl FnOnce(Self) -> Result<Self, PrintError>, conversion: &str, - ) -> Result<Self::Const, Self::Error> { + ) -> Result<Self, PrintError> { self.write_str("{")?; self = f(self)?; self.write_str(conversion)?; @@ -276,8 +266,8 @@ pub trait PrettyPrinter<'tcx>: /// Prints `<...>` around what `f` prints. fn generic_delimiters( self, - f: impl FnOnce(Self) -> Result<Self, Self::Error>, - ) -> Result<Self, Self::Error>; + f: impl FnOnce(Self) -> Result<Self, PrintError>, + ) -> Result<Self, PrintError>; /// Returns `true` if the region should be printed in /// optional positions, e.g., `&'a T` or `dyn Tr + 'b`. @@ -291,7 +281,7 @@ pub trait PrettyPrinter<'tcx>: /// If possible, this returns a global path resolving to `def_id` that is visible /// 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(self, def_id: DefId) -> Result<(Self, bool), Self::Error> { + fn try_print_visible_def_path(self, def_id: DefId) -> Result<(Self, bool), PrintError> { if NO_VISIBLE_PATH.with(|flag| flag.get()) { return Ok((self, false)); } @@ -305,10 +295,7 @@ pub trait PrettyPrinter<'tcx>: // For enum variants, if they have an unique name, then we only print the name, otherwise we // print the enum name and the variant name. Otherwise, we do not print anything and let the // caller use the `print_def_path` fallback. - fn force_print_trimmed_def_path( - mut self, - def_id: DefId, - ) -> Result<(Self::Path, bool), Self::Error> { + fn force_print_trimmed_def_path(mut self, def_id: DefId) -> Result<(Self, bool), PrintError> { let key = self.tcx().def_key(def_id); let visible_parent_map = self.tcx().visible_parent_map(()); let kind = self.tcx().def_kind(def_id); @@ -319,8 +306,7 @@ pub trait PrettyPrinter<'tcx>: && let DefPathData::TypeNs(_) = key.disambiguated_data.data && Some(*visible_parent) != actual_parent { - this - .tcx() + this.tcx() // FIXME(typed_def_id): Further propagate ModDefId .module_children(ModDefId::new_unchecked(*visible_parent)) .iter() @@ -359,8 +345,14 @@ pub trait PrettyPrinter<'tcx>: // the parent type in the path. For example, `Iterator::Item`. self.write_str(get_local_name(&self, symbol, parent, parent_key).as_str())?; self.write_str("::")?; - } else if let DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::Trait - | DefKind::TyAlias | DefKind::Fn | DefKind::Const | DefKind::Static(_) = kind + } else if let DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Trait + | DefKind::TyAlias + | DefKind::Fn + | DefKind::Const + | DefKind::Static(_) = kind { } else { // If not covered above, like for example items out of `impl` blocks, fallback. @@ -373,10 +365,7 @@ pub trait PrettyPrinter<'tcx>: } /// 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<(Self::Path, bool), Self::Error> { + fn try_print_trimmed_def_path(mut self, def_id: DefId) -> Result<(Self, bool), PrintError> { if FORCE_TRIMMED_PATH.with(|flag| flag.get()) { let (s, trimmed) = self.force_print_trimmed_def_path(def_id)?; if trimmed { @@ -418,7 +407,7 @@ pub trait PrettyPrinter<'tcx>: mut self, def_id: DefId, callers: &mut Vec<DefId>, - ) -> Result<(Self, bool), Self::Error> { + ) -> Result<(Self, bool), PrintError> { define_scoped_cx!(self); debug!("try_print_visible_def_path: def_id={:?}", def_id); @@ -590,7 +579,7 @@ pub trait PrettyPrinter<'tcx>: self, self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { if trait_ref.is_none() { // Inherent impls. Try to print `Foo::bar` for an inherent // impl on `Foo`, but fallback to `<Foo>::bar` if self-type is @@ -624,10 +613,10 @@ pub trait PrettyPrinter<'tcx>: fn pretty_path_append_impl( mut self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { self = print_prefix(self)?; self.generic_delimiters(|mut cx| { @@ -643,7 +632,7 @@ pub trait PrettyPrinter<'tcx>: }) } - fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> { + fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self, PrintError> { define_scoped_cx!(self); match *ty.kind() { @@ -914,7 +903,7 @@ pub trait PrettyPrinter<'tcx>: mut self, def_id: DefId, args: &'tcx ty::List<ty::GenericArg<'tcx>>, - ) -> Result<Self::Type, Self::Error> { + ) -> Result<Self, PrintError> { let tcx = self.tcx(); // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, @@ -1119,8 +1108,10 @@ pub trait PrettyPrinter<'tcx>: } if self.tcx().features().return_type_notation - && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) = self.tcx().opt_rpitit_info(def_id) - && let ty::Alias(_, alias_ty) = self.tcx().fn_sig(fn_def_id).skip_binder().output().skip_binder().kind() + && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) = + self.tcx().opt_rpitit_info(def_id) + && let ty::Alias(_, alias_ty) = + self.tcx().fn_sig(fn_def_id).skip_binder().output().skip_binder().kind() && alias_ty.def_id == def_id { let num_args = self.tcx().generics_of(fn_def_id).count(); @@ -1182,7 +1173,7 @@ pub trait PrettyPrinter<'tcx>: fn pretty_print_inherent_projection( self, alias_ty: &ty::AliasTy<'tcx>, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { let def_key = self.tcx().def_key(alias_ty.def_id); self.path_generic_args( |cx| { @@ -1206,7 +1197,7 @@ pub trait PrettyPrinter<'tcx>: fn pretty_print_dyn_existential( mut self, predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, - ) -> Result<Self::DynExistential, Self::Error> { + ) -> Result<Self, PrintError> { // Generate the main trait ref, including associated types. let mut first = true; @@ -1299,7 +1290,7 @@ pub trait PrettyPrinter<'tcx>: inputs: &[Ty<'tcx>], c_variadic: bool, output: Ty<'tcx>, - ) -> Result<Self, Self::Error> { + ) -> Result<Self, PrintError> { define_scoped_cx!(self); p!("(", comma_sep(inputs.iter().copied())); @@ -1321,7 +1312,7 @@ pub trait PrettyPrinter<'tcx>: mut self, ct: ty::Const<'tcx>, print_ty: bool, - ) -> Result<Self::Const, Self::Error> { + ) -> Result<Self, PrintError> { define_scoped_cx!(self); if self.should_print_verbose() { @@ -1364,20 +1355,22 @@ pub trait PrettyPrinter<'tcx>: // cause printing to enter an infinite recursion if the anon const is in the self type i.e. // `impl<T: Default> Default for [T; 32 - 1 - 1 - 1] {` // where we would try to print `<[T; /* print `constant#0` again */] as Default>::{constant#0}` - p!(write("{}::{}", self.tcx().crate_name(def.krate), self.tcx().def_path(def).to_string_no_crate_verbose())) + p!(write( + "{}::{}", + self.tcx().crate_name(def.krate), + self.tcx().def_path(def).to_string_no_crate_verbose() + )) } } defkind => bug!("`{:?}` has unexpected defkind {:?}", ct, defkind), } } - ty::ConstKind::Infer(infer_ct) => { - match infer_ct { - ty::InferConst::Var(ct_vid) - if let Some(name) = self.const_infer_name(ct_vid) => - p!(write("{}", name)), - _ => print_underscore!(), + ty::ConstKind::Infer(infer_ct) => match infer_ct { + ty::InferConst::Var(ct_vid) if let Some(name) = self.const_infer_name(ct_vid) => { + p!(write("{}", name)) } - } + _ => print_underscore!(), + }, ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)), ty::ConstKind::Value(value) => { return self.pretty_print_const_valtree(value, ct.ty(), print_ty); @@ -1395,11 +1388,7 @@ pub trait PrettyPrinter<'tcx>: Ok(self) } - fn pretty_print_const_scalar( - self, - scalar: Scalar, - ty: Ty<'tcx>, - ) -> Result<Self::Const, Self::Error> { + fn pretty_print_const_scalar(self, scalar: Scalar, ty: Ty<'tcx>) -> Result<Self, PrintError> { match scalar { Scalar::Ptr(ptr, _size) => self.pretty_print_const_scalar_ptr(ptr, ty), Scalar::Int(int) => { @@ -1412,7 +1401,7 @@ pub trait PrettyPrinter<'tcx>: mut self, ptr: Pointer, ty: Ty<'tcx>, - ) -> Result<Self::Const, Self::Error> { + ) -> Result<Self, PrintError> { define_scoped_cx!(self); let (alloc_id, offset) = ptr.into_parts(); @@ -1474,7 +1463,7 @@ pub trait PrettyPrinter<'tcx>: int: ScalarInt, ty: Ty<'tcx>, print_ty: bool, - ) -> Result<Self::Const, Self::Error> { + ) -> Result<Self, PrintError> { define_scoped_cx!(self); match ty.kind() { @@ -1536,7 +1525,7 @@ pub trait PrettyPrinter<'tcx>: self, _: Pointer<Prov>, ty: Ty<'tcx>, - ) -> Result<Self::Const, Self::Error> { + ) -> Result<Self, PrintError> { self.typed_value( |mut this| { this.write_str("&_")?; @@ -1547,7 +1536,7 @@ pub trait PrettyPrinter<'tcx>: ) } - fn pretty_print_byte_str(mut self, byte_str: &'tcx [u8]) -> Result<Self::Const, Self::Error> { + fn pretty_print_byte_str(mut self, byte_str: &'tcx [u8]) -> Result<Self, PrintError> { write!(self, "b\"{}\"", byte_str.escape_ascii())?; Ok(self) } @@ -1557,7 +1546,7 @@ pub trait PrettyPrinter<'tcx>: valtree: ty::ValTree<'tcx>, ty: Ty<'tcx>, print_ty: bool, - ) -> Result<Self::Const, Self::Error> { + ) -> Result<Self, PrintError> { define_scoped_cx!(self); if self.should_print_verbose() { @@ -1680,7 +1669,7 @@ pub trait PrettyPrinter<'tcx>: fn pretty_closure_as_impl( mut self, closure: ty::ClosureArgs<'tcx>, - ) -> Result<Self::Const, Self::Error> { + ) -> Result<Self, PrintError> { let sig = closure.sig(); let kind = closure.kind_ty().to_opt_closure_kind().unwrap_or(ty::ClosureKind::Fn); @@ -1853,14 +1842,6 @@ impl fmt::Write for FmtPrinter<'_, '_> { } impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { - type Error = fmt::Error; - - type Path = Self; - type Region = Self; - type Type = Self; - type DynExistential = Self; - type Const = Self; - fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { self.tcx } @@ -1869,7 +1850,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { mut self, def_id: DefId, args: &'tcx [GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { define_scoped_cx!(self); if args.is_empty() { @@ -1924,11 +1905,11 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { self.default_print_def_path(def_id, args) } - fn print_region(self, region: ty::Region<'tcx>) -> Result<Self::Region, Self::Error> { + fn print_region(self, region: ty::Region<'tcx>) -> Result<Self, PrintError> { self.pretty_print_region(region) } - fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> { + fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self, PrintError> { if self.type_length_limit.value_within_limit(self.printed_type_count) { self.printed_type_count += 1; self.pretty_print_type(ty) @@ -1942,15 +1923,15 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { fn print_dyn_existential( self, predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, - ) -> Result<Self::DynExistential, Self::Error> { + ) -> Result<Self, PrintError> { self.pretty_print_dyn_existential(predicates) } - fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { + fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self, PrintError> { self.pretty_print_const(ct, false) } - fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { + fn path_crate(mut self, cnum: CrateNum) -> Result<Self, PrintError> { self.empty_path = true; if cnum == LOCAL_CRATE { if self.tcx.sess.at_least_rust_2018() { @@ -1971,7 +1952,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { mut self, self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { self = self.pretty_path_qualified(self_ty, trait_ref)?; self.empty_path = false; Ok(self) @@ -1979,11 +1960,11 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { fn path_append_impl( mut self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, _disambiguated_data: &DisambiguatedDefPathData, self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { self = self.pretty_path_append_impl( |mut cx| { cx = print_prefix(cx)?; @@ -2002,9 +1983,9 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { fn path_append( mut self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, disambiguated_data: &DisambiguatedDefPathData, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { self = print_prefix(self)?; // Skip `::{{extern}}` blocks and `::{{constructor}}` on tuple/unit structs. @@ -2033,9 +2014,9 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { fn path_generic_args( mut self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, args: &[GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { self = print_prefix(self)?; let tcx = self.tcx; @@ -2092,7 +2073,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { mut self, def_id: DefId, args: &'tcx [GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { let was_in_value = std::mem::replace(&mut self.in_value, true); self = self.print_def_path(def_id, args)?; self.in_value = was_in_value; @@ -2100,30 +2081,30 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { Ok(self) } - fn in_binder<T>(self, value: &ty::Binder<'tcx, T>) -> Result<Self, Self::Error> + fn in_binder<T>(self, value: &ty::Binder<'tcx, T>) -> Result<Self, PrintError> where - T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<TyCtxt<'tcx>>, + T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>, { self.pretty_in_binder(value) } - fn wrap_binder<T, C: FnOnce(&T, Self) -> Result<Self, Self::Error>>( + fn wrap_binder<T, C: FnOnce(&T, Self) -> Result<Self, PrintError>>( self, value: &ty::Binder<'tcx, T>, f: C, - ) -> Result<Self, Self::Error> + ) -> Result<Self, PrintError> where - T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<TyCtxt<'tcx>>, + T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>, { self.pretty_wrap_binder(value, f) } fn typed_value( mut self, - f: impl FnOnce(Self) -> Result<Self, Self::Error>, - t: impl FnOnce(Self) -> Result<Self, Self::Error>, + f: impl FnOnce(Self) -> Result<Self, PrintError>, + t: impl FnOnce(Self) -> Result<Self, PrintError>, conversion: &str, - ) -> Result<Self::Const, Self::Error> { + ) -> Result<Self, PrintError> { self.write_str("{")?; self = f(self)?; self.write_str(conversion)?; @@ -2136,8 +2117,8 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { fn generic_delimiters( mut self, - f: impl FnOnce(Self) -> Result<Self, Self::Error>, - ) -> Result<Self, Self::Error> { + f: impl FnOnce(Self) -> Result<Self, PrintError>, + ) -> Result<Self, PrintError> { write!(self, "<")?; let was_in_value = std::mem::replace(&mut self.in_value, false); @@ -2197,7 +2178,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { self, p: Pointer<Prov>, ty: Ty<'tcx>, - ) -> Result<Self::Const, Self::Error> { + ) -> Result<Self, PrintError> { let print = |mut this: Self| { define_scoped_cx!(this); if this.print_alloc_ids { @@ -2246,7 +2227,9 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { | ty::RePlaceholder(ty::Placeholder { bound: ty::BoundRegion { kind: br, .. }, .. }) => { - if let ty::BrNamed(_, name) = br && br.is_named() { + if let ty::BrNamed(_, name) = br + && br.is_named() + { p!(write("{}", name)); return Ok(self); } @@ -2360,7 +2343,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { value: &ty::Binder<'tcx, T>, ) -> Result<(Self, T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>), fmt::Error> where - T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<TyCtxt<'tcx>>, + T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>, { fn name_by_region_index( index: usize, @@ -2530,7 +2513,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { pub fn pretty_in_binder<T>(self, value: &ty::Binder<'tcx, T>) -> Result<Self, fmt::Error> where - T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<TyCtxt<'tcx>>, + T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>, { let old_region_index = self.region_index; let (new, new_value, _) = self.name_all_regions(value)?; @@ -2546,7 +2529,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { f: C, ) -> Result<Self, fmt::Error> where - T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<TyCtxt<'tcx>>, + T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>, { let old_region_index = self.region_index; let (new, new_value, _) = self.name_all_regions(value)?; @@ -2611,24 +2594,19 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { impl<'tcx, T, P: PrettyPrinter<'tcx>> Print<'tcx, P> for ty::Binder<'tcx, T> where - T: Print<'tcx, P, Output = P, Error = P::Error> + TypeFoldable<TyCtxt<'tcx>>, + T: Print<'tcx, P> + TypeFoldable<TyCtxt<'tcx>>, { - type Output = P; - type Error = P::Error; - - fn print(&self, cx: P) -> Result<Self::Output, Self::Error> { + fn print(&self, cx: P) -> Result<P, PrintError> { cx.in_binder(self) } } impl<'tcx, T, U, P: PrettyPrinter<'tcx>> Print<'tcx, P> for ty::OutlivesPredicate<T, U> where - T: Print<'tcx, P, Output = P, Error = P::Error>, - U: Print<'tcx, P, Output = P, Error = P::Error>, + T: Print<'tcx, P>, + U: Print<'tcx, P>, { - type Output = P; - type Error = P::Error; - fn print(&self, mut cx: P) -> Result<Self::Output, Self::Error> { + fn print(&self, mut cx: P) -> Result<P, PrintError> { define_scoped_cx!(cx); p!(print(self.0), ": ", print(self.1)); Ok(cx) @@ -2655,9 +2633,7 @@ macro_rules! forward_display_to_print { macro_rules! define_print_and_forward_display { (($self:ident, $cx:ident): $($ty:ty $print:block)+) => { $(impl<'tcx, P: PrettyPrinter<'tcx>> Print<'tcx, P> for $ty { - type Output = P; - type Error = fmt::Error; - fn print(&$self, $cx: P) -> Result<Self::Output, Self::Error> { + fn print(&$self, $cx: P) -> Result<P, PrintError> { #[allow(unused_mut)] let mut $cx = $cx; define_scoped_cx!($cx); diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index e9d763afa68..fdfdd6cc8d6 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -8,6 +8,7 @@ use crate::ty::error::{ExpectedFound, TypeError}; use crate::ty::{self, Expr, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable}; use crate::ty::{GenericArg, GenericArgKind, GenericArgsRef}; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_target::spec::abi; use std::iter; @@ -134,7 +135,7 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>( } #[inline] -pub fn relate_args<'tcx, R: TypeRelation<'tcx>>( +pub fn relate_args_invariantly<'tcx, R: TypeRelation<'tcx>>( relation: &mut R, a_arg: GenericArgsRef<'tcx>, b_arg: GenericArgsRef<'tcx>, @@ -273,8 +274,21 @@ impl<'tcx> Relate<'tcx> for ty::AliasTy<'tcx> { if a.def_id != b.def_id { Err(TypeError::ProjectionMismatched(expected_found(relation, a.def_id, b.def_id))) } else { - let args = relation.relate(a.args, b.args)?; - Ok(relation.tcx().mk_alias_ty(a.def_id, args)) + let args = match relation.tcx().def_kind(a.def_id) { + DefKind::OpaqueTy => relate_args_with_variances( + relation, + a.def_id, + relation.tcx().variances_of(a.def_id), + a.args, + b.args, + false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle + )?, + DefKind::AssocTy | DefKind::AssocConst | DefKind::TyAlias => { + relate_args_invariantly(relation, a.args, b.args)? + } + def => bug!("unknown alias DefKind: {def:?}"), + }; + Ok(ty::AliasTy::new(relation.tcx(), a.def_id, args)) } } } @@ -315,7 +329,7 @@ impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> { if a.def_id != b.def_id { Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id))) } else { - let args = relate_args(relation, a.args, b.args)?; + let args = relate_args_invariantly(relation, a.args, b.args)?; Ok(ty::TraitRef::new(relation.tcx(), a.def_id, args)) } } @@ -331,7 +345,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> { if a.def_id != b.def_id { Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id))) } else { - let args = relate_args(relation, a.args, b.args)?; + let args = relate_args_invariantly(relation, a.args, b.args)?; Ok(ty::ExistentialTraitRef { def_id: a.def_id, args }) } } @@ -449,7 +463,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( // All Generator types with the same id represent // the (anonymous) type of the same generator expression. So // all of their regions should be equated. - let args = relation.relate(a_args, b_args)?; + let args = relate_args_invariantly(relation, a_args, b_args)?; Ok(Ty::new_generator(tcx, a_id, args, movability)) } @@ -459,7 +473,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( // All GeneratorWitness types with the same id represent // the (anonymous) type of the same generator expression. So // all of their regions should be equated. - let args = relation.relate(a_args, b_args)?; + let args = relate_args_invariantly(relation, a_args, b_args)?; Ok(Ty::new_generator_witness(tcx, a_id, args)) } @@ -467,7 +481,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( // All Closure types with the same id represent // the (anonymous) type of the same closure expression. So // all of their regions should be equated. - let args = relation.relate(a_args, b_args)?; + let args = relate_args_invariantly(relation, a_args, b_args)?; Ok(Ty::new_closure(tcx, a_id, &args)) } @@ -536,24 +550,6 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( Ok(Ty::new_fn_ptr(tcx, fty)) } - // The args of opaque types may not all be invariant, so we have - // to treat them separately from other aliases. - ( - &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, args: a_args, .. }), - &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, args: b_args, .. }), - ) if a_def_id == b_def_id => { - let opt_variances = tcx.variances_of(a_def_id); - let args = relate_args_with_variances( - relation, - a_def_id, - opt_variances, - a_args, - b_args, - false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle - )?; - Ok(Ty::new_opaque(tcx, a_def_id, args)) - } - // Alias tend to mostly already be handled downstream due to normalization. (&ty::Alias(a_kind, a_data), &ty::Alias(b_kind, b_data)) => { let alias_ty = relation.relate(a_data, b_data)?; @@ -709,7 +705,7 @@ impl<'tcx> Relate<'tcx> for ty::ClosureArgs<'tcx> { a: ty::ClosureArgs<'tcx>, b: ty::ClosureArgs<'tcx>, ) -> RelateResult<'tcx, ty::ClosureArgs<'tcx>> { - let args = relate_args(relation, a.args, b.args)?; + let args = relate_args_invariantly(relation, a.args, b.args)?; Ok(ty::ClosureArgs { args }) } } @@ -720,7 +716,7 @@ impl<'tcx> Relate<'tcx> for ty::GeneratorArgs<'tcx> { a: ty::GeneratorArgs<'tcx>, b: ty::GeneratorArgs<'tcx>, ) -> RelateResult<'tcx, ty::GeneratorArgs<'tcx>> { - let args = relate_args(relation, a.args, b.args)?; + let args = relate_args_invariantly(relation, a.args, b.args)?; Ok(ty::GeneratorArgs { args }) } } @@ -731,7 +727,7 @@ impl<'tcx> Relate<'tcx> for GenericArgsRef<'tcx> { a: GenericArgsRef<'tcx>, b: GenericArgsRef<'tcx>, ) -> RelateResult<'tcx, GenericArgsRef<'tcx>> { - relate_args(relation, a, b) + relate_args_invariantly(relation, a, b) } } @@ -835,19 +831,6 @@ impl<'tcx> Relate<'tcx> for Term<'tcx> { } } -impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: ty::ProjectionPredicate<'tcx>, - b: ty::ProjectionPredicate<'tcx>, - ) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> { - Ok(ty::ProjectionPredicate { - projection_ty: relation.relate(a.projection_ty, b.projection_ty)?, - term: relation.relate(a.term, b.term)?, - }) - } -} - /////////////////////////////////////////////////////////////////////////// // Error handling diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e5f418bbb4b..fc207a2c350 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1213,14 +1213,28 @@ pub struct AliasTy<'tcx> { pub def_id: DefId, /// This field exists to prevent the creation of `AliasTy` without using - /// [TyCtxt::mk_alias_ty]. - pub(super) _use_mk_alias_ty_instead: (), + /// [AliasTy::new]. + _use_alias_ty_new_instead: (), } impl<'tcx> AliasTy<'tcx> { + pub fn new( + tcx: TyCtxt<'tcx>, + def_id: DefId, + args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>, + ) -> ty::AliasTy<'tcx> { + let args = tcx.check_and_mk_args(def_id, args); + ty::AliasTy { def_id, args, _use_alias_ty_new_instead: () } + } + pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasKind { match tcx.def_kind(self.def_id) { - DefKind::AssocTy if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) => ty::Inherent, + DefKind::AssocTy + if let DefKind::Impl { of_trait: false } = + tcx.def_kind(tcx.parent(self.def_id)) => + { + ty::Inherent + } DefKind::AssocTy => ty::Projection, DefKind::OpaqueTy => ty::Opaque, DefKind::TyAlias => ty::Weak, @@ -1240,7 +1254,7 @@ impl<'tcx> AliasTy<'tcx> { } pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { - tcx.mk_alias_ty(self.def_id, [self_ty.into()].into_iter().chain(self.args.iter().skip(1))) + AliasTy::new(tcx, self.def_id, [self_ty.into()].into_iter().chain(self.args.iter().skip(1))) } } @@ -1662,8 +1676,11 @@ impl<'tcx> ExistentialProjection<'tcx> { debug_assert!(!self_ty.has_escaping_bound_vars()); ty::ProjectionPredicate { - projection_ty: tcx - .mk_alias_ty(self.def_id, [self_ty.into()].into_iter().chain(self.args)), + projection_ty: AliasTy::new( + tcx, + self.def_id, + [self_ty.into()].into_iter().chain(self.args), + ), term: self.term, } } @@ -1966,7 +1983,7 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn new_opaque(tcx: TyCtxt<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>) -> Ty<'tcx> { - Ty::new_alias(tcx, ty::Opaque, tcx.mk_alias_ty(def_id, args)) + Ty::new_alias(tcx, ty::Opaque, AliasTy::new(tcx, def_id, args)) } /// Constructs a `TyKind::Error` type with current `ErrorGuaranteed` @@ -2130,7 +2147,7 @@ impl<'tcx> Ty<'tcx> { item_def_id: DefId, args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>, ) -> Ty<'tcx> { - Ty::new_alias(tcx, ty::Projection, tcx.mk_alias_ty(item_def_id, args)) + Ty::new_alias(tcx, ty::Projection, AliasTy::new(tcx, item_def_id, args)) } #[inline] @@ -2848,7 +2865,7 @@ impl<'tcx> Ty<'tcx> { /// Returning true means the type is known to be pure and `Copy+Clone`. /// Returning `false` means nothing -- could be `Copy`, might not be. /// - /// This is mostly useful for optimizations, as there are the types + /// This is mostly useful for optimizations, as these are the types /// on which we can replace cloning with dereferencing. pub fn is_trivially_pure_clone_copy(self) -> bool { match self.kind() { diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 578d8e7a975..f30993c9a69 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -217,7 +217,8 @@ fn find_item_ty_spans( match ty.kind { hir::TyKind::Path(hir::QPath::Resolved(_, path)) => { if let Res::Def(kind, def_id) = path.res - && !matches!(kind, DefKind::TyAlias) { + && !matches!(kind, DefKind::TyAlias) + { let check_params = def_id.as_local().map_or(true, |def_id| { if def_id == needle { spans.push(ty.span); @@ -227,8 +228,11 @@ fn find_item_ty_spans( if check_params && let Some(args) = path.segments.last().unwrap().args { let params_in_repr = tcx.params_in_repr(def_id); // the domain size check is needed because the HIR may not be well-formed at this point - for (i, arg) in args.args.iter().enumerate().take(params_in_repr.domain_size()) { - if let hir::GenericArg::Type(ty) = arg && params_in_repr.contains(i as u32) { + for (i, arg) in args.args.iter().enumerate().take(params_in_repr.domain_size()) + { + if let hir::GenericArg::Type(ty) = arg + && params_in_repr.contains(i as u32) + { find_item_ty_spans(tcx, ty, needle, spans, seen_representable); } } diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index ce021923f64..db3886b32be 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -173,7 +173,7 @@ mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count -> mir_build_literal_in_range_out_of_bounds = literal out of range for `{$ty}` - .label = this value doesn't fit in `{$ty}` whose maximum value is `{$max}` + .label = this value does not fit into the type `{$ty}` whose range is `{$min}..={$max}` mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper = lower range bound must be less than or equal to upper diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs index e5c2cc6c7bb..a81f70e3346 100644 --- a/compiler/rustc_mir_build/src/build/custom/mod.rs +++ b/compiler/rustc_mir_build/src/build/custom/mod.rs @@ -60,6 +60,7 @@ pub(super) fn build_custom_mir<'tcx>( tainted_by_errors: None, injection_phase: None, pass_count: 0, + function_coverage_info: None, }; body.local_decls.push(LocalDecl::new(return_ty, return_ty_span)); diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index afb65ffbe8c..7d7542a9a6a 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -213,7 +213,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Casting an enum to an integer is equivalent to computing the discriminant and casting the // discriminant. Previously every backend had to repeat the logic for this operation. Now we // create all the steps directly in MIR with operations all backends need to support anyway. - let (source, ty) = if let ty::Adt(adt_def, ..) = source.ty.kind() && adt_def.is_enum() { + let (source, ty) = if let ty::Adt(adt_def, ..) = source.ty.kind() + && adt_def.is_enum() + { let discr_ty = adt_def.repr().discr_type().to_ty(this.tcx); let temp = unpack!(block = this.as_temp(block, scope, source, Mutability::Not)); let layout = this.tcx.layout_of(this.param_env.and(source.ty)); @@ -224,7 +226,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { discr, Rvalue::Discriminant(temp.into()), ); - let (op,ty) = (Operand::Move(discr), discr_ty); + let (op, ty) = (Operand::Move(discr), discr_ty); if let Abi::Scalar(scalar) = layout.unwrap().abi && !scalar.is_always_valid(&this.tcx) @@ -236,27 +238,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, source_info, unsigned_place, - Rvalue::Cast(CastKind::IntToInt, Operand::Copy(discr), unsigned_ty)); + Rvalue::Cast(CastKind::IntToInt, Operand::Copy(discr), unsigned_ty), + ); let bool_ty = this.tcx.types.bool; let range = scalar.valid_range(&this.tcx); let merge_op = - if range.start <= range.end { - BinOp::BitAnd - } else { - BinOp::BitOr - }; + if range.start <= range.end { BinOp::BitAnd } else { BinOp::BitOr }; let mut comparer = |range: u128, bin_op: BinOp| -> Place<'tcx> { - let range_val = - Const::from_bits(this.tcx, range, ty::ParamEnv::empty().and(unsigned_ty)); + let range_val = Const::from_bits( + this.tcx, + range, + ty::ParamEnv::empty().and(unsigned_ty), + ); let lit_op = this.literal_operand(expr.span, range_val); let is_bin_op = this.temp(bool_ty, expr_span); this.cfg.push_assign( block, source_info, is_bin_op, - Rvalue::BinaryOp(bin_op, Box::new((Operand::Copy(unsigned_place), lit_op))), + Rvalue::BinaryOp( + bin_op, + Box::new((Operand::Copy(unsigned_place), lit_op)), + ), ); is_bin_op }; @@ -270,7 +275,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, source_info, merge_place, - Rvalue::BinaryOp(merge_op, Box::new((Operand::Move(start_place), Operand::Move(end_place)))), + Rvalue::BinaryOp( + merge_op, + Box::new(( + Operand::Move(start_place), + Operand::Move(end_place), + )), + ), ); merge_place }; @@ -278,19 +289,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, Statement { source_info, - kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume( - Operand::Move(assert_place), - ))), + kind: StatementKind::Intrinsic(Box::new( + NonDivergingIntrinsic::Assume(Operand::Move(assert_place)), + )), }, ); } - (op,ty) - + (op, ty) } else { let ty = source.ty; let source = unpack!( - block = this.as_operand(block, scope, source, LocalInfo::Boring, NeedsTemporary::No) + block = this.as_operand( + block, + scope, + source, + LocalInfo::Boring, + NeedsTemporary::No + ) ); (source, ty) }; diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs index 396f82c27cd..7beaef602a8 100644 --- a/compiler/rustc_mir_build/src/build/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs @@ -120,32 +120,31 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // // it is usually better to focus on `the_value` rather // than the entirety of block(s) surrounding it. - let adjusted_span = - if let ExprKind::Block { block } = expr.kind - && let Some(tail_ex) = this.thir[block].expr - { - let mut expr = &this.thir[tail_ex]; - loop { - match expr.kind { - ExprKind::Block { block } - if let Some(nested_expr) = this.thir[block].expr => - { - expr = &this.thir[nested_expr]; - } - ExprKind::Scope { value: nested_expr, .. } => { - expr = &this.thir[nested_expr]; - } - _ => break, + let adjusted_span = if let ExprKind::Block { block } = expr.kind + && let Some(tail_ex) = this.thir[block].expr + { + let mut expr = &this.thir[tail_ex]; + loop { + match expr.kind { + ExprKind::Block { block } + if let Some(nested_expr) = this.thir[block].expr => + { + expr = &this.thir[nested_expr]; } + ExprKind::Scope { value: nested_expr, .. } => { + expr = &this.thir[nested_expr]; + } + _ => break, } - this.block_context.push(BlockFrame::TailExpr { - tail_result_is_ignored: true, - span: expr.span, - }); - Some(expr.span) - } else { - None - }; + } + this.block_context.push(BlockFrame::TailExpr { + tail_result_is_ignored: true, + span: expr.span, + }); + Some(expr.span) + } else { + None + }; let temp = unpack!(block = this.as_temp(block, statement_scope, expr, Mutability::Not)); diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index eb1c6a9824a..24c6e0eae36 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -736,7 +736,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) }); // Although there is almost always scope for given variable in corner cases // like #92893 we might get variable with no scope. - if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) && schedule_drop { + if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) + && schedule_drop + { self.schedule_drop(span, region_scope, local_id, DropKind::Storage); } Place::from(local_id) @@ -814,7 +816,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - PatKind::Constant { .. } | PatKind::Range { .. } | PatKind::Wild => {} + PatKind::Constant { .. } + | PatKind::Range { .. } + | PatKind::Wild + | PatKind::Error(_) => {} PatKind::Deref { ref subpattern } => { self.visit_primary_bindings(subpattern, pattern_user_ty.deref(), f); diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 17ac1f4e0ce..f340feb40d4 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -168,7 +168,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Ok(()) } - PatKind::Wild => { + PatKind::Wild | PatKind::Error(_) => { // nothing left to do Ok(()) } diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 795d1db8eec..30ce37a7ac1 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -77,7 +77,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | PatKind::Wild | PatKind::Binding { .. } | PatKind::Leaf { .. } - | PatKind::Deref { .. } => self.error_simplifiable(match_pair), + | PatKind::Deref { .. } + | PatKind::Error(_) => self.error_simplifiable(match_pair), } } @@ -111,7 +112,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | PatKind::Binding { .. } | PatKind::AscribeUserType { .. } | PatKind::Leaf { .. } - | PatKind::Deref { .. } => { + | PatKind::Deref { .. } + | PatKind::Error(_) => { // don't know how to add these patterns to a switch false } @@ -236,18 +238,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TestKind::Eq { value, ty } => { let tcx = self.tcx; - if let ty::Adt(def, _) = ty.kind() && Some(def.did()) == tcx.lang_items().string() { + if let ty::Adt(def, _) = ty.kind() + && Some(def.did()) == tcx.lang_items().string() + { if !tcx.features().string_deref_patterns { - bug!("matching on `String` went through without enabling string_deref_patterns"); + bug!( + "matching on `String` went through without enabling string_deref_patterns" + ); } let re_erased = tcx.lifetimes.re_erased; - let ref_string = self.temp(Ty::new_imm_ref(tcx,re_erased, ty), test.span); - let ref_str_ty = Ty::new_imm_ref(tcx,re_erased, tcx.types.str_); + let ref_string = self.temp(Ty::new_imm_ref(tcx, re_erased, ty), test.span); + let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_); let ref_str = self.temp(ref_str_ty, test.span); let deref = tcx.require_lang_item(LangItem::Deref, None); let method = trait_method(tcx, deref, sym::deref, [ty]); let eq_block = self.cfg.start_new_block(); - self.cfg.push_assign(block, source_info, ref_string, Rvalue::Ref(re_erased, BorrowKind::Shared, place)); + self.cfg.push_assign( + block, + source_info, + ref_string, + Rvalue::Ref(re_erased, BorrowKind::Shared, place), + ); self.cfg.terminate( block, source_info, @@ -262,10 +273,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { target: Some(eq_block), unwind: UnwindAction::Continue, call_source: CallSource::Misc, - fn_span: source_info.span - } + fn_span: source_info.span, + }, + ); + self.non_scalar_compare( + eq_block, + make_target_blocks, + source_info, + value, + ref_str, + ref_str_ty, ); - self.non_scalar_compare(eq_block, make_target_blocks, source_info, value, ref_str, ref_str_ty); return; } if !ty.is_scalar() { diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index bba47056457..d9098bac1c2 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -847,7 +847,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.local_decls.push(LocalDecl::with_source_info(param.ty, source_info)); // If this is a simple binding pattern, give debuginfo a nice name. - if let Some(ref pat) = param.pat && let Some(name) = pat.simple_ident() { + if let Some(ref pat) = param.pat + && let Some(name) = pat.simple_ident() + { self.var_debug_info.push(VarDebugInfo { name, source_info, diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 192bd4a83e3..2d221b826c9 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -224,7 +224,8 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { PatKind::Wild | // these just wrap other patterns PatKind::Or { .. } | - PatKind::AscribeUserType { .. } => {} + PatKind::AscribeUserType { .. } | + PatKind::Error(_) => {} } }; @@ -411,7 +412,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { } ExprKind::Field { lhs, .. } => { let lhs = &self.thir[lhs]; - if let ty::Adt(adt_def, _) = lhs.ty.kind() && adt_def.is_union() { + if let ty::Adt(adt_def, _) = lhs.ty.kind() + && adt_def.is_union() + { if let Some((assigned_ty, assignment_span)) = self.assignment_info { if assigned_ty.needs_drop(self.tcx, self.param_env) { // This would be unsafe, but should be outright impossible since we reject such unions. @@ -460,7 +463,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { } ExprKind::Let { expr: expr_id, .. } => { let let_expr = &self.thir[expr_id]; - if let ty::Adt(adt_def, _) = let_expr.ty.kind() && adt_def.is_union() { + if let ty::Adt(adt_def, _) = let_expr.ty.kind() + && adt_def.is_union() + { self.requires_unsafe(expr.span, AccessToUnionField); } } @@ -616,8 +621,7 @@ impl UnsafeOpKind { && let hir::BlockCheckMode::UnsafeBlock(_) = block.rules { true - } - else if let Some(sig) = tcx.hir().fn_sig_by_hir_id(*id) + } else if let Some(sig) = tcx.hir().fn_sig_by_hir_id(*id) && sig.header.is_unsafe() { true diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index bee5ac550dd..4f98932a88d 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -551,6 +551,7 @@ pub struct LiteralOutOfRange<'tcx> { #[label] pub span: Span, pub ty: Ty<'tcx>, + pub min: i128, pub max: u128, } diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index 94be38beee4..e78274b4284 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -67,16 +67,21 @@ pub fn check_drop_recursion<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let def_id = body.source.def_id().expect_local(); // First check if `body` is an `fn drop()` of `Drop` - if let DefKind::AssocFn = tcx.def_kind(def_id) && - let Some(trait_ref) = tcx.impl_of_method(def_id.to_def_id()).and_then(|def_id| tcx.impl_trait_ref(def_id)) && - let Some(drop_trait) = tcx.lang_items().drop_trait() && drop_trait == trait_ref.instantiate_identity().def_id { - + if let DefKind::AssocFn = tcx.def_kind(def_id) + && let Some(trait_ref) = + tcx.impl_of_method(def_id.to_def_id()).and_then(|def_id| tcx.impl_trait_ref(def_id)) + && let Some(drop_trait) = tcx.lang_items().drop_trait() + && drop_trait == trait_ref.instantiate_identity().def_id + { // It was. Now figure out for what type `Drop` is implemented and then // check for recursion. - if let ty::Ref(_, dropped_ty, _) = tcx.liberate_late_bound_regions( - def_id.to_def_id(), - tcx.fn_sig(def_id).instantiate_identity().input(0), - ).kind() { + if let ty::Ref(_, dropped_ty, _) = tcx + .liberate_late_bound_regions( + def_id.to_def_id(), + tcx.fn_sig(def_id).instantiate_identity().input(0), + ) + .kind() + { check_recursion(tcx, body, RecursiveDrop { drop_for: *dropped_ty }); } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 16a85d42761..0535ea24b82 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -320,17 +320,23 @@ impl<'tcx> Cx<'tcx> { reason: errors::RustcBoxAttrReason::Attributes, }); } else if let Some(box_item) = tcx.lang_items().owned_box() { - if let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, fn_path)) = fun.kind + if let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, fn_path)) = + fun.kind && let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind && path.res.opt_def_id().is_some_and(|did| did == box_item) && fn_path.ident.name == sym::new && let [value] = args { - return Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind: ExprKind::Box { value: self.mirror_expr(value) } } + return Expr { + temp_lifetime, + ty: expr_ty, + span: expr.span, + kind: ExprKind::Box { value: self.mirror_expr(value) }, + }; } else { tcx.sess.emit_err(errors::RustcBoxAttributeError { span: expr.span, - reason: errors::RustcBoxAttrReason::NotBoxNew + reason: errors::RustcBoxAttrReason::NotBoxNew, }); } } else { @@ -343,17 +349,16 @@ impl<'tcx> Cx<'tcx> { // Tuple-like ADTs are represented as ExprKind::Call. We convert them here. let adt_data = if let hir::ExprKind::Path(ref qpath) = fun.kind - && let Some(adt_def) = expr_ty.ty_adt_def() { + && let Some(adt_def) = expr_ty.ty_adt_def() + { match qpath { - hir::QPath::Resolved(_, ref path) => { - match path.res { - Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_id) => { - Some((adt_def, adt_def.variant_index_with_ctor_id(ctor_id))) - } - Res::SelfCtor(..) => Some((adt_def, FIRST_VARIANT)), - _ => None, + hir::QPath::Resolved(_, ref path) => match path.res { + Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_id) => { + Some((adt_def, adt_def.variant_index_with_ctor_id(ctor_id))) } - } + Res::SelfCtor(..) => Some((adt_def, FIRST_VARIANT)), + _ => None, + }, hir::QPath::TypeRelative(_ty, _) => { if let Some((DefKind::Ctor(_, CtorKind::Fn), ctor_id)) = self.typeck_results().type_dependent_def(fun.hir_id) @@ -362,7 +367,6 @@ impl<'tcx> Cx<'tcx> { } else { None } - } _ => None, } diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index d440ca31926..9d38087fdeb 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -168,7 +168,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> { self.lint_level = lint_level; } - if let Some(initializer) = initializer && else_block.is_some() { + if let Some(initializer) = initializer + && else_block.is_some() + { self.check_let(pattern, initializer, LetSource::LetElse, span); } @@ -231,6 +233,10 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { if let LetSource::None = source { return; } + if let Err(err) = pat.pat_error_reported() { + self.error = Err(err); + return; + } self.check_patterns(pat, Refutable); let mut cx = self.new_cx(self.lint_level, true); let tpat = self.lower_pattern(&mut cx, pat); @@ -252,6 +258,10 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { self.with_lint_level(arm.lint_level, |this| { this.check_patterns(&arm.pattern, Refutable); }); + if let Err(err) = arm.pattern.pat_error_reported() { + self.error = Err(err); + return; + } } let tarms: Vec<_> = arms @@ -334,7 +344,8 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { // and record chain members that aren't let exprs. let mut chain_refutabilities = Vec::new(); - let add = |expr: ExprId, mut local_lint_level| { + let mut error = Ok(()); + let mut add = |expr: ExprId, mut local_lint_level| { // `local_lint_level` is the lint level enclosing the pattern inside `expr`. let mut expr = &self.thir[expr]; debug!(?expr, ?local_lint_level, "add"); @@ -348,6 +359,10 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { debug!(?expr, ?local_lint_level, "after scopes"); match expr.kind { ExprKind::Let { box ref pat, expr: _ } => { + if let Err(err) = pat.pat_error_reported() { + error = Err(err); + return None; + } let mut ncx = self.new_cx(local_lint_level, true); let tpat = self.lower_pattern(&mut ncx, pat); let refutable = !is_let_irrefutable(&mut ncx, local_lint_level, tpat); @@ -380,6 +395,11 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { debug!(?chain_refutabilities); chain_refutabilities.reverse(); + if error.is_err() { + self.error = error; + return; + } + // Third, emit the actual warnings. if chain_refutabilities.iter().all(|r| matches!(*r, Some((_, false)))) { // The entire chain is made up of irrefutable `let` statements @@ -393,7 +413,10 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { return; } - if let Some(until) = chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, false)))) && until > 0 { + if let Some(until) = + chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, false)))) + && until > 0 + { // The chain has a non-zero prefix of irrefutable `let` statements. // Check if the let source is while, for there is no alternative place to put a prefix, @@ -409,23 +432,42 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { let span_end = prefix.last().unwrap().unwrap().0; let span = span_start.to(span_end); let count = prefix.len(); - self.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, self.lint_level, span, LeadingIrrefutableLetPatterns { count }); + self.tcx.emit_spanned_lint( + IRREFUTABLE_LET_PATTERNS, + self.lint_level, + span, + LeadingIrrefutableLetPatterns { count }, + ); } } - if let Some(from) = chain_refutabilities.iter().rposition(|r| !matches!(*r, Some((_, false)))) && from != (chain_refutabilities.len() - 1) { + if let Some(from) = + chain_refutabilities.iter().rposition(|r| !matches!(*r, Some((_, false)))) + && from != (chain_refutabilities.len() - 1) + { // The chain has a non-empty suffix of irrefutable `let` statements let suffix = &chain_refutabilities[from + 1..]; let span_start = suffix[0].unwrap().0; let span_end = suffix.last().unwrap().unwrap().0; let span = span_start.to(span_end); let count = suffix.len(); - self.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, self.lint_level, span, TrailingIrrefutableLetPatterns { count }); + self.tcx.emit_spanned_lint( + IRREFUTABLE_LET_PATTERNS, + self.lint_level, + span, + TrailingIrrefutableLetPatterns { count }, + ); } } #[instrument(level = "trace", skip(self))] fn check_irrefutable(&mut self, pat: &Pat<'tcx>, origin: &str, sp: Option<Span>) { + // If we got errors while lowering, don't emit anything more. + if let Err(err) = pat.pat_error_reported() { + self.error = Err(err); + return; + } + let mut cx = self.new_cx(self.lint_level, false); let pattern = self.lower_pattern(&mut cx, pat); @@ -448,23 +490,21 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { let mut interpreted_as_const = None; if let PatKind::Constant { .. } - | PatKind::AscribeUserType { - subpattern: box Pat { kind: PatKind::Constant { .. }, .. }, - .. - } = pat.kind + | PatKind::AscribeUserType { + subpattern: box Pat { kind: PatKind::Constant { .. }, .. }, + .. + } = pat.kind && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span) { // If the pattern to match is an integer literal: if snippet.chars().all(|c| c.is_digit(10)) { // Then give a suggestion, the user might've meant to create a binding instead. misc_suggestion = Some(MiscPatternSuggestion::AttemptedIntegerLiteral { - start_span: pat.span.shrink_to_lo() + start_span: pat.span.shrink_to_lo(), }); } else if snippet.chars().all(|c| c.is_alphanumeric() || c == '_') { - interpreted_as_const = Some(InterpretedAsConst { - span: pat.span, - variable: snippet, - }); + interpreted_as_const = + Some(InterpretedAsConst { span: pat.span, variable: snippet }); } } @@ -501,20 +541,19 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { // Emit an extra note if the first uncovered witness would be uninhabited // if we disregard visibility. - let witness_1_is_privately_uninhabited = - if cx.tcx.features().exhaustive_patterns - && let Some(witness_1) = witnesses.get(0) - && let ty::Adt(adt, args) = witness_1.ty().kind() - && adt.is_enum() - && let Constructor::Variant(variant_index) = witness_1.ctor() - { - let variant = adt.variant(*variant_index); - let inhabited = variant.inhabited_predicate(cx.tcx, *adt).instantiate(cx.tcx, args); - assert!(inhabited.apply(cx.tcx, cx.param_env, cx.module)); - !inhabited.apply_ignore_module(cx.tcx, cx.param_env) - } else { - false - }; + let witness_1_is_privately_uninhabited = if cx.tcx.features().exhaustive_patterns + && let Some(witness_1) = witnesses.get(0) + && let ty::Adt(adt, args) = witness_1.ty().kind() + && adt.is_enum() + && let Constructor::Variant(variant_index) = witness_1.ctor() + { + let variant = adt.variant(*variant_index); + let inhabited = variant.inhabited_predicate(cx.tcx, *adt).instantiate(cx.tcx, args); + assert!(inhabited.apply(cx.tcx, cx.param_env, cx.module)); + !inhabited.apply_ignore_module(cx.tcx, cx.param_env) + } else { + false + }; self.error = Err(self.tcx.sess.emit_err(PatternNotCovered { span: pat.span, @@ -539,23 +578,22 @@ fn check_for_bindings_named_same_as_variants( ) { pat.walk_always(|p| { if let PatKind::Binding { - name, - mode: BindingMode::ByValue, - mutability: Mutability::Not, - subpattern: None, - ty, - .. - } = p.kind + name, + mode: BindingMode::ByValue, + mutability: Mutability::Not, + subpattern: None, + ty, + .. + } = p.kind && let ty::Adt(edef, _) = ty.peel_refs().kind() && edef.is_enum() - && edef.variants().iter().any(|variant| { - variant.name == name && variant.ctor_kind() == Some(CtorKind::Const) - }) + && edef + .variants() + .iter() + .any(|variant| variant.name == name && variant.ctor_kind() == Some(CtorKind::Const)) { let variant_count = edef.variants().len(); - let ty_path = with_no_trimmed_paths!({ - cx.tcx.def_path_str(edef.did()) - }); + let ty_path = with_no_trimmed_paths!(cx.tcx.def_path_str(edef.did())); cx.tcx.emit_spanned_lint( BINDINGS_WITH_VARIANT_NAME, cx.lint_level, @@ -566,7 +604,9 @@ fn check_for_bindings_named_same_as_variants( // suggestion would produce code that breaks on `check_irrefutable`. suggestion: if rf == Refutable || variant_count == 1 { Some(p.span) - } else { None }, + } else { + None + }, ty_path, name, }, @@ -770,8 +810,10 @@ fn non_exhaustive_match<'p, 'tcx>( } [only] => { let only = &thir[*only]; - let (pre_indentation, is_multiline) = if let Some(snippet) = sm.indentation_before(only.span) - && let Ok(with_trailing) = sm.span_extend_while(only.span, |c| c.is_whitespace() || c == ',') + let (pre_indentation, is_multiline) = if let Some(snippet) = + sm.indentation_before(only.span) + && let Ok(with_trailing) = + sm.span_extend_while(only.span, |c| c.is_whitespace() || c == ',') && sm.is_multiline(with_trailing) { (format!("\n{snippet}"), true) @@ -922,7 +964,9 @@ fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>( let mut covered = vec![]; for pattern in patterns { if let Variant(variant_index) = pattern.ctor() { - if let ty::Adt(this_def, _) = pattern.ty().kind() && this_def.did() != def.did() { + if let ty::Adt(this_def, _) = pattern.ty().kind() + && this_def.did() != def.did() + { continue; } let sp = def.variant(*variant_index).ident(cx.tcx).span; 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 ae442466029..fc03f7891a8 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 @@ -7,7 +7,7 @@ use rustc_middle::mir; use rustc_middle::thir::{FieldPat, Pat, PatKind}; use rustc_middle::ty::{self, Ty, TyCtxt, ValTree}; use rustc_session::lint; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCause}; @@ -48,7 +48,7 @@ struct ConstToPat<'tcx> { // This tracks if we emitted some hard error for a given const value, so that // we will not subsequently issue an irrelevant lint for the same const // value. - saw_const_match_error: Cell<bool>, + saw_const_match_error: Cell<Option<ErrorGuaranteed>>, // This tracks if we emitted some diagnostic for a given const value, so that // we will not subsequently issue an irrelevant lint for the same const @@ -84,7 +84,7 @@ impl<'tcx> ConstToPat<'tcx> { span, infcx, param_env: pat_ctxt.param_env, - saw_const_match_error: Cell::new(false), + saw_const_match_error: Cell::new(None), saw_const_match_lint: Cell::new(false), behind_reference: Cell::new(false), treat_byte_string_as_slice: pat_ctxt @@ -154,7 +154,7 @@ impl<'tcx> ConstToPat<'tcx> { }), }; - if !self.saw_const_match_error.get() { + if self.saw_const_match_error.get().is_none() { // If we were able to successfully convert the const to some pat (possibly with some // lints, but no errors), double-check that all types in the const implement // `Structural` and `PartialEq`. @@ -180,23 +180,32 @@ impl<'tcx> ConstToPat<'tcx> { if let Some(non_sm_ty) = structural { if !self.type_has_partial_eq_impl(cv.ty()) { - if let ty::Adt(def, ..) = non_sm_ty.kind() { + let e = if let ty::Adt(def, ..) = non_sm_ty.kind() { if def.is_union() { let err = UnionPattern { span: self.span }; - self.tcx().sess.emit_err(err); + self.tcx().sess.emit_err(err) } else { // fatal avoids ICE from resolution of nonexistent method (rare case). self.tcx() .sess - .emit_fatal(TypeNotStructural { span: self.span, non_sm_ty }); + .emit_fatal(TypeNotStructural { span: self.span, non_sm_ty }) } } else { let err = InvalidPattern { span: self.span, non_sm_ty }; - self.tcx().sess.emit_err(err); - } + self.tcx().sess.emit_err(err) + }; // All branches above emitted an error. Don't print any more lints. - // The pattern we return is irrelevant since we errored. - return Box::new(Pat { span: self.span, ty: cv.ty(), kind: PatKind::Wild }); + // We errored. Signal that in the pattern, so that follow up errors can be silenced. + let kind = PatKind::Error(e); + return Box::new(Pat { span: self.span, ty: cv.ty(), kind }); + } else if let ty::Adt(..) = cv.ty().kind() && matches!(cv, mir::Const::Val(..)) { + // This branch is only entered when the current `cv` is `mir::Const::Val`. + // This is because `mir::Const::ty` has already been handled by `Self::recur` + // and the invalid types may be ignored. + let err = TypeNotStructural { span: self.span, non_sm_ty }; + let e = self.tcx().sess.emit_err(err); + let kind = PatKind::Error(e); + return Box::new(Pat { span: self.span, ty: cv.ty(), kind }); } else if !self.saw_const_match_lint.get() { if let Some(mir_structural_match_violation) = mir_structural_match_violation { match non_sm_ty.kind() { @@ -330,7 +339,7 @@ impl<'tcx> ConstToPat<'tcx> { // Backwards compatibility hack because we can't cause hard errors on these // types, so we compare them via `PartialEq::eq` at runtime. ty::Adt(..) if !self.type_marked_structural(ty) && self.behind_reference.get() => { - if !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() { + if self.saw_const_match_error.get().is_none() && !self.saw_const_match_lint.get() { self.saw_const_match_lint.set(true); tcx.emit_spanned_lint( lint::builtin::INDIRECT_STRUCTURAL_MATCH, @@ -345,18 +354,18 @@ impl<'tcx> ConstToPat<'tcx> { return Err(FallbackToOpaqueConst); } ty::FnDef(..) => { - self.saw_const_match_error.set(true); - tcx.sess.emit_err(InvalidPattern { span, non_sm_ty: ty }); - // We errored, so the pattern we generate is irrelevant. - PatKind::Wild + let e = tcx.sess.emit_err(InvalidPattern { span, non_sm_ty: ty }); + self.saw_const_match_error.set(Some(e)); + // We errored. Signal that in the pattern, so that follow up errors can be silenced. + PatKind::Error(e) } ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => { debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty,); - self.saw_const_match_error.set(true); let err = TypeNotStructural { span, non_sm_ty: ty }; - tcx.sess.emit_err(err); - // We errored, so the pattern we generate is irrelevant. - PatKind::Wild + let e = tcx.sess.emit_err(err); + self.saw_const_match_error.set(Some(e)); + // We errored. Signal that in the pattern, so that follow up errors can be silenced. + PatKind::Error(e) } ty::Adt(adt_def, args) if adt_def.is_enum() => { let (&variant_index, fields) = cv.unwrap_branch().split_first().unwrap(); @@ -416,7 +425,9 @@ impl<'tcx> ConstToPat<'tcx> { // instead of a hard error. ty::Adt(_, _) if !self.type_marked_structural(*pointee_ty) => { if self.behind_reference.get() { - if !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() { + if self.saw_const_match_error.get().is_none() + && !self.saw_const_match_lint.get() + { self.saw_const_match_lint.set(true); tcx.emit_spanned_lint( lint::builtin::INDIRECT_STRUCTURAL_MATCH, @@ -427,14 +438,16 @@ impl<'tcx> ConstToPat<'tcx> { } return Err(FallbackToOpaqueConst); } else { - if !self.saw_const_match_error.get() { - self.saw_const_match_error.set(true); + if let Some(e) = self.saw_const_match_error.get() { + // We already errored. Signal that in the pattern, so that follow up errors can be silenced. + PatKind::Error(e) + } else { let err = TypeNotStructural { span, non_sm_ty: *pointee_ty }; - tcx.sess.emit_err(err); + let e = tcx.sess.emit_err(err); + self.saw_const_match_error.set(Some(e)); + // We errored. Signal that in the pattern, so that follow up errors can be silenced. + PatKind::Error(e) } - tcx.sess.delay_span_bug(span, "`saw_const_match_error` set but no error?"); - // We errored, so the pattern we generate is irrelevant. - PatKind::Wild } } // All other references are converted into deref patterns and then recursively @@ -443,11 +456,9 @@ impl<'tcx> ConstToPat<'tcx> { _ => { if !pointee_ty.is_sized(tcx, param_env) && !pointee_ty.is_slice() { let err = UnsizedPattern { span, non_sm_ty: *pointee_ty }; - tcx.sess.emit_err(err); - - // FIXME: introduce PatKind::Error to silence follow up diagnostics due to unreachable patterns. - // We errored, so the pattern we generate is irrelevant. - PatKind::Wild + let e = tcx.sess.emit_err(err); + // We errored. Signal that in the pattern, so that follow up errors can be silenced. + PatKind::Error(e) } else { let old = self.behind_reference.replace(true); // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when @@ -474,15 +485,15 @@ impl<'tcx> ConstToPat<'tcx> { } ty::FnPtr(..) | ty::RawPtr(..) => unreachable!(), _ => { - self.saw_const_match_error.set(true); let err = InvalidPattern { span, non_sm_ty: ty }; - tcx.sess.emit_err(err); - // We errored, so the pattern we generate is irrelevant. - PatKind::Wild + let e = tcx.sess.emit_err(err); + self.saw_const_match_error.set(Some(e)); + // We errored. Signal that in the pattern, so that follow up errors can be silenced. + PatKind::Error(e) } }; - if !self.saw_const_match_error.get() + if self.saw_const_match_error.get().is_none() && !self.saw_const_match_lint.get() && mir_structural_match_violation // FIXME(#73448): Find a way to bring const qualification into parity with @@ -497,7 +508,7 @@ impl<'tcx> ConstToPat<'tcx> { lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH, id, span, - NontrivialStructuralMatch {non_sm_ty} + NontrivialStructuralMatch { non_sm_ty }, ); } diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 3ee4befa121..bbc0aeb66cf 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -39,8 +39,8 @@ //! //! Splitting is implemented in the [`Constructor::split`] function. We don't do splitting for //! or-patterns; instead we just try the alternatives one-by-one. For details on splitting -//! wildcards, see [`SplitWildcard`]; for integer ranges, see [`SplitIntRange`]; for slices, see -//! [`SplitVarLenSlice`]. +//! wildcards, see [`Constructor::split`]; for integer ranges, see +//! [`IntRange::split`]; for slices, see [`Slice::split`]. use std::cell::Cell; use std::cmp::{self, max, min, Ordering}; @@ -52,6 +52,7 @@ use smallvec::{smallvec, SmallVec}; use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS}; use rustc_data_structures::captures::Captures; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::{HirId, RangeEnd}; use rustc_index::Idx; use rustc_middle::middle::stability::EvalResult; @@ -86,6 +87,13 @@ fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> { pats } +/// Whether we have seen a constructor in the column or not. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +enum Presence { + Unseen, + Seen, +} + /// An inclusive interval, used for precise integer exhaustiveness checking. /// `IntRange`s always store a contiguous range. This means that values are /// encoded such that `0` encodes the minimum value for the integer, @@ -186,7 +194,105 @@ impl IntRange { (lo == other_hi || hi == other_lo) && !self.is_singleton() && !other.is_singleton() } - /// Only used for displaying the range properly. + /// Partition a range of integers into disjoint subranges. This does constructor splitting for + /// integer ranges as explained at the top of the file. + /// + /// This returns an output that covers `self`. The output is split so that the only + /// intersections between an output range and a column range are inclusions. No output range + /// straddles the boundary of one of the inputs. + /// + /// Additionally, we track for each output range whether it is covered by one of the column ranges or not. + /// + /// The following input: + /// ```text + /// (--------------------------) // `self` + /// (------) (----------) (-) + /// (------) (--------) + /// ``` + /// is first intersected with `self`: + /// ```text + /// (--------------------------) // `self` + /// (----) (----------) (-) + /// (------) (--------) + /// ``` + /// and then iterated over as follows: + /// ```text + /// (-(--)-(-)-(------)-)--(-)- + /// ``` + /// where each sequence of dashes is an output range, and dashes outside parentheses are marked + /// as `Presence::Missing`. + fn split( + &self, + column_ranges: impl Iterator<Item = IntRange>, + ) -> impl Iterator<Item = (Presence, IntRange)> { + /// Represents a boundary between 2 integers. Because the intervals spanning boundaries must be + /// able to cover every integer, we need to be able to represent 2^128 + 1 such boundaries. + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] + enum IntBoundary { + JustBefore(u128), + AfterMax, + } + + fn unpack_intrange(range: IntRange) -> [IntBoundary; 2] { + use IntBoundary::*; + let (lo, hi) = range.boundaries(); + let lo = JustBefore(lo); + let hi = match hi.checked_add(1) { + Some(m) => JustBefore(m), + None => AfterMax, + }; + [lo, hi] + } + + // The boundaries of ranges in `column_ranges` intersected with `self`. + // We do parenthesis matching for input ranges. A boundary counts as +1 if it starts + // a range and -1 if it ends it. When the count is > 0 between two boundaries, we + // are within an input range. + let mut boundaries: Vec<(IntBoundary, isize)> = column_ranges + .filter_map(|r| self.intersection(&r)) + .map(unpack_intrange) + .flat_map(|[lo, hi]| [(lo, 1), (hi, -1)]) + .collect(); + // We sort by boundary, and for each boundary we sort the "closing parentheses" first. The + // order of +1/-1 for a same boundary value is actually irrelevant, because we only look at + // the accumulated count between distinct boundary values. + boundaries.sort_unstable(); + + let [self_start, self_end] = unpack_intrange(self.clone()); + // Accumulate parenthesis counts. + let mut paren_counter = 0isize; + // Gather pairs of adjacent boundaries. + let mut prev_bdy = self_start; + boundaries + .into_iter() + // End with the end of the range. The count is ignored. + .chain(once((self_end, 0))) + // List pairs of adjacent boundaries and the count between them. + .map(move |(bdy, delta)| { + // `delta` affects the count as we cross `bdy`, so the relevant count between + // `prev_bdy` and `bdy` is untouched by `delta`. + let ret = (prev_bdy, paren_counter, bdy); + prev_bdy = bdy; + paren_counter += delta; + ret + }) + // Skip empty ranges. + .filter(|&(prev_bdy, _, bdy)| prev_bdy != bdy) + // Convert back to ranges. + .map(move |(prev_bdy, paren_count, bdy)| { + use IntBoundary::*; + use Presence::*; + let presence = if paren_count > 0 { Seen } else { Unseen }; + let range = match (prev_bdy, bdy) { + (JustBefore(n), JustBefore(m)) if n < m => n..=(m - 1), + (JustBefore(n), AfterMax) => n..=u128::MAX, + _ => unreachable!(), // Ruled out by the sorting and filtering we did + }; + (presence, IntRange { range }) + }) + } + + /// Only used for displaying the range. fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> { let (lo, hi) = self.boundaries(); @@ -254,18 +360,6 @@ impl IntRange { ); } } - - /// See `Constructor::is_covered_by` - fn is_covered_by(&self, other: &Self) -> bool { - if self.intersection(other).is_some() { - // Constructor splitting should ensure that all intersections we encounter are actually - // inclusions. - assert!(self.is_subrange(other)); - true - } else { - false - } - } } /// Note: this is often not what we want: e.g. `false` is converted into the range `0..=0` and @@ -279,101 +373,6 @@ impl fmt::Debug for IntRange { } } -/// Represents a border between 2 integers. Because the intervals spanning borders must be able to -/// cover every integer, we need to be able to represent 2^128 + 1 such borders. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -enum IntBorder { - JustBefore(u128), - AfterMax, -} - -/// A range of integers that is partitioned into disjoint subranges. This does constructor -/// splitting for integer ranges as explained at the top of the file. -/// -/// This is fed multiple ranges, and returns an output that covers the input, but is split so that -/// the only intersections between an output range and a seen range are inclusions. No output range -/// straddles the boundary of one of the inputs. -/// -/// The following input: -/// ```text -/// |-------------------------| // `self` -/// |------| |----------| |----| -/// |-------| |-------| -/// ``` -/// would be iterated over as follows: -/// ```text -/// ||---|--||-|---|---|---|--| -/// ``` -#[derive(Debug, Clone)] -struct SplitIntRange { - /// The range we are splitting - range: IntRange, - /// The borders of ranges we have seen. They are all contained within `range`. This is kept - /// sorted. - borders: Vec<IntBorder>, -} - -impl SplitIntRange { - fn new(range: IntRange) -> Self { - SplitIntRange { range, borders: Vec::new() } - } - - /// Internal use - fn to_borders(r: IntRange) -> [IntBorder; 2] { - use IntBorder::*; - let (lo, hi) = r.boundaries(); - let lo = JustBefore(lo); - let hi = match hi.checked_add(1) { - Some(m) => JustBefore(m), - None => AfterMax, - }; - [lo, hi] - } - - /// Add ranges relative to which we split. - fn split(&mut self, ranges: impl Iterator<Item = IntRange>) { - let this_range = &self.range; - let included_ranges = ranges.filter_map(|r| this_range.intersection(&r)); - let included_borders = included_ranges.flat_map(|r| { - let borders = Self::to_borders(r); - once(borders[0]).chain(once(borders[1])) - }); - self.borders.extend(included_borders); - self.borders.sort_unstable(); - } - - /// Iterate over the contained ranges. - fn iter(&self) -> impl Iterator<Item = IntRange> + Captures<'_> { - use IntBorder::*; - - let self_range = Self::to_borders(self.range.clone()); - // Start with the start of the range. - let mut prev_border = self_range[0]; - self.borders - .iter() - .copied() - // End with the end of the range. - .chain(once(self_range[1])) - // List pairs of adjacent borders. - .map(move |border| { - let ret = (prev_border, border); - prev_border = border; - ret - }) - // Skip duplicates. - .filter(|(prev_border, border)| prev_border != border) - // Finally, convert to ranges. - .map(move |(prev_border, border)| { - let range = match (prev_border, border) { - (JustBefore(n), JustBefore(m)) if n < m => n..=(m - 1), - (JustBefore(n), AfterMax) => n..=u128::MAX, - _ => unreachable!(), // Ruled out by the sorting and filtering we did - }; - IntRange { range } - }) - } -} - #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum SliceKind { /// Patterns of length `n` (`[x, y]`). @@ -430,142 +429,164 @@ impl Slice { fn is_covered_by(self, other: Self) -> bool { other.kind.covers_length(self.arity()) } -} - -/// This computes constructor splitting for variable-length slices, as explained at the top of the -/// file. -/// -/// A slice pattern `[x, .., y]` behaves like the infinite or-pattern `[x, y] | [x, _, y] | [x, _, -/// _, y] | ...`. The corresponding value constructors are fixed-length array constructors above a -/// given minimum length. We obviously can't list this infinitude of constructors. Thankfully, -/// it turns out that for each finite set of slice patterns, all sufficiently large array lengths -/// are equivalent. -/// -/// Let's look at an example, where we are trying to split the last pattern: -/// ``` -/// # fn foo(x: &[bool]) { -/// match x { -/// [true, true, ..] => {} -/// [.., false, false] => {} -/// [..] => {} -/// } -/// # } -/// ``` -/// Here are the results of specialization for the first few lengths: -/// ``` -/// # fn foo(x: &[bool]) { match x { -/// // length 0 -/// [] => {} -/// // length 1 -/// [_] => {} -/// // length 2 -/// [true, true] => {} -/// [false, false] => {} -/// [_, _] => {} -/// // length 3 -/// [true, true, _ ] => {} -/// [_, false, false] => {} -/// [_, _, _ ] => {} -/// // length 4 -/// [true, true, _, _ ] => {} -/// [_, _, false, false] => {} -/// [_, _, _, _ ] => {} -/// // length 5 -/// [true, true, _, _, _ ] => {} -/// [_, _, _, false, false] => {} -/// [_, _, _, _, _ ] => {} -/// # _ => {} -/// # }} -/// ``` -/// -/// If we went above length 5, we would simply be inserting more columns full of wildcards in the -/// middle. This means that the set of witnesses for length `l >= 5` if equivalent to the set for -/// any other `l' >= 5`: simply add or remove wildcards in the middle to convert between them. -/// -/// This applies to any set of slice patterns: there will be a length `L` above which all lengths -/// behave the same. This is exactly what we need for constructor splitting. Therefore a -/// variable-length slice can be split into a variable-length slice of minimal length `L`, and many -/// fixed-length slices of lengths `< L`. -/// -/// For each variable-length pattern `p` with a prefix of length `plₚ` and suffix of length `slₚ`, -/// only the first `plₚ` and the last `slₚ` elements are examined. Therefore, as long as `L` is -/// positive (to avoid concerns about empty types), all elements after the maximum prefix length -/// and before the maximum suffix length are not examined by any variable-length pattern, and -/// therefore can be added/removed without affecting them - creating equivalent patterns from any -/// sufficiently-large length. -/// -/// Of course, if fixed-length patterns exist, we must be sure that our length is large enough to -/// miss them all, so we can pick `L = max(max(FIXED_LEN)+1, max(PREFIX_LEN) + max(SUFFIX_LEN))` -/// -/// `max_slice` below will be made to have arity `L`. -#[derive(Debug)] -struct SplitVarLenSlice { - /// If the type is an array, this is its size. - array_len: Option<usize>, - /// The arity of the input slice. - arity: usize, - /// The smallest slice bigger than any slice seen. `max_slice.arity()` is the length `L` - /// described above. - max_slice: SliceKind, -} - -impl SplitVarLenSlice { - fn new(prefix: usize, suffix: usize, array_len: Option<usize>) -> Self { - SplitVarLenSlice { array_len, arity: prefix + suffix, max_slice: VarLen(prefix, suffix) } - } - /// Pass a set of slices relative to which to split this one. - fn split(&mut self, slices: impl Iterator<Item = SliceKind>) { - let VarLen(max_prefix_len, max_suffix_len) = &mut self.max_slice else { - // No need to split - return; - }; - // We grow `self.max_slice` to be larger than all slices encountered, as described above. - // For diagnostics, we keep the prefix and suffix lengths separate, but grow them so that - // `L = max_prefix_len + max_suffix_len`. - let mut max_fixed_len = 0; - for slice in slices { - match slice { - FixedLen(len) => { - max_fixed_len = cmp::max(max_fixed_len, len); + /// This computes constructor splitting for variable-length slices, as explained at the top of + /// the file. + /// + /// A slice pattern `[x, .., y]` behaves like the infinite or-pattern `[x, y] | [x, _, y] | [x, + /// _, _, y] | etc`. The corresponding value constructors are fixed-length array constructors of + /// corresponding lengths. We obviously can't list this infinitude of constructors. + /// Thankfully, it turns out that for each finite set of slice patterns, all sufficiently large + /// array lengths are equivalent. + /// + /// Let's look at an example, where we are trying to split the last pattern: + /// ``` + /// # fn foo(x: &[bool]) { + /// match x { + /// [true, true, ..] => {} + /// [.., false, false] => {} + /// [..] => {} + /// } + /// # } + /// ``` + /// Here are the results of specialization for the first few lengths: + /// ``` + /// # fn foo(x: &[bool]) { match x { + /// // length 0 + /// [] => {} + /// // length 1 + /// [_] => {} + /// // length 2 + /// [true, true] => {} + /// [false, false] => {} + /// [_, _] => {} + /// // length 3 + /// [true, true, _ ] => {} + /// [_, false, false] => {} + /// [_, _, _ ] => {} + /// // length 4 + /// [true, true, _, _ ] => {} + /// [_, _, false, false] => {} + /// [_, _, _, _ ] => {} + /// // length 5 + /// [true, true, _, _, _ ] => {} + /// [_, _, _, false, false] => {} + /// [_, _, _, _, _ ] => {} + /// # _ => {} + /// # }} + /// ``` + /// + /// We see that above length 4, we are simply inserting columns full of wildcards in the middle. + /// This means that specialization and witness computation with slices of length `l >= 4` will + /// give equivalent results regardless of `l`. This applies to any set of slice patterns: there + /// will be a length `L` above which all lengths behave the same. This is exactly what we need + /// for constructor splitting. + /// + /// A variable-length slice pattern covers all lengths from its arity up to infinity. As we just + /// saw, we can split this in two: lengths below `L` are treated individually with a + /// fixed-length slice each; lengths above `L` are grouped into a single variable-length slice + /// constructor. + /// + /// For each variable-length slice pattern `p` with a prefix of length `plₚ` and suffix of + /// length `slₚ`, only the first `plₚ` and the last `slₚ` elements are examined. Therefore, as + /// long as `L` is positive (to avoid concerns about empty types), all elements after the + /// maximum prefix length and before the maximum suffix length are not examined by any + /// variable-length pattern, and therefore can be ignored. This gives us a way to compute `L`. + /// + /// Additionally, if fixed-length patterns exist, we must pick an `L` large enough to miss them, + /// so we can pick `L = max(max(FIXED_LEN)+1, max(PREFIX_LEN) + max(SUFFIX_LEN))`. + /// `max_slice` below will be made to have this arity `L`. + /// + /// If `self` is fixed-length, it is returned as-is. + /// + /// Additionally, we track for each output slice whether it is covered by one of the column slices or not. + fn split( + self, + column_slices: impl Iterator<Item = Slice>, + ) -> impl Iterator<Item = (Presence, Slice)> { + // Range of lengths below `L`. + let smaller_lengths; + let arity = self.arity(); + let mut max_slice = self.kind; + // Tracks the smallest variable-length slice we've seen. Any slice arity above it is + // therefore `Presence::Seen` in the column. + let mut min_var_len = usize::MAX; + // Tracks the fixed-length slices we've seen, to mark them as `Presence::Seen`. + let mut seen_fixed_lens = FxHashSet::default(); + match &mut max_slice { + VarLen(max_prefix_len, max_suffix_len) => { + // We grow `max_slice` to be larger than all slices encountered, as described above. + // For diagnostics, we keep the prefix and suffix lengths separate, but grow them so that + // `L = max_prefix_len + max_suffix_len`. + let mut max_fixed_len = 0; + for slice in column_slices { + match slice.kind { + FixedLen(len) => { + max_fixed_len = cmp::max(max_fixed_len, len); + if arity <= len { + seen_fixed_lens.insert(len); + } + } + VarLen(prefix, suffix) => { + *max_prefix_len = cmp::max(*max_prefix_len, prefix); + *max_suffix_len = cmp::max(*max_suffix_len, suffix); + min_var_len = cmp::min(min_var_len, prefix + suffix); + } + } } - VarLen(prefix, suffix) => { - *max_prefix_len = cmp::max(*max_prefix_len, prefix); - *max_suffix_len = cmp::max(*max_suffix_len, suffix); + // We want `L = max(L, max_fixed_len + 1)`, modulo the fact that we keep prefix and + // suffix separate. + if max_fixed_len + 1 >= *max_prefix_len + *max_suffix_len { + // The subtraction can't overflow thanks to the above check. + // The new `max_prefix_len` is larger than its previous value. + *max_prefix_len = max_fixed_len + 1 - *max_suffix_len; } - } - } - // We want `L = max(L, max_fixed_len + 1)`, modulo the fact that we keep prefix and - // suffix separate. - if max_fixed_len + 1 >= *max_prefix_len + *max_suffix_len { - // The subtraction can't overflow thanks to the above check. - // The new `max_prefix_len` is larger than its previous value. - *max_prefix_len = max_fixed_len + 1 - *max_suffix_len; - } - // We cap the arity of `max_slice` at the array size. - match self.array_len { - Some(len) if self.max_slice.arity() >= len => self.max_slice = FixedLen(len), - _ => {} - } - } + // We cap the arity of `max_slice` at the array size. + match self.array_len { + Some(len) if max_slice.arity() >= len => max_slice = FixedLen(len), + _ => {} + } - /// Iterate over the partition of this slice. - fn iter(&self) -> impl Iterator<Item = Slice> + Captures<'_> { - let smaller_lengths = match self.array_len { - // The only admissible fixed-length slice is one of the array size. Whether `max_slice` - // is fixed-length or variable-length, it will be the only relevant slice to output - // here. - Some(_) => 0..0, // empty range - // We cover all arities in the range `(self.arity..infinity)`. We split that range into - // two: lengths smaller than `max_slice.arity()` are treated independently as - // fixed-lengths slices, and lengths above are captured by `max_slice`. - None => self.arity..self.max_slice.arity(), + smaller_lengths = match self.array_len { + // The only admissible fixed-length slice is one of the array size. Whether `max_slice` + // is fixed-length or variable-length, it will be the only relevant slice to output + // here. + Some(_) => 0..0, // empty range + // We need to cover all arities in the range `(arity..infinity)`. We split that + // range into two: lengths smaller than `max_slice.arity()` are treated + // independently as fixed-lengths slices, and lengths above are captured by + // `max_slice`. + None => self.arity()..max_slice.arity(), + }; + } + FixedLen(_) => { + // No need to split here. We only track presence. + for slice in column_slices { + match slice.kind { + FixedLen(len) => { + if len == arity { + seen_fixed_lens.insert(len); + } + } + VarLen(prefix, suffix) => { + min_var_len = cmp::min(min_var_len, prefix + suffix); + } + } + } + smaller_lengths = 0..0; + } }; - smaller_lengths - .map(FixedLen) - .chain(once(self.max_slice)) - .map(move |kind| Slice::new(self.array_len, kind)) + + smaller_lengths.map(FixedLen).chain(once(max_slice)).map(move |kind| { + let arity = kind.arity(); + let seen = if min_var_len <= arity || seen_fixed_lens.contains(&arity) { + Presence::Seen + } else { + Presence::Unseen + }; + (seen, Slice::new(self.array_len, kind)) + }) } } @@ -596,19 +617,23 @@ pub(super) enum Constructor<'tcx> { /// boxes for the purposes of exhaustiveness: we must not inspect them, and they /// don't count towards making a match exhaustive. Opaque, + /// Or-pattern. + Or, + /// Wildcard pattern. + Wildcard, /// Fake extra constructor for enums that aren't allowed to be matched exhaustively. Also used /// for those types for which we cannot list constructors explicitly, like `f64` and `str`. NonExhaustive, - /// Stands for constructors that are not seen in the matrix, as explained in the documentation - /// for [`SplitWildcard`]. The carried `bool` is used for the `non_exhaustive_omitted_patterns` - /// lint. + /// Fake extra constructor for variants that should not be mentioned in diagnostics. + /// We use this for variants behind an unstable gate as well as + /// `#[doc(hidden)]` ones. + Hidden, + /// Fake extra constructor for constructors that are not seen in the matrix, as explained in the + /// code for [`Constructor::split`]. The carried `bool` is used for the + /// `non_exhaustive_omitted_patterns` lint. Missing { - nonexhaustive_enum_missing_real_variants: bool, + nonexhaustive_enum_missing_visible_variants: bool, }, - /// Wildcard pattern. - Wildcard, - /// Or-pattern. - Or, } impl<'tcx> Constructor<'tcx> { @@ -620,13 +645,18 @@ impl<'tcx> Constructor<'tcx> { matches!(self, NonExhaustive) } + pub(super) fn as_variant(&self) -> Option<VariantIdx> { + match self { + Variant(i) => Some(*i), + _ => None, + } + } fn as_int_range(&self) -> Option<&IntRange> { match self { IntRange(range) => Some(range), _ => None, } } - fn as_slice(&self) -> Option<Slice> { match self { Slice(slice) => Some(*slice), @@ -634,32 +664,6 @@ impl<'tcx> Constructor<'tcx> { } } - /// Checks if the `Constructor` is a variant and `TyCtxt::eval_stability` returns - /// `EvalResult::Deny { .. }`. - /// - /// This means that the variant has a stdlib unstable feature marking it. - pub(super) fn is_unstable_variant(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> bool { - if let Constructor::Variant(idx) = self && let ty::Adt(adt, _) = pcx.ty.kind() { - let variant_def_id = adt.variant(*idx).def_id; - // Filter variants that depend on a disabled unstable feature. - return matches!( - pcx.cx.tcx.eval_stability(variant_def_id, None, DUMMY_SP, None), - EvalResult::Deny { .. } - ); - } - false - } - - /// Checks if the `Constructor` is a `Constructor::Variant` with a `#[doc(hidden)]` - /// attribute from a type not local to the current crate. - pub(super) fn is_doc_hidden_variant(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> bool { - if let Constructor::Variant(idx) = self && let ty::Adt(adt, _) = pcx.ty.kind() { - let variant_def_id = adt.variants()[*idx].def_id; - return pcx.cx.tcx.is_doc_hidden(variant_def_id) && !variant_def_id.is_local(); - } - false - } - fn variant_index_for_adt(&self, adt: ty::AdtDef<'tcx>) -> VariantIdx { match *self { Variant(idx) => idx, @@ -695,27 +699,28 @@ impl<'tcx> Constructor<'tcx> { | F32Range(..) | F64Range(..) | IntRange(..) - | NonExhaustive | Opaque + | NonExhaustive + | Hidden | Missing { .. } | Wildcard => 0, Or => bug!("The `Or` constructor doesn't have a fixed arity"), } } - /// Some constructors (namely `Wildcard`, `IntRange` and `Slice`) actually stand for a set of actual - /// constructors (like variants, integers or fixed-sized slices). When specializing for these - /// constructors, we want to be specialising for the actual underlying constructors. + /// Some constructors (namely `Wildcard`, `IntRange` and `Slice`) actually stand for a set of + /// actual constructors (like variants, integers or fixed-sized slices). When specializing for + /// these constructors, we want to be specialising for the actual underlying constructors. /// Naively, we would simply return the list of constructors they correspond to. We instead are - /// more clever: if there are constructors that we know will behave the same wrt the current - /// matrix, we keep them grouped. For example, all slices of a sufficiently large length - /// will either be all useful or all non-useful with a given matrix. + /// more clever: if there are constructors that we know will behave the same w.r.t. the current + /// matrix, we keep them grouped. For example, all slices of a sufficiently large length will + /// either be all useful or all non-useful with a given matrix. /// /// See the branches for details on how the splitting is done. /// - /// This function may discard some irrelevant constructors if this preserves behavior and - /// diagnostics. Eg. for the `_` case, we ignore the constructors already present in the - /// matrix, unless all of them are. + /// This function may discard some irrelevant constructors if this preserves behavior. Eg. for + /// the `_` case, we ignore the constructors already present in the column, unless all of them + /// are. pub(super) fn split<'a>( &self, pcx: &PatCtxt<'_, '_, 'tcx>, @@ -726,23 +731,74 @@ impl<'tcx> Constructor<'tcx> { { match self { Wildcard => { - let mut split_wildcard = SplitWildcard::new(pcx); - split_wildcard.split(pcx, ctors); - split_wildcard.into_ctors(pcx) + let split_set = ConstructorSet::for_ty(pcx.cx, pcx.ty).split(pcx, ctors); + if !split_set.missing.is_empty() { + // We are splitting a wildcard in order to compute its usefulness. Some constructors are + // not present in the column. The first thing we note is that specializing with any of + // the missing constructors would select exactly the rows with wildcards. Moreover, they + // would all return equivalent results. We can therefore group them all into a + // fictitious `Missing` constructor. + // + // As an important optimization, this function will skip all the present constructors. + // This is correct because specializing with any of the present constructors would + // select a strict superset of the wildcard rows, and thus would only find witnesses + // already found with the `Missing` constructor. + // This does mean that diagnostics are incomplete: in + // ``` + // match x { + // Some(true) => {} + // } + // ``` + // we report `None` as missing but not `Some(false)`. + // + // When all the constructors are missing we can equivalently return the `Wildcard` + // constructor on its own. The difference between `Wildcard` and `Missing` will then + // only be in diagnostics. + + // If some constructors are missing, we typically want to report those constructors, + // e.g.: + // ``` + // enum Direction { N, S, E, W } + // let Direction::N = ...; + // ``` + // we can report 3 witnesses: `S`, `E`, and `W`. + // + // However, if the user didn't actually specify a constructor + // in this arm, e.g., in + // ``` + // let x: (Direction, Direction, bool) = ...; + // let (_, _, false) = x; + // ``` + // we don't want to show all 16 possible witnesses `(<direction-1>, <direction-2>, + // true)` - we are satisfied with `(_, _, true)`. So if all constructors are missing we + // prefer to report just a wildcard `_`. + // + // The exception is: if we are at the top-level, for example in an empty match, we + // usually prefer to report the full list of constructors. + let all_missing = split_set.present.is_empty(); + let report_when_all_missing = + pcx.is_top_level && !IntRange::is_integral(pcx.ty); + let ctor = if all_missing && !report_when_all_missing { + Wildcard + } else { + Missing { + nonexhaustive_enum_missing_visible_variants: split_set + .nonexhaustive_enum_missing_visible_variants, + } + }; + smallvec![ctor] + } else { + split_set.present + } } - // Fast-track if the range is trivial. In particular, we don't do the overlapping - // ranges check. - IntRange(ctor_range) if !ctor_range.is_singleton() => { - let mut split_range = SplitIntRange::new(ctor_range.clone()); - let int_ranges = ctors.filter_map(|ctor| ctor.as_int_range()); - split_range.split(int_ranges.cloned()); - split_range.iter().map(IntRange).collect() + // Fast-track if the range is trivial. + IntRange(this_range) if !this_range.is_singleton() => { + let column_ranges = ctors.filter_map(|ctor| ctor.as_int_range()).cloned(); + this_range.split(column_ranges).map(|(_, range)| IntRange(range)).collect() } - &Slice(Slice { kind: VarLen(self_prefix, self_suffix), array_len }) => { - let mut split_self = SplitVarLenSlice::new(self_prefix, self_suffix, array_len); - let slices = ctors.filter_map(|c| c.as_slice()).map(|s| s.kind); - split_self.split(slices); - split_self.iter().map(Slice).collect() + Slice(this_slice @ Slice { kind: VarLen(..), .. }) => { + let column_slices = ctors.filter_map(|c| c.as_slice()); + this_slice.split(column_slices).map(|(_, slice)| Slice(slice)).collect() } // Any other constructor can be used unchanged. _ => smallvec![self.clone()], @@ -759,13 +815,13 @@ impl<'tcx> Constructor<'tcx> { match (self, other) { // Wildcards cover anything (_, Wildcard) => true, - // The missing ctors are not covered by anything in the matrix except wildcards. - (Missing { .. } | Wildcard, _) => false, + // Only a wildcard pattern can match these special constructors. + (Wildcard | Missing { .. } | NonExhaustive | Hidden, _) => false, (Single, Single) => true, (Variant(self_id), Variant(other_id)) => self_id == other_id, - (IntRange(self_range), IntRange(other_range)) => self_range.is_covered_by(other_range), + (IntRange(self_range), IntRange(other_range)) => self_range.is_subrange(other_range), (F32Range(self_from, self_to, self_end), F32Range(other_from, other_to, other_end)) => { self_from.ge(other_from) && match self_to.partial_cmp(other_to) { @@ -791,8 +847,6 @@ impl<'tcx> Constructor<'tcx> { // We are trying to inspect an opaque constant. Thus we skip the row. (Opaque, _) | (_, Opaque) => false, - // Only a wildcard pattern can match the special extra constructor. - (NonExhaustive, _) => false, _ => span_bug!( pcx.span, @@ -802,96 +856,121 @@ impl<'tcx> Constructor<'tcx> { ), } } +} - /// Faster version of `is_covered_by` when applied to many constructors. `used_ctors` is - /// assumed to be built from `matrix.head_ctors()` with wildcards and opaques filtered out, - /// and `self` is assumed to have been split from a wildcard. - fn is_covered_by_any<'p>( - &self, - pcx: &PatCtxt<'_, 'p, 'tcx>, - used_ctors: &[Constructor<'tcx>], - ) -> bool { - if used_ctors.is_empty() { - return false; - } - - // This must be kept in sync with `is_covered_by`. - match self { - // If `self` is `Single`, `used_ctors` cannot contain anything else than `Single`s. - Single => !used_ctors.is_empty(), - Variant(vid) => used_ctors.iter().any(|c| matches!(c, Variant(i) if i == vid)), - IntRange(range) => used_ctors - .iter() - .filter_map(|c| c.as_int_range()) - .any(|other| range.is_covered_by(other)), - Slice(slice) => used_ctors - .iter() - .filter_map(|c| c.as_slice()) - .any(|other| slice.is_covered_by(other)), - // This constructor is never covered by anything else - NonExhaustive => false, - Str(..) | F32Range(..) | F64Range(..) | Opaque | Missing { .. } | Wildcard | Or => { - span_bug!(pcx.span, "found unexpected ctor in all_ctors: {:?}", self) - } - } - } +/// Describes the set of all constructors for a type. +#[derive(Debug)] +pub(super) enum ConstructorSet { + /// The type has a single constructor, e.g. `&T` or a struct. + Single, + /// This type has the following list of constructors. + /// Some variants are hidden, which means they won't be mentioned in diagnostics unless the user + /// mentioned them first. We use this for variants behind an unstable gate as well as + /// `#[doc(hidden)]` ones. + Variants { + visible_variants: Vec<VariantIdx>, + hidden_variants: Vec<VariantIdx>, + non_exhaustive: bool, + }, + /// The type is spanned by integer values. The range or ranges give the set of allowed values. + /// The second range is only useful for `char`. + /// This is reused for bool. FIXME: don't. + /// `non_exhaustive` is used when the range is not allowed to be matched exhaustively (that's + /// for usize/isize). + Integers { range_1: IntRange, range_2: Option<IntRange>, non_exhaustive: bool }, + /// The type is matched by slices. The usize is the compile-time length of the array, if known. + Slice(Option<usize>), + /// The type is matched by slices whose elements are uninhabited. + SliceOfEmpty, + /// The constructors cannot be listed, and the type cannot be matched exhaustively. E.g. `str`, + /// floats. + Unlistable, + /// The type has no inhabitants. + Uninhabited, } -/// A wildcard constructor that we split relative to the constructors in the matrix, as explained -/// at the top of the file. +/// Describes the result of analyzing the constructors in a column of a match. /// -/// A constructor that is not present in the matrix rows will only be covered by the rows that have -/// wildcards. Thus we can group all of those constructors together; we call them "missing -/// constructors". Splitting a wildcard would therefore list all present constructors individually -/// (or grouped if they are integers or slices), and then all missing constructors together as a -/// group. +/// `present` is morally the set of constructors present in the column, and `missing` is the set of +/// constructors that exist in the type but are not present in the column. /// -/// However we can go further: since any constructor will match the wildcard rows, and having more -/// rows can only reduce the amount of usefulness witnesses, we can skip the present constructors -/// and only try the missing ones. -/// This will not preserve the whole list of witnesses, but will preserve whether the list is empty -/// or not. In fact this is quite natural from the point of view of diagnostics too. This is done -/// in `to_ctors`: in some cases we only return `Missing`. +/// More formally, they respect the following constraints: +/// - the union of `present` and `missing` covers the whole type +/// - `present` and `missing` are disjoint +/// - neither contains wildcards +/// - each constructor in `present` is covered by some non-wildcard constructor in the column +/// - together, the constructors in `present` cover all the non-wildcard constructor in the column +/// - non-wildcards in the column do no cover anything in `missing` +/// - constructors in `present` and `missing` are split for the column; in other words, they are +/// either fully included in or disjoint from each constructor in the column. This avoids +/// non-trivial intersections like between `0..10` and `5..15`. #[derive(Debug)] -pub(super) struct SplitWildcard<'tcx> { - /// Constructors (other than wildcards and opaques) seen in the matrix. - matrix_ctors: Vec<Constructor<'tcx>>, - /// All the constructors for this type - all_ctors: SmallVec<[Constructor<'tcx>; 1]>, +struct SplitConstructorSet<'tcx> { + present: SmallVec<[Constructor<'tcx>; 1]>, + missing: Vec<Constructor<'tcx>>, + /// For the `non_exhaustive_omitted_patterns` lint. + nonexhaustive_enum_missing_visible_variants: bool, } -impl<'tcx> SplitWildcard<'tcx> { - pub(super) fn new<'p>(pcx: &PatCtxt<'_, 'p, 'tcx>) -> Self { - debug!("SplitWildcard::new({:?})", pcx.ty); - let cx = pcx.cx; - let make_range = |start, end| { - IntRange( - // `unwrap()` is ok because we know the type is an integer. - IntRange::from_range(cx.tcx, start, end, pcx.ty, RangeEnd::Included), - ) - }; - // This determines the set of all possible constructors for the type `pcx.ty`. For numbers, +impl ConstructorSet { + #[instrument(level = "debug", skip(cx), ret)] + pub(super) fn for_ty<'p, 'tcx>(cx: &MatchCheckCtxt<'p, 'tcx>, ty: Ty<'tcx>) -> Self { + let make_range = + |start, end| IntRange::from_range(cx.tcx, start, end, ty, RangeEnd::Included); + // This determines the set of all possible constructors for the type `ty`. For numbers, // arrays and slices we use ranges and variable-length slices when appropriate. // // If the `exhaustive_patterns` feature is enabled, we make sure to omit constructors that // are statically impossible. E.g., for `Option<!>`, we do not include `Some(_)` in the // returned list of constructors. - // Invariant: this is empty if and only if the type is uninhabited (as determined by + // Invariant: this is `Uninhabited` if and only if the type is uninhabited (as determined by // `cx.is_uninhabited()`). - let all_ctors = match pcx.ty.kind() { - ty::Bool => smallvec![make_range(0, 1)], + match ty.kind() { + ty::Bool => { + Self::Integers { range_1: make_range(0, 1), range_2: None, non_exhaustive: false } + } + ty::Char => { + // The valid Unicode Scalar Value ranges. + Self::Integers { + range_1: make_range('\u{0000}' as u128, '\u{D7FF}' as u128), + range_2: Some(make_range('\u{E000}' as u128, '\u{10FFFF}' as u128)), + non_exhaustive: false, + } + } + &ty::Int(ity) => { + // `usize`/`isize` are not allowed to be matched exhaustively unless the + // `precise_pointer_size_matching` feature is enabled. + let non_exhaustive = + ty.is_ptr_sized_integral() && !cx.tcx.features().precise_pointer_size_matching; + let bits = Integer::from_int_ty(&cx.tcx, ity).size().bits() as u128; + let min = 1u128 << (bits - 1); + let max = min - 1; + Self::Integers { range_1: make_range(min, max), non_exhaustive, range_2: None } + } + &ty::Uint(uty) => { + // `usize`/`isize` are not allowed to be matched exhaustively unless the + // `precise_pointer_size_matching` feature is enabled. + let non_exhaustive = + ty.is_ptr_sized_integral() && !cx.tcx.features().precise_pointer_size_matching; + let size = Integer::from_uint_ty(&cx.tcx, uty).size(); + let max = size.truncate(u128::MAX); + Self::Integers { range_1: make_range(0, max), non_exhaustive, range_2: None } + } ty::Array(sub_ty, len) if len.try_eval_target_usize(cx.tcx, cx.param_env).is_some() => { let len = len.eval_target_usize(cx.tcx, cx.param_env) as usize; if len != 0 && cx.is_uninhabited(*sub_ty) { - smallvec![] + Self::Uninhabited } else { - smallvec![Slice(Slice::new(Some(len), VarLen(0, 0)))] + Self::Slice(Some(len)) } } // Treat arrays of a constant but unknown length like slices. ty::Array(sub_ty, _) | ty::Slice(sub_ty) => { - let kind = if cx.is_uninhabited(*sub_ty) { FixedLen(0) } else { VarLen(0, 0) }; - smallvec![Slice(Slice::new(None, kind))] + if cx.is_uninhabited(*sub_ty) { + Self::SliceOfEmpty + } else { + Self::Slice(None) + } } ty::Adt(def, args) if def.is_enum() => { // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an @@ -910,19 +989,14 @@ impl<'tcx> SplitWildcard<'tcx> { // // we don't want to show every possible IO error, but instead have only `_` as the // witness. - let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty); + let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(ty); - let is_exhaustive_pat_feature = cx.tcx.features().exhaustive_patterns; - - // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it - // as though it had an "unknown" constructor to avoid exposing its emptiness. The - // exception is if the pattern is at the top level, because we want empty matches to be - // considered exhaustive. - let is_secretly_empty = - def.variants().is_empty() && !is_exhaustive_pat_feature && !pcx.is_top_level; - - let mut ctors: SmallVec<[_; 1]> = - def.variants() + if def.variants().is_empty() && !is_declared_nonexhaustive { + Self::Uninhabited + } else { + let is_exhaustive_pat_feature = cx.tcx.features().exhaustive_patterns; + let (hidden_variants, visible_variants) = def + .variants() .iter_enumerated() .filter(|(_, v)| { // If `exhaustive_patterns` is enabled, we exclude variants known to be @@ -932,135 +1006,173 @@ impl<'tcx> SplitWildcard<'tcx> { .instantiate(cx.tcx, args) .apply(cx.tcx, cx.param_env, cx.module) }) - .map(|(idx, _)| Variant(idx)) - .collect(); + .map(|(idx, _)| idx) + .partition(|idx| { + let variant_def_id = def.variant(*idx).def_id; + // Filter variants that depend on a disabled unstable feature. + let is_unstable = matches!( + cx.tcx.eval_stability(variant_def_id, None, DUMMY_SP, None), + EvalResult::Deny { .. } + ); + // Filter foreign `#[doc(hidden)]` variants. + let is_doc_hidden = + cx.tcx.is_doc_hidden(variant_def_id) && !variant_def_id.is_local(); + is_unstable || is_doc_hidden + }); + + Self::Variants { + visible_variants, + hidden_variants, + non_exhaustive: is_declared_nonexhaustive, + } + } + } + ty::Never => Self::Uninhabited, + _ if cx.is_uninhabited(ty) => Self::Uninhabited, + ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => Self::Single, + // This type is one for which we cannot list constructors, like `str` or `f64`. + _ => Self::Unlistable, + } + } - if is_secretly_empty || is_declared_nonexhaustive { - ctors.push(NonExhaustive); + /// This is the core logical operation of exhaustiveness checking. This analyzes a column a + /// constructors to 1/ determine which constructors of the type (if any) are missing; 2/ split + /// constructors to handle non-trivial intersections e.g. on ranges or slices. + #[instrument(level = "debug", skip(self, pcx, ctors), ret)] + fn split<'a, 'tcx>( + &self, + pcx: &PatCtxt<'_, '_, 'tcx>, + ctors: impl Iterator<Item = &'a Constructor<'tcx>> + Clone, + ) -> SplitConstructorSet<'tcx> + where + 'tcx: 'a, + { + let mut present: SmallVec<[_; 1]> = SmallVec::new(); + let mut missing = Vec::new(); + // Constructors in `ctors`, except wildcards. + let mut seen = ctors.filter(|c| !(matches!(c, Opaque | Wildcard))); + let mut nonexhaustive_enum_missing_visible_variants = false; + match self { + ConstructorSet::Single => { + if seen.next().is_none() { + missing.push(Single); + } else { + present.push(Single); } - ctors } - ty::Char => { - smallvec![ - // The valid Unicode Scalar Value ranges. - make_range('\u{0000}' as u128, '\u{D7FF}' as u128), - make_range('\u{E000}' as u128, '\u{10FFFF}' as u128), - ] + ConstructorSet::Variants { visible_variants, hidden_variants, non_exhaustive } => { + let seen_set: FxHashSet<_> = seen.map(|c| c.as_variant().unwrap()).collect(); + let mut skipped_a_hidden_variant = false; + for variant in visible_variants { + let ctor = Variant(*variant); + if seen_set.contains(&variant) { + present.push(ctor); + } else { + missing.push(ctor); + } + } + nonexhaustive_enum_missing_visible_variants = + *non_exhaustive && !missing.is_empty(); + + for variant in hidden_variants { + let ctor = Variant(*variant); + if seen_set.contains(&variant) { + present.push(ctor); + } else { + skipped_a_hidden_variant = true; + } + } + if skipped_a_hidden_variant { + missing.push(Hidden); + } + + if *non_exhaustive { + missing.push(NonExhaustive); + } } - ty::Int(_) | ty::Uint(_) - if pcx.ty.is_ptr_sized_integral() - && !cx.tcx.features().precise_pointer_size_matching => - { - // `usize`/`isize` are not allowed to be matched exhaustively unless the - // `precise_pointer_size_matching` feature is enabled. So we treat those types like - // `#[non_exhaustive]` enums by returning a special unmatchable constructor. - smallvec![NonExhaustive] + ConstructorSet::Integers { range_1, range_2, non_exhaustive } => { + let seen_ranges: Vec<_> = + seen.map(|ctor| ctor.as_int_range().unwrap().clone()).collect(); + for (seen, splitted_range) in range_1.split(seen_ranges.iter().cloned()) { + match seen { + Presence::Unseen => missing.push(IntRange(splitted_range)), + Presence::Seen => present.push(IntRange(splitted_range)), + } + } + if let Some(range_2) = range_2 { + for (seen, splitted_range) in range_2.split(seen_ranges.into_iter()) { + match seen { + Presence::Unseen => missing.push(IntRange(splitted_range)), + Presence::Seen => present.push(IntRange(splitted_range)), + } + } + } + + if *non_exhaustive { + missing.push(NonExhaustive); + } } - &ty::Int(ity) => { - let bits = Integer::from_int_ty(&cx.tcx, ity).size().bits() as u128; - let min = 1u128 << (bits - 1); - let max = min - 1; - smallvec![make_range(min, max)] + &ConstructorSet::Slice(array_len) => { + let seen_slices = seen.map(|c| c.as_slice().unwrap()); + let base_slice = Slice::new(array_len, VarLen(0, 0)); + for (seen, splitted_slice) in base_slice.split(seen_slices) { + let ctor = Slice(splitted_slice); + match seen { + Presence::Unseen => missing.push(ctor), + Presence::Seen => present.push(ctor), + } + } } - &ty::Uint(uty) => { - let size = Integer::from_uint_ty(&cx.tcx, uty).size(); - let max = size.truncate(u128::MAX); - smallvec![make_range(0, max)] + ConstructorSet::SliceOfEmpty => { + // This one is tricky because even though there's only one possible value of this + // type (namely `[]`), slice patterns of all lengths are allowed, they're just + // unreachable if length != 0. + // We still gather the seen constructors in `present`, but the only slice that can + // go in `missing` is `[]`. + let seen_slices = seen.map(|c| c.as_slice().unwrap()); + let base_slice = Slice::new(None, VarLen(0, 0)); + for (seen, splitted_slice) in base_slice.split(seen_slices) { + let ctor = Slice(splitted_slice); + match seen { + Presence::Seen => present.push(ctor), + Presence::Unseen if splitted_slice.arity() == 0 => { + missing.push(Slice(Slice::new(None, FixedLen(0)))) + } + Presence::Unseen => {} + } + } + } + ConstructorSet::Unlistable => { + // Since we can't list constructors, we take the ones in the column. This might list + // some constructors several times but there's not much we can do. + present.extend(seen.cloned()); + missing.push(NonExhaustive); } - // If `exhaustive_patterns` is disabled and our scrutinee is the never type, we cannot + // If `exhaustive_patterns` is disabled and our scrutinee is an empty type, we cannot // expose its emptiness. The exception is if the pattern is at the top level, because we // want empty matches to be considered exhaustive. - ty::Never if !cx.tcx.features().exhaustive_patterns && !pcx.is_top_level => { - smallvec![NonExhaustive] + ConstructorSet::Uninhabited + if !pcx.cx.tcx.features().exhaustive_patterns && !pcx.is_top_level => + { + missing.push(NonExhaustive); } - ty::Never => smallvec![], - _ if cx.is_uninhabited(pcx.ty) => smallvec![], - ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => smallvec![Single], - // This type is one for which we cannot list constructors, like `str` or `f64`. - _ => smallvec![NonExhaustive], - }; + ConstructorSet::Uninhabited => {} + } - SplitWildcard { matrix_ctors: Vec::new(), all_ctors } + SplitConstructorSet { present, missing, nonexhaustive_enum_missing_visible_variants } } - /// Pass a set of constructors relative to which to split this one. Don't call twice, it won't - /// do what you want. - pub(super) fn split<'a>( - &mut self, + /// Compute the set of constructors missing from this column. + /// This is only used for reporting to the user. + pub(super) fn compute_missing<'a, 'tcx>( + &self, pcx: &PatCtxt<'_, '_, 'tcx>, ctors: impl Iterator<Item = &'a Constructor<'tcx>> + Clone, - ) where + ) -> Vec<Constructor<'tcx>> + where 'tcx: 'a, { - // Since `all_ctors` never contains wildcards, this won't recurse further. - self.all_ctors = - self.all_ctors.iter().flat_map(|ctor| ctor.split(pcx, ctors.clone())).collect(); - self.matrix_ctors = ctors.filter(|c| !matches!(c, Wildcard | Opaque)).cloned().collect(); - } - - /// Whether there are any value constructors for this type that are not present in the matrix. - fn any_missing(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> bool { - self.iter_missing(pcx).next().is_some() - } - - /// Iterate over the constructors for this type that are not present in the matrix. - pub(super) fn iter_missing<'a, 'p>( - &'a self, - pcx: &'a PatCtxt<'a, 'p, 'tcx>, - ) -> impl Iterator<Item = &'a Constructor<'tcx>> + Captures<'p> { - self.all_ctors.iter().filter(move |ctor| !ctor.is_covered_by_any(pcx, &self.matrix_ctors)) - } - - /// Return the set of constructors resulting from splitting the wildcard. As explained at the - /// top of the file, if any constructors are missing we can ignore the present ones. - fn into_ctors(self, pcx: &PatCtxt<'_, '_, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> { - if self.any_missing(pcx) { - // Some constructors are missing, thus we can specialize with the special `Missing` - // constructor, which stands for those constructors that are not seen in the matrix, - // and matches the same rows as any of them (namely the wildcard rows). See the top of - // the file for details. - // However, when all constructors are missing we can also specialize with the full - // `Wildcard` constructor. The difference will depend on what we want in diagnostics. - - // If some constructors are missing, we typically want to report those constructors, - // e.g.: - // ``` - // enum Direction { N, S, E, W } - // let Direction::N = ...; - // ``` - // we can report 3 witnesses: `S`, `E`, and `W`. - // - // However, if the user didn't actually specify a constructor - // in this arm, e.g., in - // ``` - // let x: (Direction, Direction, bool) = ...; - // let (_, _, false) = x; - // ``` - // we don't want to show all 16 possible witnesses `(<direction-1>, <direction-2>, - // true)` - we are satisfied with `(_, _, true)`. So if all constructors are missing we - // prefer to report just a wildcard `_`. - // - // The exception is: if we are at the top-level, for example in an empty match, we - // sometimes prefer reporting the list of constructors instead of just `_`. - let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty); - let ctor = if !self.matrix_ctors.is_empty() || report_when_all_missing { - if pcx.is_non_exhaustive { - Missing { - nonexhaustive_enum_missing_real_variants: self - .iter_missing(pcx) - .any(|c| !(c.is_non_exhaustive() || c.is_unstable_variant(pcx))), - } - } else { - Missing { nonexhaustive_enum_missing_real_variants: false } - } - } else { - Wildcard - }; - return smallvec![ctor]; - } - - // All the constructors are present in the matrix, so we just go through them all. - self.all_ctors + self.split(pcx, ctors).missing } } @@ -1177,8 +1289,9 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { | F32Range(..) | F64Range(..) | IntRange(..) - | NonExhaustive | Opaque + | NonExhaustive + | Hidden | Missing { .. } | Wildcard => Fields::empty(), Or => { @@ -1412,6 +1525,10 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { let pats = expand_or_pat(pat); fields = Fields::from_iter(cx, pats.into_iter().map(mkpat)); } + PatKind::Error(_) => { + ctor = Opaque; + fields = Fields::empty(); + } } DeconstructedPat::new(ctor, fields, pat.ty, pat.span) } @@ -1492,7 +1609,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { } &Str(value) => PatKind::Constant { value }, IntRange(range) => return range.to_pat(cx.tcx, self.ty), - Wildcard | NonExhaustive => PatKind::Wild, + Wildcard | NonExhaustive | Hidden => PatKind::Wild, Missing { .. } => bug!( "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug, `Missing` should have been processed in `apply_constructors`" @@ -1675,15 +1792,15 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> { F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"), F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"), IntRange(range) => write!(f, "{range:?}"), // Best-effort, will render e.g. `false` as `0..=0` - Wildcard | Missing { .. } | NonExhaustive => write!(f, "_ : {:?}", self.ty), + Str(value) => write!(f, "{value}"), + Opaque => write!(f, "<constant pattern>"), Or => { for pat in self.iter_fields() { write!(f, "{}{:?}", start_or_continue(" | "), pat)?; } Ok(()) } - Str(value) => write!(f, "{value}"), - Opaque => write!(f, "<constant pattern>"), + Wildcard | Missing { .. } | NonExhaustive | Hidden => write!(f, "_ : {:?}", self.ty), } } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index fe47a1cd78c..76ed6d2b6d7 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -20,15 +20,15 @@ use rustc_index::Idx; use rustc_middle::mir::interpret::{ ErrorHandled, GlobalId, LitToConstError, LitToConstInput, Scalar, }; -use rustc_middle::mir::{self, Const, UserTypeProjection}; -use rustc_middle::mir::{BorrowKind, Mutability}; +use rustc_middle::mir::{self, BorrowKind, Const, Mutability, UserTypeProjection}; use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange}; -use rustc_middle::ty::CanonicalUserTypeAnnotation; -use rustc_middle::ty::TypeVisitableExt; -use rustc_middle::ty::{self, AdtDef, Region, Ty, TyCtxt, UserType}; -use rustc_middle::ty::{GenericArg, GenericArgsRef}; -use rustc_span::{Span, Symbol}; -use rustc_target::abi::FieldIdx; +use rustc_middle::ty::layout::IntegerExt; +use rustc_middle::ty::{ + self, AdtDef, CanonicalUserTypeAnnotation, GenericArg, GenericArgsRef, Region, Ty, TyCtxt, + TypeVisitableExt, UserType, +}; +use rustc_span::{ErrorGuaranteed, Span, Symbol}; +use rustc_target::abi::{FieldIdx, Integer}; use std::cmp::Ordering; @@ -85,127 +85,159 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { ) } - fn lower_range_expr( + fn lower_pattern_range_endpoint( &mut self, - expr: &'tcx hir::Expr<'tcx>, - ) -> (PatKind<'tcx>, Option<Ascription<'tcx>>) { - match self.lower_lit(expr) { - PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => { - (kind, Some(ascription)) + expr: Option<&'tcx hir::Expr<'tcx>>, + ) -> Result<(Option<mir::Const<'tcx>>, Option<Ascription<'tcx>>), ErrorGuaranteed> { + match expr { + None => Ok((None, None)), + Some(expr) => { + let (kind, ascr) = match self.lower_lit(expr) { + PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => { + (kind, Some(ascription)) + } + kind => (kind, None), + }; + let value = if let PatKind::Constant { value } = kind { + value + } else { + let msg = format!( + "found bad range pattern endpoint `{expr:?}` outside of error recovery" + ); + return Err(self.tcx.sess.delay_span_bug(expr.span, msg)); + }; + Ok((Some(value), ascr)) + } + } + } + + /// Overflowing literals are linted against in a late pass. This is mostly fine, except when we + /// encounter a range pattern like `-130i8..2`: if we believe `eval_bits`, this looks like a + /// range where the endpoints are in the wrong order. To avoid a confusing error message, we + /// check for overflow then. + /// This is only called when the range is already known to be malformed. + fn error_on_literal_overflow( + &self, + expr: Option<&'tcx hir::Expr<'tcx>>, + ty: Ty<'tcx>, + ) -> Result<(), ErrorGuaranteed> { + use hir::{ExprKind, UnOp}; + use rustc_ast::ast::LitKind; + + let Some(mut expr) = expr else { + return Ok(()); + }; + let span = expr.span; + + // We need to inspect the original expression, because if we only inspect the output of + // `eval_bits`, an overflowed value has already been wrapped around. + // We mostly copy the logic from the `rustc_lint::OVERFLOWING_LITERALS` lint. + let mut negated = false; + if let ExprKind::Unary(UnOp::Neg, sub_expr) = expr.kind { + negated = true; + expr = sub_expr; + } + let ExprKind::Lit(lit) = expr.kind else { + return Ok(()); + }; + let LitKind::Int(lit_val, _) = lit.node else { + return Ok(()); + }; + let (min, max): (i128, u128) = match ty.kind() { + ty::Int(ity) => { + let size = Integer::from_int_ty(&self.tcx, *ity).size(); + (size.signed_int_min(), size.signed_int_max() as u128) } - kind => (kind, None), + ty::Uint(uty) => { + let size = Integer::from_uint_ty(&self.tcx, *uty).size(); + (0, size.unsigned_int_max()) + } + _ => { + return Ok(()); + } + }; + // Detect literal value out of range `[min, max]` inclusive, avoiding use of `-min` to + // prevent overflow/panic. + if (negated && lit_val > max + 1) || (!negated && lit_val > max) { + return Err(self.tcx.sess.emit_err(LiteralOutOfRange { span, ty, min, max })); } + Ok(()) } fn lower_pattern_range( &mut self, - ty: Ty<'tcx>, - lo: mir::Const<'tcx>, - hi: mir::Const<'tcx>, + lo_expr: Option<&'tcx hir::Expr<'tcx>>, + hi_expr: Option<&'tcx hir::Expr<'tcx>>, end: RangeEnd, + ty: Ty<'tcx>, span: Span, - lo_expr: Option<&hir::Expr<'tcx>>, - hi_expr: Option<&hir::Expr<'tcx>>, - ) -> PatKind<'tcx> { + ) -> Result<PatKind<'tcx>, ErrorGuaranteed> { + if lo_expr.is_none() && hi_expr.is_none() { + let msg = format!("found twice-open range pattern (`..`) outside of error recovery"); + return Err(self.tcx.sess.delay_span_bug(span, msg)); + } + + let (lo, lo_ascr) = self.lower_pattern_range_endpoint(lo_expr)?; + let (hi, hi_ascr) = self.lower_pattern_range_endpoint(hi_expr)?; + + let lo = lo.unwrap_or_else(|| { + // Unwrap is ok because the type is known to be numeric. + let lo = ty.numeric_min_val(self.tcx).unwrap(); + mir::Const::from_ty_const(lo, self.tcx) + }); + let hi = hi.unwrap_or_else(|| { + // Unwrap is ok because the type is known to be numeric. + let hi = ty.numeric_max_val(self.tcx).unwrap(); + mir::Const::from_ty_const(hi, self.tcx) + }); assert_eq!(lo.ty(), ty); assert_eq!(hi.ty(), ty); + let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env); - let max = || { - self.tcx - .layout_of(self.param_env.with_reveal_all_normalized(self.tcx).and(ty)) - .ok() - .unwrap() - .size - .unsigned_int_max() - }; - match (end, cmp) { + let mut kind = match (end, cmp) { // `x..y` where `x < y`. // Non-empty because the range includes at least `x`. (RangeEnd::Excluded, Some(Ordering::Less)) => { PatKind::Range(Box::new(PatRange { lo, hi, end })) } - // `x..y` where `x >= y`. The range is empty => error. - (RangeEnd::Excluded, _) => { - let mut lower_overflow = false; - let mut higher_overflow = false; - if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr - && let rustc_ast::ast::LitKind::Int(val, _) = lit.node - { - if lo.eval_bits(self.tcx, self.param_env) != val { - lower_overflow = true; - self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); - } - } - if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr - && let rustc_ast::ast::LitKind::Int(val, _) = lit.node - { - if hi.eval_bits(self.tcx, self.param_env) != val { - higher_overflow = true; - self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); - } - } - if !lower_overflow && !higher_overflow { - self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanUpper { span }); - } - PatKind::Wild - } // `x..=y` where `x == y`. (RangeEnd::Included, Some(Ordering::Equal)) => PatKind::Constant { value: lo }, // `x..=y` where `x < y`. (RangeEnd::Included, Some(Ordering::Less)) => { PatKind::Range(Box::new(PatRange { lo, hi, end })) } - // `x..=y` where `x > y` hence the range is empty => error. - (RangeEnd::Included, _) => { - let mut lower_overflow = false; - let mut higher_overflow = false; - if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr - && let rustc_ast::ast::LitKind::Int(val, _) = lit.node - { - if lo.eval_bits(self.tcx, self.param_env) != val { - lower_overflow = true; - self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); + // `x..y` where `x >= y`, or `x..=y` where `x > y`. The range is empty => error. + _ => { + // Emit a more appropriate message if there was overflow. + self.error_on_literal_overflow(lo_expr, ty)?; + self.error_on_literal_overflow(hi_expr, ty)?; + let e = match end { + RangeEnd::Included => { + self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper { + span, + teach: self.tcx.sess.teach(&error_code!(E0030)).then_some(()), + }) } - } - if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr - && let rustc_ast::ast::LitKind::Int(val, _) = lit.node - { - if hi.eval_bits(self.tcx, self.param_env) != val { - higher_overflow = true; - self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() }); + RangeEnd::Excluded => { + self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanUpper { span }) } - } - if !lower_overflow && !higher_overflow { - self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper { - span, - teach: self.tcx.sess.teach(&error_code!(E0030)).then_some(()), - }); - } - PatKind::Wild + }; + return Err(e); } - } - } + }; - fn normalize_range_pattern_ends( - &self, - ty: Ty<'tcx>, - lo: Option<&PatKind<'tcx>>, - hi: Option<&PatKind<'tcx>>, - ) -> Option<(mir::Const<'tcx>, mir::Const<'tcx>)> { - match (lo, hi) { - (Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => { - Some((*lo, *hi)) - } - (Some(PatKind::Constant { value: lo }), None) => { - let hi = ty.numeric_max_val(self.tcx)?; - Some((*lo, mir::Const::from_ty_const(hi, self.tcx))) - } - (None, Some(PatKind::Constant { value: hi })) => { - let lo = ty.numeric_min_val(self.tcx)?; - Some((mir::Const::from_ty_const(lo, self.tcx), *hi)) + // If we are handling a range with associated constants (e.g. + // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated + // constants somewhere. Have them on the range pattern. + for ascr in [lo_ascr, hi_ascr] { + if let Some(ascription) = ascr { + kind = PatKind::AscribeUserType { + ascription, + subpattern: Box::new(Pat { span, ty, kind }), + }; } - _ => None, } + Ok(kind) } #[instrument(skip(self), level = "debug")] @@ -220,37 +252,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => { let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref()); - let lo_span = lo_expr.map_or(pat.span, |e| e.span); - let lo = lo_expr.map(|e| self.lower_range_expr(e)); - let hi = hi_expr.map(|e| self.lower_range_expr(e)); - - let (lp, hp) = (lo.as_ref().map(|(x, _)| x), hi.as_ref().map(|(x, _)| x)); - let mut kind = match self.normalize_range_pattern_ends(ty, lp, hp) { - Some((lc, hc)) => { - self.lower_pattern_range(ty, lc, hc, end, lo_span, lo_expr, hi_expr) - } - None => { - let msg = format!( - "found bad range pattern `{:?}` outside of error recovery", - (&lo, &hi), - ); - self.tcx.sess.delay_span_bug(pat.span, msg); - PatKind::Wild - } - }; - - // If we are handling a range with associated constants (e.g. - // `Foo::<'a>::A..=Foo::B`), we need to put the ascriptions for the associated - // constants somewhere. Have them on the range pattern. - for end in &[lo, hi] { - if let Some((_, Some(ascription))) = end { - let subpattern = Box::new(Pat { span: pat.span, ty, kind }); - kind = - PatKind::AscribeUserType { ascription: ascription.clone(), subpattern }; - } - } - - kind + self.lower_pattern_range(lo_expr, hi_expr, end, ty, span) + .unwrap_or_else(PatKind::Error) } hir::PatKind::Path(ref qpath) => { @@ -418,9 +421,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if adt_def.is_enum() { let args = match ty.kind() { ty::Adt(_, args) | ty::FnDef(_, args) => args, - ty::Error(_) => { + ty::Error(e) => { // Avoid ICE (#50585) - return PatKind::Wild; + return PatKind::Error(*e); } _ => bug!("inappropriate type for def: {:?}", ty), }; @@ -447,7 +450,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { | Res::SelfTyAlias { .. } | Res::SelfCtor(..) => PatKind::Leaf { subpatterns }, _ => { - match res { + let e = match res { Res::Def(DefKind::ConstParam, _) => { self.tcx.sess.emit_err(ConstParamInPattern { span }) } @@ -456,7 +459,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } _ => self.tcx.sess.emit_err(NonConstPath { span }), }; - PatKind::Wild + PatKind::Error(e) } }; @@ -508,14 +511,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // It should be assoc consts if there's no error but we cannot resolve it. debug_assert!(is_associated_const); - self.tcx.sess.emit_err(AssocConstInPattern { span }); - - return pat_from_kind(PatKind::Wild); + let e = self.tcx.sess.emit_err(AssocConstInPattern { span }); + return pat_from_kind(PatKind::Error(e)); } Err(_) => { - self.tcx.sess.emit_err(CouldNotEvalConstPattern { span }); - return pat_from_kind(PatKind::Wild); + let e = self.tcx.sess.emit_err(CouldNotEvalConstPattern { span }); + return pat_from_kind(PatKind::Error(e)); } }; @@ -569,12 +571,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { Err(ErrorHandled::TooGeneric(_)) => { // While `Reported | Linted` cases will have diagnostics emitted already // it is not true for TooGeneric case, so we need to give user more information. - self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span }); - pat_from_kind(PatKind::Wild) + let e = self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span }); + pat_from_kind(PatKind::Error(e)) } Err(_) => { - self.tcx.sess.emit_err(CouldNotEvalConstPattern { span }); - pat_from_kind(PatKind::Wild) + let e = self.tcx.sess.emit_err(CouldNotEvalConstPattern { span }); + pat_from_kind(PatKind::Error(e)) } } } @@ -624,7 +626,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let uneval = mir::UnevaluatedConst { def: def_id.to_def_id(), args, promoted: None }; debug_assert!(!args.has_free_regions()); - let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args: args }; + let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args }; // First try using a valtree in order to destructure the constant into a pattern. // FIXME: replace "try to do a thing, then fall back to another thing" // but something more principled, like a trait query checking whether this can be turned into a valtree. @@ -644,10 +646,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span, None).kind, Err(ErrorHandled::TooGeneric(_)) => { // If we land here it means the const can't be evaluated because it's `TooGeneric`. - self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span }); - PatKind::Wild + let e = self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span }); + PatKind::Error(e) } - Err(ErrorHandled::Reported(..)) => PatKind::Wild, + Err(ErrorHandled::Reported(err, ..)) => PatKind::Error(err.into()), } } } @@ -680,7 +682,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { Ok(constant) => { self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span, None).kind } - Err(LitToConstError::Reported(_)) => PatKind::Wild, + Err(LitToConstError::Reported(e)) => PatKind::Error(e), Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), } } @@ -786,6 +788,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> { fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self { match *self { PatKind::Wild => PatKind::Wild, + PatKind::Error(e) => PatKind::Error(e), PatKind::AscribeUserType { ref subpattern, ascription: Ascription { ref annotation, variance }, diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 21031e8ba9d..6cd73c7eaa9 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -307,7 +307,7 @@ use self::ArmType::*; use self::Usefulness::*; -use super::deconstruct_pat::{Constructor, DeconstructedPat, Fields, SplitWildcard}; +use super::deconstruct_pat::{Constructor, ConstructorSet, DeconstructedPat, Fields}; use crate::errors::{NonExhaustiveOmittedPattern, Uncovered}; use rustc_data_structures::captures::Captures; @@ -368,8 +368,6 @@ pub(super) struct PatCtxt<'a, 'p, 'tcx> { /// Whether the current pattern is the whole pattern as found in a match arm, or if it's a /// subpattern. pub(super) is_top_level: bool, - /// Whether the current pattern is from a `non_exhaustive` enum. - pub(super) is_non_exhaustive: bool, } impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> { @@ -616,62 +614,41 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> { WithWitnesses(ref witnesses) if witnesses.is_empty() => self, WithWitnesses(witnesses) => { let new_witnesses = if let Constructor::Missing { .. } = ctor { + let mut missing = ConstructorSet::for_ty(pcx.cx, pcx.ty) + .compute_missing(pcx, matrix.heads().map(DeconstructedPat::ctor)); + if missing.iter().any(|c| c.is_non_exhaustive()) { + // We only report `_` here; listing other constructors would be redundant. + missing = vec![Constructor::NonExhaustive]; + } + // We got the special `Missing` constructor, so each of the missing constructors - // gives a new pattern that is not caught by the match. We list those patterns. - if pcx.is_non_exhaustive { - witnesses - .into_iter() - // Here we don't want the user to try to list all variants, we want them to add - // a wildcard, so we only suggest that. - .map(|witness| { - witness.apply_constructor(pcx, &Constructor::NonExhaustive) - }) - .collect() - } else { - let mut split_wildcard = SplitWildcard::new(pcx); - split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); - - // This lets us know if we skipped any variants because they are marked - // `doc(hidden)` or they are unstable feature gate (only stdlib types). - let mut hide_variant_show_wild = false; - // Construct for each missing constructor a "wild" version of this - // constructor, that matches everything that can be built with - // it. For example, if `ctor` is a `Constructor::Variant` for - // `Option::Some`, we get the pattern `Some(_)`. - let mut new_patterns: Vec<DeconstructedPat<'_, '_>> = split_wildcard - .iter_missing(pcx) - .filter_map(|missing_ctor| { - // Check if this variant is marked `doc(hidden)` - if missing_ctor.is_doc_hidden_variant(pcx) - || missing_ctor.is_unstable_variant(pcx) - { - hide_variant_show_wild = true; - return None; - } - Some(DeconstructedPat::wild_from_ctor(pcx, missing_ctor.clone())) - }) - .collect(); - - if hide_variant_show_wild { - new_patterns.push(DeconstructedPat::wildcard(pcx.ty, pcx.span)); - } - - witnesses - .into_iter() - .flat_map(|witness| { - new_patterns.iter().map(move |pat| { - Witness( - witness - .0 - .iter() - .chain(once(pat)) - .map(DeconstructedPat::clone_and_forget_reachability) - .collect(), - ) - }) + // gives a new pattern that is not caught by the match. + // We construct for each missing constructor a version of this constructor with + // wildcards for fields, i.e. that matches everything that can be built with it. + // For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get + // the pattern `Some(_)`. + let new_patterns: Vec<DeconstructedPat<'_, '_>> = missing + .into_iter() + .map(|missing_ctor| { + DeconstructedPat::wild_from_ctor(pcx, missing_ctor.clone()) + }) + .collect(); + + witnesses + .into_iter() + .flat_map(|witness| { + new_patterns.iter().map(move |pat| { + Witness( + witness + .0 + .iter() + .chain(once(pat)) + .map(DeconstructedPat::clone_and_forget_reachability) + .collect(), + ) }) - .collect() - } + }) + .collect() } else { witnesses .into_iter() @@ -844,9 +821,8 @@ fn is_useful<'p, 'tcx>( ty = row.head().ty(); } } - let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty); debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span()); - let pcx = &PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive }; + let pcx = &PatCtxt { cx, ty, span: v.head().span(), is_top_level }; let v_ctor = v.head().ctor(); debug!(?v_ctor); @@ -861,7 +837,8 @@ fn is_useful<'p, 'tcx>( } // We split the head constructor of `v`. let split_ctors = v_ctor.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); - let is_non_exhaustive_and_wild = is_non_exhaustive && v_ctor.is_wildcard(); + let is_non_exhaustive_and_wild = + cx.is_foreign_non_exhaustive_enum(ty) && v_ctor.is_wildcard(); // For each constructor, we compute whether there's a value that starts with it that would // witness the usefulness of `v`. let start_matrix = &matrix; @@ -895,27 +872,21 @@ fn is_useful<'p, 'tcx>( && usefulness.is_useful() && matches!(witness_preference, RealArm) && matches!( &ctor, - Constructor::Missing { nonexhaustive_enum_missing_real_variants: true } + Constructor::Missing { nonexhaustive_enum_missing_visible_variants: true } ) { - let patterns = { - let mut split_wildcard = SplitWildcard::new(pcx); - split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); - // Construct for each missing constructor a "wild" version of this - // constructor, that matches everything that can be built with - // it. For example, if `ctor` is a `Constructor::Variant` for - // `Option::Some`, we get the pattern `Some(_)`. - split_wildcard - .iter_missing(pcx) - // Filter out the `NonExhaustive` because we want to list only real - // variants. Also remove any unstable feature gated variants. - // Because of how we computed `nonexhaustive_enum_missing_real_variants`, - // this will not return an empty `Vec`. - .filter(|c| !(c.is_non_exhaustive() || c.is_unstable_variant(pcx))) - .cloned() - .map(|missing_ctor| DeconstructedPat::wild_from_ctor(pcx, missing_ctor)) - .collect::<Vec<_>>() - }; + let missing = ConstructorSet::for_ty(pcx.cx, pcx.ty) + .compute_missing(pcx, matrix.heads().map(DeconstructedPat::ctor)); + // Construct for each missing constructor a "wild" version of this constructor, that + // matches everything that can be built with it. For example, if `ctor` is a + // `Constructor::Variant` for `Option::Some`, we get the pattern `Some(_)`. + let patterns = missing + .into_iter() + // Because of how we computed `nonexhaustive_enum_missing_visible_variants`, + // this will not return an empty `Vec`. + .filter(|c| !(matches!(c, Constructor::NonExhaustive | Constructor::Hidden))) + .map(|missing_ctor| DeconstructedPat::wild_from_ctor(pcx, missing_ctor)) + .collect::<Vec<_>>(); // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns` // is not exhaustive enough. diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 3b6276cfeb0..c957611b975 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -757,6 +757,9 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, "]", depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } + PatKind::Error(_) => { + print_indented!(self, "Error", depth_lvl + 1); + } } print_indented!(self, "}", depth_lvl); diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 83766f31148..44bbb8374dc 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -685,8 +685,10 @@ impl Map { // `elem1` is either `Some(Variant(i))` or `None`. while let Some((mut place, elem1, elem2, ty)) = worklist.pop_front() { // The user requires a bound on the number of created values. - if let Some(value_limit) = value_limit && self.value_count >= value_limit { - break + if let Some(value_limit) = value_limit + && self.value_count >= value_limit + { + break; } // Create a place for this projection. @@ -717,7 +719,9 @@ impl Map { // Trim useless places. for opt_place in self.locals.iter_mut() { - if let Some(place) = *opt_place && self.inner_values[place].is_empty() { + if let Some(place) = *opt_place + && self.inner_values[place].is_empty() + { *opt_place = None; } } @@ -772,7 +776,7 @@ impl Map { assert!(old.is_none()); // Allocate a value slot since it doesn't have one. - assert!( self.places[len].value_index.is_none() ); + assert!(self.places[len].value_index.is_none()); self.places[len].value_index = Some(self.value_count.into()); self.value_count += 1; } diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs index 4500bb7ff0f..74243f1f8f2 100644 --- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs +++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs @@ -113,6 +113,6 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls { } // We may have invalidated some `cleanup` blocks so clean those up now. - super::simplify::remove_dead_blocks(tcx, body); + super::simplify::remove_dead_blocks(body); } } diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs index b79150737d6..61bf530f11c 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -97,13 +97,15 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> { // so emitting a lint would be redundant. if !lhs.projection.is_empty() { if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) - && let Some((lint_root, span, item)) = self.should_lint_const_item_usage(&lhs, def_id, loc) { - self.tcx.emit_spanned_lint( - CONST_ITEM_MUTATION, - lint_root, - span, - errors::ConstMutate::Modify { konst: item } - ); + && let Some((lint_root, span, item)) = + self.should_lint_const_item_usage(&lhs, def_id, loc) + { + self.tcx.emit_spanned_lint( + CONST_ITEM_MUTATION, + lint_root, + span, + errors::ConstMutate::Modify { konst: item }, + ); } } // We are looking for MIR of the form: diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs index 2e6cf603d59..9ee0a704071 100644 --- a/compiler/rustc_mir_transform/src/check_packed_ref.rs +++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs @@ -46,9 +46,14 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> { // If we ever reach here it means that the generated derive // code is somehow doing an unaligned reference, which it // shouldn't do. - span_bug!(self.source_info.span, "builtin derive created an unaligned reference"); + span_bug!( + self.source_info.span, + "builtin derive created an unaligned reference" + ); } else { - self.tcx.sess.emit_err(errors::UnalignedPackedRef { span: self.source_info.span }); + self.tcx + .sess + .emit_err(errors::UnalignedPackedRef { span: self.source_info.span }); } } } diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index c428007707e..7e4731f5d8a 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -540,8 +540,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) { && let BlockCheckMode::UnsafeBlock(_) = block.rules { true - } - else if let Some(sig) = tcx.hir().fn_sig_by_hir_id(*id) + } else if let Some(sig) = tcx.hir().fn_sig_by_hir_id(*id) && sig.header.is_unsafe() { true diff --git a/compiler/rustc_mir_transform/src/const_debuginfo.rs b/compiler/rustc_mir_transform/src/const_debuginfo.rs index 40cd2825408..e4e4270c499 100644 --- a/compiler/rustc_mir_transform/src/const_debuginfo.rs +++ b/compiler/rustc_mir_transform/src/const_debuginfo.rs @@ -55,7 +55,9 @@ fn find_optimization_opportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, Const let mut locals_to_debuginfo = BitSet::new_empty(body.local_decls.len()); for debuginfo in &body.var_debug_info { - if let VarDebugInfoContents::Place(p) = debuginfo.value && let Some(l) = p.as_local() { + if let VarDebugInfoContents::Place(p) = debuginfo.value + && let Some(l) = p.as_local() + { locals_to_debuginfo.insert(l); } } diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 4fc78b28580..3450a0f3686 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -2,8 +2,6 @@ //! assertion failures use either::Right; - -use rustc_const_eval::const_eval::CheckAlignment; use rustc_const_eval::ReportErrorExt; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::DefKind; @@ -16,7 +14,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::{self, GenericArgs, Instance, ParamEnv, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::{def_id::DefId, Span}; -use rustc_target::abi::{self, Align, HasDataLayout, Size, TargetDataLayout}; +use rustc_target::abi::{self, HasDataLayout, Size, TargetDataLayout}; use rustc_target::spec::abi::Abi as CallAbi; use crate::dataflow_const_prop::Patch; @@ -141,27 +139,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> type MemoryKind = !; #[inline(always)] - fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment { - // We do not check for alignment to avoid having to carry an `Align` - // in `ConstValue::Indirect`. - CheckAlignment::No + fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + false // no reason to enforce alignment } #[inline(always)] fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool { false // for now, we don't enforce validity } - fn alignment_check_failed( - ecx: &InterpCx<'mir, 'tcx, Self>, - _has: Align, - _required: Align, - _check: CheckAlignment, - ) -> InterpResult<'tcx, ()> { - span_bug!( - ecx.cur_span(), - "`alignment_check_failed` called when no alignment check requested" - ) - } fn load_mir( _ecx: &InterpCx<'mir, 'tcx, Self>, @@ -699,7 +684,9 @@ impl<'tcx> Visitor<'tcx> for CanConstProp { impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { self.super_operand(operand, location); - if let Some(place) = operand.place() && let Some(value) = self.replace_with_const(place) { + if let Some(place) = operand.place() + && let Some(value) = self.replace_with_const(place) + { self.patch.before_effect.insert((location, place), value); } } @@ -733,7 +720,10 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { if let Rvalue::Use(Operand::Constant(c)) = rvalue && let Const::Val(..) = c.const_ { - trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c); + trace!( + "skipping replace of Rvalue::Use({:?} because it is already a const", + c + ); } else if let Some(operand) = self.replace_with_const(*place) { self.patch.assignments.insert(location, operand); } diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 64e262c6c93..aad513d7355 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -22,7 +22,6 @@ use rustc_middle::ty::{ }; use rustc_span::Span; use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout}; -use rustc_trait_selection::traits; use crate::const_prop::CanConstProp; use crate::const_prop::ConstPropMachine; @@ -35,9 +34,9 @@ use crate::MirLint; /// Severely regress performance. const MAX_ALLOC_LIMIT: u64 = 1024; -pub struct ConstProp; +pub struct ConstPropLint; -impl<'tcx> MirLint<'tcx> for ConstProp { +impl<'tcx> MirLint<'tcx> for ConstPropLint { fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { if body.tainted_by_errors.is_some() { return; @@ -49,61 +48,25 @@ impl<'tcx> MirLint<'tcx> for ConstProp { } let def_id = body.source.def_id().expect_local(); - let is_fn_like = tcx.def_kind(def_id).is_fn_like(); - let is_assoc_const = tcx.def_kind(def_id) == DefKind::AssocConst; + let def_kind = tcx.def_kind(def_id); + let is_fn_like = def_kind.is_fn_like(); + let is_assoc_const = def_kind == DefKind::AssocConst; // Only run const prop on functions, methods, closures and associated constants if !is_fn_like && !is_assoc_const { // skip anon_const/statics/consts because they'll be evaluated by miri anyway - trace!("ConstProp skipped for {:?}", def_id); + trace!("ConstPropLint skipped for {:?}", def_id); return; } - let is_generator = tcx.type_of(def_id.to_def_id()).instantiate_identity().is_generator(); // FIXME(welseywiser) const prop doesn't work on generators because of query cycles // computing their layout. - if is_generator { - trace!("ConstProp skipped for generator {:?}", def_id); + if let DefKind::Generator = def_kind { + trace!("ConstPropLint skipped for generator {:?}", def_id); return; } - // Check if it's even possible to satisfy the 'where' clauses - // for this item. - // This branch will never be taken for any normal function. - // However, it's possible to `#!feature(trivial_bounds)]` to write - // a function with impossible to satisfy clauses, e.g.: - // `fn foo() where String: Copy {}` - // - // We don't usually need to worry about this kind of case, - // since we would get a compilation error if the user tried - // to call it. However, since we can do const propagation - // even without any calls to the function, we need to make - // sure that it even makes sense to try to evaluate the body. - // If there are unsatisfiable where clauses, then all bets are - // off, and we just give up. - // - // We manually filter the predicates, skipping anything that's not - // "global". We are in a potentially generic context - // (e.g. we are evaluating a function without substituting generic - // parameters, so this filtering serves two purposes: - // - // 1. We skip evaluating any predicates that we would - // never be able prove are unsatisfiable (e.g. `<T as Foo>` - // 2. We avoid trying to normalize predicates involving generic - // parameters (e.g. `<T as Foo>::MyItem`). This can confuse - // the normalization code (leading to cycle errors), since - // it's usually never invoked in this way. - let predicates = tcx - .predicates_of(def_id.to_def_id()) - .predicates - .iter() - .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None }); - if traits::impossible_predicates(tcx, traits::elaborate(tcx, predicates).collect()) { - trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", def_id); - return; - } - - trace!("ConstProp starting for {:?}", def_id); + trace!("ConstPropLint starting for {:?}", def_id); // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold // constants, instead of just checking for const-folding succeeding. @@ -112,7 +75,7 @@ impl<'tcx> MirLint<'tcx> for ConstProp { let mut linter = ConstPropagator::new(body, tcx); linter.visit_body(body); - trace!("ConstProp done for {:?}", def_id); + trace!("ConstPropLint done for {:?}", def_id); } } @@ -664,9 +627,10 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { } TerminatorKind::SwitchInt { ref discr, ref targets } => { if let Some(ref value) = self.eval_operand(&discr, location) - && let Some(value_const) = self.use_ecx(location, |this| this.ecx.read_scalar(value)) - && let Ok(constant) = value_const.try_to_int() - && let Ok(constant) = constant.to_bits(constant.size()) + && let Some(value_const) = + self.use_ecx(location, |this| this.ecx.read_scalar(value)) + && let Ok(constant) = value_const.try_to_int() + && let Ok(constant) = constant.to_bits(constant.size()) { // We managed to evaluate the discriminant, so we know we only need to visit // one target. diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index 9a3798eea3b..be4af3b76f1 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -168,14 +168,15 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { && self.storage_to_remove.contains(l) { stmt.make_nop(); - return + return; } self.super_statement(stmt, loc); // Do not leave tautological assignments around. if let StatementKind::Assign(box (lhs, ref rhs)) = stmt.kind - && let Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)) | Rvalue::CopyForDeref(rhs) = *rhs + && let Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)) | Rvalue::CopyForDeref(rhs) = + *rhs && lhs == rhs { stmt.make_nop(); diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 78845af0162..a83ccf8fc3c 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -19,7 +19,7 @@ const NESTED_INDENT: &str = " "; #[derive(Clone)] pub(super) enum BcbCounter { Counter { id: CounterId }, - Expression { id: ExpressionId, lhs: Operand, op: Op, rhs: Operand }, + Expression { id: ExpressionId }, } impl BcbCounter { @@ -27,10 +27,10 @@ impl BcbCounter { matches!(self, Self::Expression { .. }) } - pub(super) fn as_operand(&self) -> Operand { + pub(super) fn as_term(&self) -> CovTerm { match *self { - BcbCounter::Counter { id, .. } => Operand::Counter(id), - BcbCounter::Expression { id, .. } => Operand::Expression(id), + BcbCounter::Counter { id, .. } => CovTerm::Counter(id), + BcbCounter::Expression { id, .. } => CovTerm::Expression(id), } } } @@ -39,17 +39,7 @@ impl Debug for BcbCounter { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Counter { id, .. } => write!(fmt, "Counter({:?})", id.index()), - Self::Expression { id, lhs, op, rhs } => write!( - fmt, - "Expression({:?}) = {:?} {} {:?}", - id.index(), - lhs, - match op { - Op::Add => "+", - Op::Subtract => "-", - }, - rhs, - ), + Self::Expression { id } => write!(fmt, "Expression({:?})", id.index()), } } } @@ -58,7 +48,6 @@ impl Debug for BcbCounter { /// associated with nodes/edges in the BCB graph. pub(super) struct CoverageCounters { next_counter_id: CounterId, - next_expression_id: ExpressionId, /// Coverage counters/expressions that are associated with individual BCBs. bcb_counters: IndexVec<BasicCoverageBlock, Option<BcbCounter>>, @@ -69,10 +58,9 @@ pub(super) struct CoverageCounters { /// Only used by debug assertions, to verify that BCBs with incoming edge /// counters do not have their own physical counters (expressions are allowed). bcb_has_incoming_edge_counters: BitSet<BasicCoverageBlock>, - /// Expression nodes that are not directly associated with any particular - /// BCB/edge, but are needed as operands to more complex expressions. - /// These are always [`BcbCounter::Expression`]. - pub(super) intermediate_expressions: Vec<BcbCounter>, + /// Table of expression data, associating each expression ID with its + /// corresponding operator (+ or -) and its LHS/RHS operands. + expressions: IndexVec<ExpressionId, Expression>, } impl CoverageCounters { @@ -81,12 +69,10 @@ impl CoverageCounters { Self { next_counter_id: CounterId::START, - next_expression_id: ExpressionId::START, - bcb_counters: IndexVec::from_elem_n(None, num_bcbs), bcb_edge_counters: FxHashMap::default(), bcb_has_incoming_edge_counters: BitSet::new_empty(num_bcbs), - intermediate_expressions: Vec::new(), + expressions: IndexVec::new(), } } @@ -106,9 +92,9 @@ impl CoverageCounters { BcbCounter::Counter { id } } - fn make_expression(&mut self, lhs: Operand, op: Op, rhs: Operand) -> BcbCounter { - let id = self.next_expression(); - BcbCounter::Expression { id, lhs, op, rhs } + fn make_expression(&mut self, lhs: CovTerm, op: Op, rhs: CovTerm) -> BcbCounter { + let id = self.expressions.push(Expression { lhs, op, rhs }); + BcbCounter::Expression { id } } /// Counter IDs start from one and go up. @@ -118,19 +104,20 @@ impl CoverageCounters { next } - /// Expression IDs start from 0 and go up. - /// (Counter IDs and Expression IDs are distinguished by the `Operand` enum.) - fn next_expression(&mut self) -> ExpressionId { - let next = self.next_expression_id; - self.next_expression_id = self.next_expression_id + 1; - next + pub(super) fn num_counters(&self) -> usize { + self.next_counter_id.as_usize() + } + + #[cfg(test)] + pub(super) fn num_expressions(&self) -> usize { + self.expressions.len() } fn set_bcb_counter( &mut self, bcb: BasicCoverageBlock, counter_kind: BcbCounter, - ) -> Result<Operand, Error> { + ) -> Result<CovTerm, Error> { debug_assert!( // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also // have an expression (to be injected into an existing `BasicBlock` represented by this @@ -138,14 +125,14 @@ impl CoverageCounters { counter_kind.is_expression() || !self.bcb_has_incoming_edge_counters.contains(bcb), "attempt to add a `Counter` to a BCB target with existing incoming edge counters" ); - let operand = counter_kind.as_operand(); + let term = counter_kind.as_term(); if let Some(replaced) = self.bcb_counters[bcb].replace(counter_kind) { Error::from_string(format!( "attempt to set a BasicCoverageBlock coverage counter more than once; \ {bcb:?} already had counter {replaced:?}", )) } else { - Ok(operand) + Ok(term) } } @@ -154,7 +141,7 @@ impl CoverageCounters { from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock, counter_kind: BcbCounter, - ) -> Result<Operand, Error> { + ) -> Result<CovTerm, Error> { if level_enabled!(tracing::Level::DEBUG) { // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also // have an expression (to be injected into an existing `BasicBlock` represented by this @@ -167,14 +154,14 @@ impl CoverageCounters { } } self.bcb_has_incoming_edge_counters.insert(to_bcb); - let operand = counter_kind.as_operand(); + let term = counter_kind.as_term(); if let Some(replaced) = self.bcb_edge_counters.insert((from_bcb, to_bcb), counter_kind) { Error::from_string(format!( "attempt to set an edge counter more than once; from_bcb: \ {from_bcb:?} already had counter {replaced:?}", )) } else { - Ok(operand) + Ok(term) } } @@ -199,6 +186,10 @@ impl CoverageCounters { ) -> impl Iterator<Item = ((BasicCoverageBlock, BasicCoverageBlock), BcbCounter)> + '_ { self.bcb_edge_counters.drain() } + + pub(super) fn take_expressions(&mut self) -> IndexVec<ExpressionId, Expression> { + std::mem::take(&mut self.expressions) + } } /// Traverse the `CoverageGraph` and add either a `Counter` or `Expression` to every BCB, to be @@ -245,13 +236,13 @@ impl<'a> MakeBcbCounters<'a> { // the loop. The `traversal` state includes a `context_stack`, providing a way to know if // the current BCB is in one or more nested loops or not. let mut traversal = TraverseCoverageGraphWithLoops::new(&self.basic_coverage_blocks); - while let Some(bcb) = traversal.next(self.basic_coverage_blocks) { + while let Some(bcb) = traversal.next() { if bcb_has_coverage_spans(bcb) { debug!("{:?} has at least one coverage span. Get or make its counter", bcb); let branching_counter_operand = self.get_or_make_counter_operand(bcb)?; if self.bcb_needs_branch_counters(bcb) { - self.make_branch_counters(&mut traversal, bcb, branching_counter_operand)?; + self.make_branch_counters(&traversal, bcb, branching_counter_operand)?; } } else { debug!( @@ -274,9 +265,9 @@ impl<'a> MakeBcbCounters<'a> { fn make_branch_counters( &mut self, - traversal: &mut TraverseCoverageGraphWithLoops, + traversal: &TraverseCoverageGraphWithLoops<'_>, branching_bcb: BasicCoverageBlock, - branching_counter_operand: Operand, + branching_counter_operand: CovTerm, ) -> Result<(), Error> { let branches = self.bcb_branches(branching_bcb); debug!( @@ -324,8 +315,7 @@ impl<'a> MakeBcbCounters<'a> { sumup_counter_operand, ); debug!(" [new intermediate expression: {:?}]", intermediate_expression); - let intermediate_expression_operand = intermediate_expression.as_operand(); - self.coverage_counters.intermediate_expressions.push(intermediate_expression); + let intermediate_expression_operand = intermediate_expression.as_term(); some_sumup_counter_operand.replace(intermediate_expression_operand); } } @@ -356,7 +346,7 @@ impl<'a> MakeBcbCounters<'a> { Ok(()) } - fn get_or_make_counter_operand(&mut self, bcb: BasicCoverageBlock) -> Result<Operand, Error> { + fn get_or_make_counter_operand(&mut self, bcb: BasicCoverageBlock) -> Result<CovTerm, Error> { self.recursive_get_or_make_counter_operand(bcb, 1) } @@ -364,7 +354,7 @@ impl<'a> MakeBcbCounters<'a> { &mut self, bcb: BasicCoverageBlock, debug_indent_level: usize, - ) -> Result<Operand, Error> { + ) -> Result<CovTerm, Error> { // If the BCB already has a counter, return it. if let Some(counter_kind) = &self.coverage_counters.bcb_counters[bcb] { debug!( @@ -373,7 +363,7 @@ impl<'a> MakeBcbCounters<'a> { bcb, counter_kind, ); - return Ok(counter_kind.as_operand()); + return Ok(counter_kind.as_term()); } // A BCB with only one incoming edge gets a simple `Counter` (via `make_counter()`). @@ -437,8 +427,7 @@ impl<'a> MakeBcbCounters<'a> { NESTED_INDENT.repeat(debug_indent_level), intermediate_expression ); - let intermediate_expression_operand = intermediate_expression.as_operand(); - self.coverage_counters.intermediate_expressions.push(intermediate_expression); + let intermediate_expression_operand = intermediate_expression.as_term(); some_sumup_edge_counter_operand.replace(intermediate_expression_operand); } } @@ -460,7 +449,7 @@ impl<'a> MakeBcbCounters<'a> { &mut self, from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock, - ) -> Result<Operand, Error> { + ) -> Result<CovTerm, Error> { self.recursive_get_or_make_edge_counter_operand(from_bcb, to_bcb, 1) } @@ -469,7 +458,7 @@ impl<'a> MakeBcbCounters<'a> { from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock, debug_indent_level: usize, - ) -> Result<Operand, Error> { + ) -> Result<CovTerm, Error> { // If the source BCB has only one successor (assumed to be the given target), an edge // counter is unnecessary. Just get or make a counter for the source BCB. let successors = self.bcb_successors(from_bcb).iter(); @@ -488,7 +477,7 @@ impl<'a> MakeBcbCounters<'a> { to_bcb, counter_kind ); - return Ok(counter_kind.as_operand()); + return Ok(counter_kind.as_term()); } // Make a new counter to count this edge. @@ -507,21 +496,14 @@ impl<'a> MakeBcbCounters<'a> { /// found, select any branch. fn choose_preferred_expression_branch( &self, - traversal: &TraverseCoverageGraphWithLoops, + traversal: &TraverseCoverageGraphWithLoops<'_>, branches: &[BcbBranch], ) -> BcbBranch { - let branch_needs_a_counter = |branch: &BcbBranch| self.branch_has_no_counter(branch); - - let some_reloop_branch = self.find_some_reloop_branch(traversal, &branches); - if let Some(reloop_branch_without_counter) = - some_reloop_branch.filter(branch_needs_a_counter) - { - debug!( - "Selecting reloop_branch={:?} that still needs a counter, to get the \ - `Expression`", - reloop_branch_without_counter - ); - reloop_branch_without_counter + let good_reloop_branch = self.find_good_reloop_branch(traversal, &branches); + if let Some(reloop_branch) = good_reloop_branch { + assert!(self.branch_has_no_counter(&reloop_branch)); + debug!("Selecting reloop branch {reloop_branch:?} to get an expression"); + reloop_branch } else { let &branch_without_counter = branches.iter().find(|&branch| self.branch_has_no_counter(branch)).expect( @@ -538,75 +520,52 @@ impl<'a> MakeBcbCounters<'a> { } } - /// At most, one of the branches (or its edge, from the branching_bcb, if the branch has - /// multiple incoming edges) can have a counter computed by expression. - /// - /// If at least one of the branches leads outside of a loop (`found_loop_exit` is - /// true), and at least one other branch does not exit the loop (the first of which - /// is captured in `some_reloop_branch`), it's likely any reloop branch will be - /// executed far more often than loop exit branch, making the reloop branch a better - /// candidate for an expression. - fn find_some_reloop_branch( + /// Tries to find a branch that leads back to the top of a loop, and that + /// doesn't already have a counter. Such branches are good candidates to + /// be given an expression (instead of a physical counter), because they + /// will tend to be executed more times than a loop-exit branch. + fn find_good_reloop_branch( &self, - traversal: &TraverseCoverageGraphWithLoops, + traversal: &TraverseCoverageGraphWithLoops<'_>, branches: &[BcbBranch], ) -> Option<BcbBranch> { - let branch_needs_a_counter = |branch: &BcbBranch| self.branch_has_no_counter(branch); - - let mut some_reloop_branch: Option<BcbBranch> = None; - for context in traversal.context_stack.iter().rev() { - if let Some((backedge_from_bcbs, _)) = &context.loop_backedges { - let mut found_loop_exit = false; - for &branch in branches.iter() { - if backedge_from_bcbs.iter().any(|&backedge_from_bcb| { - self.bcb_dominates(branch.target_bcb, backedge_from_bcb) - }) { - if let Some(reloop_branch) = some_reloop_branch { - if self.branch_has_no_counter(&reloop_branch) { - // we already found a candidate reloop_branch that still - // needs a counter - continue; - } - } - // The path from branch leads back to the top of the loop. Set this - // branch as the `reloop_branch`. If this branch already has a - // counter, and we find another reloop branch that doesn't have a - // counter yet, that branch will be selected as the `reloop_branch` - // instead. - some_reloop_branch = Some(branch); - } else { - // The path from branch leads outside this loop - found_loop_exit = true; - } - if found_loop_exit - && some_reloop_branch.filter(branch_needs_a_counter).is_some() - { - // Found both a branch that exits the loop and a branch that returns - // to the top of the loop (`reloop_branch`), and the `reloop_branch` - // doesn't already have a counter. - break; + // Consider each loop on the current traversal context stack, top-down. + for reloop_bcbs in traversal.reloop_bcbs_per_loop() { + let mut all_branches_exit_this_loop = true; + + // Try to find a branch that doesn't exit this loop and doesn't + // already have a counter. + for &branch in branches { + // A branch is a reloop branch if it dominates any BCB that has + // an edge back to the loop header. (Other branches are exits.) + let is_reloop_branch = reloop_bcbs.iter().any(|&reloop_bcb| { + self.basic_coverage_blocks.dominates(branch.target_bcb, reloop_bcb) + }); + + if is_reloop_branch { + all_branches_exit_this_loop = false; + if self.branch_has_no_counter(&branch) { + // We found a good branch to be given an expression. + return Some(branch); } + // Keep looking for another reloop branch without a counter. + } else { + // This branch exits the loop. } - if !found_loop_exit { - debug!( - "No branches exit the loop, so any branch without an existing \ - counter can have the `Expression`." - ); - break; - } - if some_reloop_branch.is_some() { - debug!( - "Found a branch that exits the loop and a branch the loops back to \ - the top of the loop (`reloop_branch`). The `reloop_branch` will \ - get the `Expression`, as long as it still needs a counter." - ); - break; - } - // else all branches exited this loop context, so run the same checks with - // the outer loop(s) } + + if !all_branches_exit_this_loop { + // We found one or more reloop branches, but all of them already + // have counters. Let the caller choose one of the exit branches. + debug!("All reloop branches had counters; skip checking the other loops"); + return None; + } + + // All of the branches exit this loop, so keep looking for a good + // reloop branch for one of the outer loops. } - some_reloop_branch + + None } #[inline] @@ -652,9 +611,4 @@ impl<'a> MakeBcbCounters<'a> { fn bcb_has_one_path_to_target(&self, bcb: BasicCoverageBlock) -> bool { self.bcb_predecessors(bcb).len() <= 1 } - - #[inline] - fn bcb_dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool { - self.basic_coverage_blocks.dominates(dom, node) - } } diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 812633348e3..9a7adaada09 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -1,10 +1,12 @@ +use rustc_data_structures::captures::Captures; use rustc_data_structures::graph::dominators::{self, Dominators}; use rustc_data_structures::graph::{self, GraphSuccessors, WithNumNodes, WithStartNode}; use rustc_index::bit_set::BitSet; use rustc_index::{IndexSlice, IndexVec}; -use rustc_middle::mir::{self, BasicBlock, BasicBlockData, Terminator, TerminatorKind}; +use rustc_middle::mir::{self, BasicBlock, TerminatorKind}; use std::cmp::Ordering; +use std::collections::VecDeque; use std::ops::{Index, IndexMut}; /// A coverage-specific simplification of the MIR control flow graph (CFG). The `CoverageGraph`s @@ -36,9 +38,8 @@ impl CoverageGraph { } let bcb_data = &bcbs[bcb]; let mut bcb_successors = Vec::new(); - for successor in - bcb_filtered_successors(&mir_body, &bcb_data.terminator(mir_body).kind) - .filter_map(|successor_bb| bb_to_bcb[successor_bb]) + for successor in bcb_filtered_successors(&mir_body, bcb_data.last_bb()) + .filter_map(|successor_bb| bb_to_bcb[successor_bb]) { if !seen[successor] { seen[successor] = true; @@ -80,10 +81,9 @@ impl CoverageGraph { // intentionally omits unwind paths. // FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and // `catch_unwind()` handlers. - let mir_cfg_without_unwind = ShortCircuitPreorder::new(&mir_body, bcb_filtered_successors); let mut basic_blocks = Vec::new(); - for (bb, data) in mir_cfg_without_unwind { + for bb in short_circuit_preorder(mir_body, bcb_filtered_successors) { if let Some(last) = basic_blocks.last() { let predecessors = &mir_body.basic_blocks.predecessors()[bb]; if predecessors.len() > 1 || !predecessors.contains(last) { @@ -109,7 +109,7 @@ impl CoverageGraph { } basic_blocks.push(bb); - let term = data.terminator(); + let term = mir_body[bb].terminator(); match term.kind { TerminatorKind::Return { .. } @@ -316,11 +316,6 @@ impl BasicCoverageBlockData { pub fn last_bb(&self) -> BasicBlock { *self.basic_blocks.last().unwrap() } - - #[inline(always)] - pub fn terminator<'a, 'tcx>(&self, mir_body: &'a mir::Body<'tcx>) -> &'a Terminator<'tcx> { - &mir_body[self.last_bb()].terminator() - } } /// Represents a successor from a branching BasicCoverageBlock (such as the arms of a `SwitchInt`) @@ -362,26 +357,28 @@ impl std::fmt::Debug for BcbBranch { } } -// Returns the `Terminator`s non-unwind successors. +// Returns the subset of a block's successors that are relevant to the coverage +// graph, i.e. those that do not represent unwinds or unreachable branches. // FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and // `catch_unwind()` handlers. fn bcb_filtered_successors<'a, 'tcx>( body: &'a mir::Body<'tcx>, - term_kind: &'a TerminatorKind<'tcx>, -) -> Box<dyn Iterator<Item = BasicBlock> + 'a> { - Box::new( - match &term_kind { - // SwitchInt successors are never unwind, and all of them should be traversed. - TerminatorKind::SwitchInt { ref targets, .. } => { - None.into_iter().chain(targets.all_targets().into_iter().copied()) - } - // For all other kinds, return only the first successor, if any, and ignore unwinds. - // NOTE: `chain(&[])` is required to coerce the `option::iter` (from - // `next().into_iter()`) into the `mir::Successors` aliased type. - _ => term_kind.successors().next().into_iter().chain((&[]).into_iter().copied()), - } - .filter(move |&successor| body[successor].terminator().kind != TerminatorKind::Unreachable), - ) + bb: BasicBlock, +) -> impl Iterator<Item = BasicBlock> + Captures<'a> + Captures<'tcx> { + let terminator = body[bb].terminator(); + + let take_n_successors = match terminator.kind { + // SwitchInt successors are never unwinds, so all of them should be traversed. + TerminatorKind::SwitchInt { .. } => usize::MAX, + // For all other kinds, return only the first successor (if any), ignoring any + // unwind successors. + _ => 1, + }; + + terminator + .successors() + .take(take_n_successors) + .filter(move |&successor| body[successor].terminator().kind != TerminatorKind::Unreachable) } /// Maintains separate worklists for each loop in the BasicCoverageBlock CFG, plus one for the @@ -389,57 +386,72 @@ fn bcb_filtered_successors<'a, 'tcx>( /// ensures a loop is completely traversed before processing Blocks after the end of the loop. #[derive(Debug)] pub(super) struct TraversalContext { - /// From one or more backedges returning to a loop header. - pub loop_backedges: Option<(Vec<BasicCoverageBlock>, BasicCoverageBlock)>, - - /// worklist, to be traversed, of CoverageGraph in the loop with the given loop - /// backedges, such that the loop is the inner inner-most loop containing these - /// CoverageGraph - pub worklist: Vec<BasicCoverageBlock>, + /// BCB with one or more incoming loop backedges, indicating which loop + /// this context is for. + /// + /// If `None`, this is the non-loop context for the function as a whole. + loop_header: Option<BasicCoverageBlock>, + + /// Worklist of BCBs to be processed in this context. + worklist: VecDeque<BasicCoverageBlock>, } -pub(super) struct TraverseCoverageGraphWithLoops { - pub backedges: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>, - pub context_stack: Vec<TraversalContext>, +pub(super) struct TraverseCoverageGraphWithLoops<'a> { + basic_coverage_blocks: &'a CoverageGraph, + + backedges: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>, + context_stack: Vec<TraversalContext>, visited: BitSet<BasicCoverageBlock>, } -impl TraverseCoverageGraphWithLoops { - pub fn new(basic_coverage_blocks: &CoverageGraph) -> Self { - let start_bcb = basic_coverage_blocks.start_node(); +impl<'a> TraverseCoverageGraphWithLoops<'a> { + pub(super) fn new(basic_coverage_blocks: &'a CoverageGraph) -> Self { let backedges = find_loop_backedges(basic_coverage_blocks); - let context_stack = - vec![TraversalContext { loop_backedges: None, worklist: vec![start_bcb] }]; + + let worklist = VecDeque::from([basic_coverage_blocks.start_node()]); + let context_stack = vec![TraversalContext { loop_header: None, worklist }]; + // `context_stack` starts with a `TraversalContext` for the main function context (beginning // with the `start` BasicCoverageBlock of the function). New worklists are pushed to the top // of the stack as loops are entered, and popped off of the stack when a loop's worklist is // exhausted. let visited = BitSet::new_empty(basic_coverage_blocks.num_nodes()); - Self { backedges, context_stack, visited } + Self { basic_coverage_blocks, backedges, context_stack, visited } } - pub fn next(&mut self, basic_coverage_blocks: &CoverageGraph) -> Option<BasicCoverageBlock> { + /// For each loop on the loop context stack (top-down), yields a list of BCBs + /// within that loop that have an outgoing edge back to the loop header. + pub(super) fn reloop_bcbs_per_loop(&self) -> impl Iterator<Item = &[BasicCoverageBlock]> { + self.context_stack + .iter() + .rev() + .filter_map(|context| context.loop_header) + .map(|header_bcb| self.backedges[header_bcb].as_slice()) + } + + pub(super) fn next(&mut self) -> Option<BasicCoverageBlock> { debug!( "TraverseCoverageGraphWithLoops::next - context_stack: {:?}", self.context_stack.iter().rev().collect::<Vec<_>>() ); while let Some(context) = self.context_stack.last_mut() { - if let Some(next_bcb) = context.worklist.pop() { - if !self.visited.insert(next_bcb) { - debug!("Already visited: {:?}", next_bcb); + if let Some(bcb) = context.worklist.pop_front() { + if !self.visited.insert(bcb) { + debug!("Already visited: {bcb:?}"); continue; } - debug!("Visiting {:?}", next_bcb); - if self.backedges[next_bcb].len() > 0 { - debug!("{:?} is a loop header! Start a new TraversalContext...", next_bcb); + debug!("Visiting {bcb:?}"); + + if self.backedges[bcb].len() > 0 { + debug!("{bcb:?} is a loop header! Start a new TraversalContext..."); self.context_stack.push(TraversalContext { - loop_backedges: Some((self.backedges[next_bcb].clone(), next_bcb)), - worklist: Vec::new(), + loop_header: Some(bcb), + worklist: VecDeque::new(), }); } - self.extend_worklist(basic_coverage_blocks, next_bcb); - return Some(next_bcb); + self.add_successors_to_worklists(bcb); + return Some(bcb); } else { // Strip contexts with empty worklists from the top of the stack self.context_stack.pop(); @@ -449,13 +461,10 @@ impl TraverseCoverageGraphWithLoops { None } - pub fn extend_worklist( - &mut self, - basic_coverage_blocks: &CoverageGraph, - bcb: BasicCoverageBlock, - ) { - let successors = &basic_coverage_blocks.successors[bcb]; + pub fn add_successors_to_worklists(&mut self, bcb: BasicCoverageBlock) { + let successors = &self.basic_coverage_blocks.successors[bcb]; debug!("{:?} has {} successors:", bcb, successors.len()); + for &successor in successors { if successor == bcb { debug!( @@ -464,56 +473,44 @@ impl TraverseCoverageGraphWithLoops { bcb ); // Don't re-add this successor to the worklist. We are already processing it. + // FIXME: This claims to skip just the self-successor, but it actually skips + // all other successors as well. Does that matter? break; } - for context in self.context_stack.iter_mut().rev() { - // Add successors of the current BCB to the appropriate context. Successors that - // stay within a loop are added to the BCBs context worklist. Successors that - // exit the loop (they are not dominated by the loop header) must be reachable - // from other BCBs outside the loop, and they will be added to a different - // worklist. - // - // Branching blocks (with more than one successor) must be processed before - // blocks with only one successor, to prevent unnecessarily complicating - // `Expression`s by creating a Counter in a `BasicCoverageBlock` that the - // branching block would have given an `Expression` (or vice versa). - let (some_successor_to_add, some_loop_header) = - if let Some((_, loop_header)) = context.loop_backedges { - if basic_coverage_blocks.dominates(loop_header, successor) { - (Some(successor), Some(loop_header)) - } else { - (None, None) - } - } else { - (Some(successor), None) - }; - if let Some(successor_to_add) = some_successor_to_add { - if basic_coverage_blocks.successors[successor_to_add].len() > 1 { - debug!( - "{:?} successor is branching. Prioritize it at the beginning of \ - the {}", - successor_to_add, - if let Some(loop_header) = some_loop_header { - format!("worklist for the loop headed by {loop_header:?}") - } else { - String::from("non-loop worklist") - }, - ); - context.worklist.insert(0, successor_to_add); - } else { - debug!( - "{:?} successor is non-branching. Defer it to the end of the {}", - successor_to_add, - if let Some(loop_header) = some_loop_header { - format!("worklist for the loop headed by {loop_header:?}") - } else { - String::from("non-loop worklist") - }, - ); - context.worklist.push(successor_to_add); + + // Add successors of the current BCB to the appropriate context. Successors that + // stay within a loop are added to the BCBs context worklist. Successors that + // exit the loop (they are not dominated by the loop header) must be reachable + // from other BCBs outside the loop, and they will be added to a different + // worklist. + // + // Branching blocks (with more than one successor) must be processed before + // blocks with only one successor, to prevent unnecessarily complicating + // `Expression`s by creating a Counter in a `BasicCoverageBlock` that the + // branching block would have given an `Expression` (or vice versa). + + let context = self + .context_stack + .iter_mut() + .rev() + .find(|context| match context.loop_header { + Some(loop_header) => { + self.basic_coverage_blocks.dominates(loop_header, successor) } - break; - } + None => true, + }) + .unwrap_or_else(|| bug!("should always fall back to the root non-loop context")); + debug!("adding to worklist for {:?}", context.loop_header); + + // FIXME: The code below had debug messages claiming to add items to a + // particular end of the worklist, but was confused about which end was + // which. The existing behaviour has been preserved for now, but it's + // unclear what the intended behaviour was. + + if self.basic_coverage_blocks.successors[successor].len() > 1 { + context.worklist.push_back(successor); + } else { + context.worklist.push_front(successor); } } } @@ -553,66 +550,28 @@ pub(super) fn find_loop_backedges( backedges } -pub struct ShortCircuitPreorder< - 'a, - 'tcx, - F: Fn(&'a mir::Body<'tcx>, &'a TerminatorKind<'tcx>) -> Box<dyn Iterator<Item = BasicBlock> + 'a>, -> { +fn short_circuit_preorder<'a, 'tcx, F, Iter>( body: &'a mir::Body<'tcx>, - visited: BitSet<BasicBlock>, - worklist: Vec<BasicBlock>, filtered_successors: F, -} - -impl< - 'a, - 'tcx, - F: Fn(&'a mir::Body<'tcx>, &'a TerminatorKind<'tcx>) -> Box<dyn Iterator<Item = BasicBlock> + 'a>, -> ShortCircuitPreorder<'a, 'tcx, F> -{ - pub fn new( - body: &'a mir::Body<'tcx>, - filtered_successors: F, - ) -> ShortCircuitPreorder<'a, 'tcx, F> { - let worklist = vec![mir::START_BLOCK]; - - ShortCircuitPreorder { - body, - visited: BitSet::new_empty(body.basic_blocks.len()), - worklist, - filtered_successors, - } - } -} - -impl< - 'a, - 'tcx, - F: Fn(&'a mir::Body<'tcx>, &'a TerminatorKind<'tcx>) -> Box<dyn Iterator<Item = BasicBlock> + 'a>, -> Iterator for ShortCircuitPreorder<'a, 'tcx, F> +) -> impl Iterator<Item = BasicBlock> + Captures<'a> + Captures<'tcx> +where + F: Fn(&'a mir::Body<'tcx>, BasicBlock) -> Iter, + Iter: Iterator<Item = BasicBlock>, { - type Item = (BasicBlock, &'a BasicBlockData<'tcx>); + let mut visited = BitSet::new_empty(body.basic_blocks.len()); + let mut worklist = vec![mir::START_BLOCK]; - fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> { - while let Some(idx) = self.worklist.pop() { - if !self.visited.insert(idx) { + std::iter::from_fn(move || { + while let Some(bb) = worklist.pop() { + if !visited.insert(bb) { continue; } - let data = &self.body[idx]; - - if let Some(ref term) = data.terminator { - self.worklist.extend((self.filtered_successors)(&self.body, &term.kind)); - } + worklist.extend(filtered_successors(body, bb)); - return Some((idx, data)); + return Some(bb); } None - } - - fn size_hint(&self) -> (usize, Option<usize>) { - let size = self.body.basic_blocks.len() - self.visited.count(); - (size, Some(size)) - } + }) } diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index abf13519e9e..df4dccf0f0b 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -104,6 +104,7 @@ struct Instrumentor<'a, 'tcx> { function_source_hash: u64, basic_coverage_blocks: CoverageGraph, coverage_counters: CoverageCounters, + mappings: Vec<Mapping>, } impl<'a, 'tcx> Instrumentor<'a, 'tcx> { @@ -144,6 +145,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { function_source_hash, basic_coverage_blocks, coverage_counters, + mappings: Vec::new(), } } @@ -165,9 +167,6 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { // every coverage span has a `Counter` or `Expression` assigned to its `BasicCoverageBlock` // and all `Expression` dependencies (operands) are also generated, for any other // `BasicCoverageBlock`s not already associated with a coverage span. - // - // Intermediate expressions (used to compute other `Expression` values), which have no - // direct association with any `BasicCoverageBlock`, are accumulated inside `coverage_counters`. let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb); let result = self .coverage_counters @@ -193,24 +192,18 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { // are in fact counted, even though they don't directly contribute to counting // their own independent code region's coverage. self.inject_indirect_counters(); - - // Intermediate expressions will be injected as the final step, after generating - // debug output, if any. - //////////////////////////////////////////////////// }; if let Err(e) = result { bug!("Error processing: {:?}: {:?}", self.mir_body.source.def_id(), e.message) }; - //////////////////////////////////////////////////// - // Finally, inject the intermediate expressions collected along the way. - for intermediate_expression in &self.coverage_counters.intermediate_expressions { - inject_intermediate_expression( - self.mir_body, - self.make_mir_coverage_kind(intermediate_expression), - ); - } + self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { + function_source_hash: self.function_source_hash, + num_counters: self.coverage_counters.num_counters(), + expressions: self.coverage_counters.take_expressions(), + mappings: std::mem::take(&mut self.mappings), + })); } /// Injects a single [`StatementKind::Coverage`] for each BCB that has one @@ -226,18 +219,16 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { bug!("Every BasicCoverageBlock should have a Counter or Expression"); }); - // Convert the coverage spans into a vector of code regions to be - // associated with this BCB's coverage statement. - let code_regions = spans - .iter() - .map(|&span| make_code_region(source_map, file_name, span, body_span)) - .collect::<Vec<_>>(); + let term = counter_kind.as_term(); + self.mappings.extend(spans.iter().map(|&span| { + let code_region = make_code_region(source_map, file_name, span, body_span); + Mapping { code_region, term } + })); inject_statement( self.mir_body, self.make_mir_coverage_kind(&counter_kind), self.bcb_leader_bb(bcb), - code_regions, ); } } @@ -295,13 +286,10 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { self.mir_body, self.make_mir_coverage_kind(&counter_kind), inject_to_bb, - Vec::new(), ); } - BcbCounter::Expression { .. } => inject_intermediate_expression( - self.mir_body, - self.make_mir_coverage_kind(&counter_kind), - ), + // Experessions with no associated spans don't need to inject a statement. + BcbCounter::Expression { .. } => {} } } } @@ -323,12 +311,8 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { fn make_mir_coverage_kind(&self, counter_kind: &BcbCounter) -> CoverageKind { match *counter_kind { - BcbCounter::Counter { id } => { - CoverageKind::Counter { function_source_hash: self.function_source_hash, id } - } - BcbCounter::Expression { id, lhs, op, rhs } => { - CoverageKind::Expression { id, lhs, op, rhs } - } + BcbCounter::Counter { id } => CoverageKind::CounterIncrement { id }, + BcbCounter::Expression { id } => CoverageKind::ExpressionUsed { id }, } } } @@ -356,39 +340,17 @@ fn inject_edge_counter_basic_block( new_bb } -fn inject_statement( - mir_body: &mut mir::Body<'_>, - counter_kind: CoverageKind, - bb: BasicBlock, - code_regions: Vec<CodeRegion>, -) { - debug!(" injecting statement {counter_kind:?} for {bb:?} at code regions: {code_regions:?}"); +fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb: BasicBlock) { + debug!(" injecting statement {counter_kind:?} for {bb:?}"); let data = &mut mir_body[bb]; let source_info = data.terminator().source_info; let statement = Statement { source_info, - kind: StatementKind::Coverage(Box::new(Coverage { kind: counter_kind, code_regions })), + kind: StatementKind::Coverage(Box::new(Coverage { kind: counter_kind })), }; data.statements.insert(0, statement); } -// Non-code expressions are injected into the coverage map, without generating executable code. -fn inject_intermediate_expression(mir_body: &mut mir::Body<'_>, expression: CoverageKind) { - debug_assert!(matches!(expression, CoverageKind::Expression { .. })); - debug!(" injecting non-code expression {:?}", expression); - let inject_in_bb = mir::START_BLOCK; - let data = &mut mir_body[inject_in_bb]; - let source_info = data.terminator().source_info; - let statement = Statement { - source_info, - kind: StatementKind::Coverage(Box::new(Coverage { - kind: expression, - code_regions: Vec::new(), - })), - }; - data.statements.push(statement); -} - /// Convert the Span into its file name, start line and column, and end line and column fn make_code_region( source_map: &SourceMap, diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index 2c0164e765c..809407f897d 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -2,100 +2,31 @@ use super::*; use rustc_data_structures::captures::Captures; use rustc_middle::mir::coverage::*; -use rustc_middle::mir::{self, Body, Coverage, CoverageInfo}; +use rustc_middle::mir::{Body, Coverage, CoverageIdsInfo}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::def_id::DefId; /// A `query` provider for retrieving coverage information injected into MIR. pub(crate) fn provide(providers: &mut Providers) { - providers.coverageinfo = |tcx, def_id| coverageinfo(tcx, def_id); - providers.covered_code_regions = |tcx, def_id| covered_code_regions(tcx, def_id); + providers.coverage_ids_info = |tcx, def_id| coverage_ids_info(tcx, def_id); } -/// Coverage codegen needs to know the total number of counter IDs and expression IDs that have -/// been used by a function's coverage mappings. These totals are used to create vectors to hold -/// the relevant counter and expression data, and the maximum counter ID (+ 1) is also needed by -/// the `llvm.instrprof.increment` intrinsic. -/// -/// MIR optimization may split and duplicate some BasicBlock sequences, or optimize out some code -/// including injected counters. (It is OK if some counters are optimized out, but those counters -/// are still included in the total `num_counters` or `num_expressions`.) Simply counting the -/// calls may not work; but computing the number of counters or expressions by adding `1` to the -/// highest ID (for a given instrumented function) is valid. -/// -/// It's possible for a coverage expression to remain in MIR while one or both of its operands -/// have been optimized away. To avoid problems in codegen, we include those operands' IDs when -/// determining the maximum counter/expression ID, even if the underlying counter/expression is -/// no longer present. -struct CoverageVisitor { - max_counter_id: CounterId, - max_expression_id: ExpressionId, -} - -impl CoverageVisitor { - /// Updates `max_counter_id` to the maximum encountered counter ID. - #[inline(always)] - fn update_max_counter_id(&mut self, counter_id: CounterId) { - self.max_counter_id = self.max_counter_id.max(counter_id); - } - - /// Updates `max_expression_id` to the maximum encountered expression ID. - #[inline(always)] - fn update_max_expression_id(&mut self, expression_id: ExpressionId) { - self.max_expression_id = self.max_expression_id.max(expression_id); - } - - fn update_from_expression_operand(&mut self, operand: Operand) { - match operand { - Operand::Counter(id) => self.update_max_counter_id(id), - Operand::Expression(id) => self.update_max_expression_id(id), - Operand::Zero => {} - } - } - - fn visit_body(&mut self, body: &Body<'_>) { - for coverage in all_coverage_in_mir_body(body) { - self.visit_coverage(coverage); - } - } - - fn visit_coverage(&mut self, coverage: &Coverage) { - match coverage.kind { - CoverageKind::Counter { id, .. } => self.update_max_counter_id(id), - CoverageKind::Expression { id, lhs, rhs, .. } => { - self.update_max_expression_id(id); - self.update_from_expression_operand(lhs); - self.update_from_expression_operand(rhs); - } - CoverageKind::Unreachable => {} - } - } -} - -fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) -> CoverageInfo { +/// Query implementation for `coverage_ids_info`. +fn coverage_ids_info<'tcx>( + tcx: TyCtxt<'tcx>, + instance_def: ty::InstanceDef<'tcx>, +) -> CoverageIdsInfo { let mir_body = tcx.instance_mir(instance_def); - let mut coverage_visitor = CoverageVisitor { - max_counter_id: CounterId::START, - max_expression_id: ExpressionId::START, - }; - - coverage_visitor.visit_body(mir_body); - - // Add 1 to the highest IDs to get the total number of IDs. - CoverageInfo { - num_counters: (coverage_visitor.max_counter_id + 1).as_u32(), - num_expressions: (coverage_visitor.max_expression_id + 1).as_u32(), - } -} + let max_counter_id = all_coverage_in_mir_body(mir_body) + .filter_map(|coverage| match coverage.kind { + CoverageKind::CounterIncrement { id } => Some(id), + _ => None, + }) + .max() + .unwrap_or(CounterId::START); -fn covered_code_regions(tcx: TyCtxt<'_>, def_id: DefId) -> Vec<&CodeRegion> { - let body = mir_body(tcx, def_id); - all_coverage_in_mir_body(body) - // Coverage statements have a list of code regions (possibly empty). - .flat_map(|coverage| coverage.code_regions.as_slice()) - .collect() + CoverageIdsInfo { max_counter_id } } fn all_coverage_in_mir_body<'a, 'tcx>( @@ -115,11 +46,3 @@ fn is_inlined(body: &Body<'_>, statement: &Statement<'_>) -> bool { let scope_data = &body.source_scopes[statement.source_info.scope]; scope_data.inlined.is_some() || scope_data.inlined_parent_scope.is_some() } - -/// This function ensures we obtain the correct MIR for the given item irrespective of -/// whether that means const mir or runtime mir. For `const fn` this opts for runtime -/// mir. -fn mir_body(tcx: TyCtxt<'_>, def_id: DefId) -> &mir::Body<'_> { - let def = ty::InstanceDef::Item(def_id); - tcx.instance_mir(def) -} diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index dd87694f97c..f1a0f762041 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,15 +1,13 @@ -use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB}; +use std::cell::OnceCell; use rustc_data_structures::graph::WithNumNodes; use rustc_index::IndexVec; -use rustc_middle::mir::{ - self, AggregateKind, BasicBlock, FakeReadCause, Rvalue, Statement, StatementKind, Terminator, - TerminatorKind, -}; -use rustc_span::source_map::original_sp; -use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol}; +use rustc_middle::mir::{self, AggregateKind, Rvalue, Statement, StatementKind}; +use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol, DUMMY_SP}; -use std::cell::OnceCell; +use super::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; + +mod from_mir; pub(super) struct CoverageSpans { /// Map from BCBs to their list of coverage spans. @@ -53,27 +51,13 @@ impl CoverageSpans { } } -#[derive(Debug, Copy, Clone)] -pub(super) enum CoverageStatement { - Statement(BasicBlock, Span, usize), - Terminator(BasicBlock, Span), -} - -impl CoverageStatement { - pub fn span(&self) -> Span { - match self { - Self::Statement(_, span, _) | Self::Terminator(_, span) => *span, - } - } -} - /// A BCB is deconstructed into one or more `Span`s. Each `Span` maps to a `CoverageSpan` that /// references the originating BCB and one or more MIR `Statement`s and/or `Terminator`s. /// Initially, the `Span`s come from the `Statement`s and `Terminator`s, but subsequent /// transforms can combine adjacent `Span`s and `CoverageSpan` from the same BCB, merging the -/// `CoverageStatement` vectors, and the `Span`s to cover the extent of the combined `Span`s. +/// `merged_spans` vectors, and the `Span`s to cover the extent of the combined `Span`s. /// -/// Note: A `CoverageStatement` merged into another CoverageSpan may come from a `BasicBlock` that +/// Note: A span merged into another CoverageSpan may come from a `BasicBlock` that /// is not part of the `CoverageSpan` bcb if the statement was included because it's `Span` matches /// or is subsumed by the `Span` associated with this `CoverageSpan`, and it's `BasicBlock` /// `dominates()` the `BasicBlock`s in this `CoverageSpan`. @@ -83,7 +67,9 @@ struct CoverageSpan { pub expn_span: Span, pub current_macro_or_none: OnceCell<Option<Symbol>>, pub bcb: BasicCoverageBlock, - pub coverage_statements: Vec<CoverageStatement>, + /// List of all the original spans from MIR that have been merged into this + /// span. Mainly used to precisely skip over gaps when truncating a span. + pub merged_spans: Vec<Span>, pub is_closure: bool, } @@ -94,7 +80,7 @@ impl CoverageSpan { expn_span: fn_sig_span, current_macro_or_none: Default::default(), bcb: START_BCB, - coverage_statements: vec![], + merged_spans: vec![], is_closure: false, } } @@ -104,8 +90,6 @@ impl CoverageSpan { span: Span, expn_span: Span, bcb: BasicCoverageBlock, - bb: BasicBlock, - stmt_index: usize, ) -> Self { let is_closure = match statement.kind { StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => { @@ -119,23 +103,18 @@ impl CoverageSpan { expn_span, current_macro_or_none: Default::default(), bcb, - coverage_statements: vec![CoverageStatement::Statement(bb, span, stmt_index)], + merged_spans: vec![span], is_closure, } } - pub fn for_terminator( - span: Span, - expn_span: Span, - bcb: BasicCoverageBlock, - bb: BasicBlock, - ) -> Self { + pub fn for_terminator(span: Span, expn_span: Span, bcb: BasicCoverageBlock) -> Self { Self { span, expn_span, current_macro_or_none: Default::default(), bcb, - coverage_statements: vec![CoverageStatement::Terminator(bb, span)], + merged_spans: vec![span], is_closure: false, } } @@ -143,15 +122,13 @@ impl CoverageSpan { pub fn merge_from(&mut self, mut other: CoverageSpan) { debug_assert!(self.is_mergeable(&other)); self.span = self.span.to(other.span); - self.coverage_statements.append(&mut other.coverage_statements); + self.merged_spans.append(&mut other.merged_spans); } pub fn cutoff_statements_at(&mut self, cutoff_pos: BytePos) { - self.coverage_statements.retain(|covstmt| covstmt.span().hi() <= cutoff_pos); - if let Some(highest_covstmt) = - self.coverage_statements.iter().max_by_key(|covstmt| covstmt.span().hi()) - { - self.span = self.span.with_hi(highest_covstmt.span().hi()); + self.merged_spans.retain(|span| span.hi() <= cutoff_pos); + if let Some(max_hi) = self.merged_spans.iter().map(|span| span.hi()).max() { + self.span = self.span.with_hi(max_hi); } } @@ -182,11 +159,12 @@ impl CoverageSpan { /// If the span is part of a macro, and the macro is visible (expands directly to the given /// body_span), returns the macro name symbol. pub fn visible_macro(&self, body_span: Span) -> Option<Symbol> { - if let Some(current_macro) = self.current_macro() && self - .expn_span - .parent_callsite() - .unwrap_or_else(|| bug!("macro must have a parent")) - .eq_ctxt(body_span) + if let Some(current_macro) = self.current_macro() + && self + .expn_span + .parent_callsite() + .unwrap_or_else(|| bug!("macro must have a parent")) + .eq_ctxt(body_span) { return Some(current_macro); } @@ -205,13 +183,7 @@ impl CoverageSpan { /// * Merge spans that represent continuous (both in source code and control flow), non-branching /// execution /// * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures) -struct CoverageSpansGenerator<'a, 'tcx> { - /// The MIR, used to look up `BasicBlockData`. - mir_body: &'a mir::Body<'tcx>, - - /// A `Span` covering the signature of function for the MIR. - fn_sig_span: Span, - +struct CoverageSpansGenerator<'a> { /// A `Span` covering the function body of the MIR (typically from left curly brace to right /// curly brace). body_span: Span, @@ -221,7 +193,7 @@ struct CoverageSpansGenerator<'a, 'tcx> { /// The initial set of `CoverageSpan`s, sorted by `Span` (`lo` and `hi`) and by relative /// dominance between the `BasicCoverageBlock`s of equal `Span`s. - sorted_spans_iter: Option<std::vec::IntoIter<CoverageSpan>>, + sorted_spans_iter: std::vec::IntoIter<CoverageSpan>, /// The current `CoverageSpan` to compare to its `prev`, to possibly merge, discard, force the /// discard of the `prev` (and or `pending_dups`), or keep both (with `prev` moved to @@ -243,9 +215,6 @@ struct CoverageSpansGenerator<'a, 'tcx> { /// is mutated. prev_original_span: Span, - /// A copy of the expn_span from the prior iteration. - prev_expn_span: Option<Span>, - /// One or more `CoverageSpan`s with the same `Span` but different `BasicCoverageBlock`s, and /// no `BasicCoverageBlock` in this list dominates another `BasicCoverageBlock` in the list. /// If a new `curr` span also fits this criteria (compared to an existing list of @@ -261,7 +230,7 @@ struct CoverageSpansGenerator<'a, 'tcx> { refined_spans: Vec<CoverageSpan>, } -impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> { +impl<'a> CoverageSpansGenerator<'a> { /// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be /// counted. /// @@ -284,109 +253,79 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> { /// Note the resulting vector of `CoverageSpan`s may not be fully sorted (and does not need /// to be). pub(super) fn generate_coverage_spans( - mir_body: &'a mir::Body<'tcx>, + mir_body: &mir::Body<'_>, fn_sig_span: Span, // Ensured to be same SourceFile and SyntaxContext as `body_span` body_span: Span, basic_coverage_blocks: &'a CoverageGraph, ) -> Vec<CoverageSpan> { - let mut coverage_spans = Self { + let sorted_spans = from_mir::mir_to_initial_sorted_coverage_spans( mir_body, fn_sig_span, body_span, basic_coverage_blocks, - sorted_spans_iter: None, - refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2), + ); + + let coverage_spans = Self { + body_span, + basic_coverage_blocks, + sorted_spans_iter: sorted_spans.into_iter(), some_curr: None, - curr_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)), + curr_original_span: DUMMY_SP, some_prev: None, - prev_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)), - prev_expn_span: None, + prev_original_span: DUMMY_SP, pending_dups: Vec::new(), + refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2), }; - let sorted_spans = coverage_spans.mir_to_initial_sorted_coverage_spans(); - - coverage_spans.sorted_spans_iter = Some(sorted_spans.into_iter()); - coverage_spans.to_refined_spans() } - fn mir_to_initial_sorted_coverage_spans(&self) -> Vec<CoverageSpan> { - let mut initial_spans = - Vec::<CoverageSpan>::with_capacity(self.mir_body.basic_blocks.len() * 2); - for (bcb, bcb_data) in self.basic_coverage_blocks.iter_enumerated() { - initial_spans.extend(self.bcb_to_initial_coverage_spans(bcb, bcb_data)); - } - - if initial_spans.is_empty() { - // This can happen if, for example, the function is unreachable (contains only a - // `BasicBlock`(s) with an `Unreachable` terminator). - return initial_spans; - } - - initial_spans.push(CoverageSpan::for_fn_sig(self.fn_sig_span)); - - initial_spans.sort_by(|a, b| { - // First sort by span start. - Ord::cmp(&a.span.lo(), &b.span.lo()) - // If span starts are the same, sort by span end in reverse order. - // This ensures that if spans A and B are adjacent in the list, - // and they overlap but are not equal, then either: - // - Span A extends further left, or - // - Both have the same start and span A extends further right - .then_with(|| Ord::cmp(&a.span.hi(), &b.span.hi()).reverse()) - // If both spans are equal, sort the BCBs in dominator order, - // so that dominating BCBs come before other BCBs they dominate. - .then_with(|| self.basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb)) - // If two spans are otherwise identical, put closure spans first, - // as this seems to be what the refinement step expects. - .then_with(|| Ord::cmp(&a.is_closure, &b.is_closure).reverse()) - }); - - initial_spans - } - /// Iterate through the sorted `CoverageSpan`s, and return the refined list of merged and /// de-duplicated `CoverageSpan`s. fn to_refined_spans(mut self) -> Vec<CoverageSpan> { while self.next_coverage_span() { + // For the first span we don't have `prev` set, so most of the + // span-processing steps don't make sense yet. if self.some_prev.is_none() { debug!(" initial span"); - self.check_invoked_macro_name_span(); - } else if self.curr().is_mergeable(self.prev()) { - debug!(" same bcb (and neither is a closure), merge with prev={:?}", self.prev()); + self.maybe_push_macro_name_span(); + continue; + } + + // The remaining cases assume that `prev` and `curr` are set. + let prev = self.prev(); + let curr = self.curr(); + + if curr.is_mergeable(prev) { + debug!(" same bcb (and neither is a closure), merge with prev={prev:?}"); let prev = self.take_prev(); self.curr_mut().merge_from(prev); - self.check_invoked_macro_name_span(); + self.maybe_push_macro_name_span(); // Note that curr.span may now differ from curr_original_span - } else if self.prev_ends_before_curr() { + } else if prev.span.hi() <= curr.span.lo() { debug!( - " different bcbs and disjoint spans, so keep curr for next iter, and add \ - prev={:?}", - self.prev() + " different bcbs and disjoint spans, so keep curr for next iter, and add prev={prev:?}", ); let prev = self.take_prev(); self.push_refined_span(prev); - self.check_invoked_macro_name_span(); - } else if self.prev().is_closure { + self.maybe_push_macro_name_span(); + } else if prev.is_closure { // drop any equal or overlapping span (`curr`) and keep `prev` to test again in the // next iter debug!( - " curr overlaps a closure (prev). Drop curr and keep prev for next iter. \ - prev={:?}", - self.prev() + " curr overlaps a closure (prev). Drop curr and keep prev for next iter. prev={prev:?}", ); - self.take_curr(); - } else if self.curr().is_closure { + self.take_curr(); // Discards curr. + } else if curr.is_closure { self.carve_out_span_for_closure(); - } else if self.prev_original_span == self.curr().span { + } else if self.prev_original_span == curr.span { // Note that this compares the new (`curr`) span to `prev_original_span`. // In this branch, the actual span byte range of `prev_original_span` is not // important. What is important is knowing whether the new `curr` span was // **originally** the same as the original span of `prev()`. The original spans // reflect their original sort order, and for equal spans, conveys a partial // ordering based on CFG dominator priority. - if self.prev().is_macro_expansion() && self.curr().is_macro_expansion() { + if prev.is_macro_expansion() && curr.is_macro_expansion() { // Macros that expand to include branching (such as // `assert_eq!()`, `assert_ne!()`, `info!()`, `debug!()`, or // `trace!()`) typically generate callee spans with identical @@ -400,23 +339,24 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> { debug!( " curr and prev are part of a macro expansion, and curr has the same span \ as prev, but is in a different bcb. Drop curr and keep prev for next iter. \ - prev={:?}", - self.prev() + prev={prev:?}", ); - self.take_curr(); + self.take_curr(); // Discards curr. } else { - self.hold_pending_dups_unless_dominated(); + self.update_pending_dups(); } } else { self.cutoff_prev_at_overlapping_curr(); - self.check_invoked_macro_name_span(); + self.maybe_push_macro_name_span(); } } - debug!(" AT END, adding last prev={:?}", self.prev()); let prev = self.take_prev(); - let pending_dups = self.pending_dups.split_off(0); - for dup in pending_dups { + debug!(" AT END, adding last prev={prev:?}"); + + // Take `pending_dups` so that we can drain it while calling self methods. + // It is never used as a field after this point. + for dup in std::mem::take(&mut self.pending_dups) { debug!(" ...adding at least one pending dup={:?}", dup); self.push_refined_span(dup); } @@ -446,85 +386,40 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> { } fn push_refined_span(&mut self, covspan: CoverageSpan) { - let len = self.refined_spans.len(); - if len > 0 { - let last = &mut self.refined_spans[len - 1]; - if last.is_mergeable(&covspan) { - debug!( - "merging new refined span with last refined span, last={:?}, covspan={:?}", - last, covspan - ); - last.merge_from(covspan); - return; - } + if let Some(last) = self.refined_spans.last_mut() + && last.is_mergeable(&covspan) + { + // Instead of pushing the new span, merge it with the last refined span. + debug!(?last, ?covspan, "merging new refined span with last refined span"); + last.merge_from(covspan); + } else { + self.refined_spans.push(covspan); } - self.refined_spans.push(covspan) } - fn check_invoked_macro_name_span(&mut self) { - if let Some(visible_macro) = self.curr().visible_macro(self.body_span) { - if !self - .prev_expn_span - .is_some_and(|prev_expn_span| self.curr().expn_span.ctxt() == prev_expn_span.ctxt()) - { - let merged_prefix_len = self.curr_original_span.lo() - self.curr().span.lo(); - let after_macro_bang = - merged_prefix_len + BytePos(visible_macro.as_str().len() as u32 + 1); - let mut macro_name_cov = self.curr().clone(); - self.curr_mut().span = - self.curr().span.with_lo(self.curr().span.lo() + after_macro_bang); - macro_name_cov.span = - macro_name_cov.span.with_hi(macro_name_cov.span.lo() + after_macro_bang); - debug!( - " and curr starts a new macro expansion, so add a new span just for \ - the macro `{}!`, new span={:?}", - visible_macro, macro_name_cov - ); - self.push_refined_span(macro_name_cov); - } + /// If `curr` is part of a new macro expansion, carve out and push a separate + /// span that ends just after the macro name and its subsequent `!`. + fn maybe_push_macro_name_span(&mut self) { + let curr = self.curr(); + + let Some(visible_macro) = curr.visible_macro(self.body_span) else { return }; + if let Some(prev) = &self.some_prev + && prev.expn_span.eq_ctxt(curr.expn_span) + { + return; } - } - // Generate a set of `CoverageSpan`s from the filtered set of `Statement`s and `Terminator`s of - // the `BasicBlock`(s) in the given `BasicCoverageBlockData`. One `CoverageSpan` is generated - // for each `Statement` and `Terminator`. (Note that subsequent stages of coverage analysis will - // merge some `CoverageSpan`s, at which point a `CoverageSpan` may represent multiple - // `Statement`s and/or `Terminator`s.) - fn bcb_to_initial_coverage_spans( - &self, - bcb: BasicCoverageBlock, - bcb_data: &'a BasicCoverageBlockData, - ) -> Vec<CoverageSpan> { - bcb_data - .basic_blocks - .iter() - .flat_map(|&bb| { - let data = &self.mir_body[bb]; - data.statements - .iter() - .enumerate() - .filter_map(move |(index, statement)| { - filtered_statement_span(statement).map(|span| { - CoverageSpan::for_statement( - statement, - function_source_span(span, self.body_span), - span, - bcb, - bb, - index, - ) - }) - }) - .chain(filtered_terminator_span(data.terminator()).map(|span| { - CoverageSpan::for_terminator( - function_source_span(span, self.body_span), - span, - bcb, - bb, - ) - })) - }) - .collect() + let merged_prefix_len = self.curr_original_span.lo() - curr.span.lo(); + let after_macro_bang = merged_prefix_len + BytePos(visible_macro.as_str().len() as u32 + 1); + let mut macro_name_cov = curr.clone(); + self.curr_mut().span = curr.span.with_lo(curr.span.lo() + after_macro_bang); + macro_name_cov.span = + macro_name_cov.span.with_hi(macro_name_cov.span.lo() + after_macro_bang); + debug!( + " and curr starts a new macro expansion, so add a new span just for \ + the macro `{visible_macro}!`, new span={macro_name_cov:?}", + ); + self.push_refined_span(macro_name_cov); } fn curr(&self) -> &CoverageSpan { @@ -539,6 +434,12 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> { .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr")) } + /// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the + /// `curr` coverage span. + fn take_curr(&mut self) -> CoverageSpan { + self.some_curr.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr")) + } + fn prev(&self) -> &CoverageSpan { self.some_prev .as_ref() @@ -564,82 +465,78 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> { /// `pending_dups` could have as few as one span) /// In either case, no more spans will match the span of `pending_dups`, so /// add the `pending_dups` if they don't overlap `curr`, and clear the list. - fn check_pending_dups(&mut self) { - if let Some(dup) = self.pending_dups.last() && dup.span != self.prev().span { - debug!( - " SAME spans, but pending_dups are NOT THE SAME, so BCBs matched on \ - previous iteration, or prev started a new disjoint span" - ); - if dup.span.hi() <= self.curr().span.lo() { - let pending_dups = self.pending_dups.split_off(0); - for dup in pending_dups.into_iter() { - debug!(" ...adding at least one pending={:?}", dup); - self.push_refined_span(dup); - } - } else { - self.pending_dups.clear(); + fn maybe_flush_pending_dups(&mut self) { + let Some(last_dup) = self.pending_dups.last() else { return }; + if last_dup.span == self.prev().span { + return; + } + + debug!( + " SAME spans, but pending_dups are NOT THE SAME, so BCBs matched on \ + previous iteration, or prev started a new disjoint span" + ); + if last_dup.span.hi() <= self.curr().span.lo() { + // Temporarily steal `pending_dups` into a local, so that we can + // drain it while calling other self methods. + let mut pending_dups = std::mem::take(&mut self.pending_dups); + for dup in pending_dups.drain(..) { + debug!(" ...adding at least one pending={:?}", dup); + self.push_refined_span(dup); } + // The list of dups is now empty, but we can recycle its capacity. + assert!(pending_dups.is_empty() && self.pending_dups.is_empty()); + self.pending_dups = pending_dups; + } else { + self.pending_dups.clear(); } } /// Advance `prev` to `curr` (if any), and `curr` to the next `CoverageSpan` in sorted order. fn next_coverage_span(&mut self) -> bool { if let Some(curr) = self.some_curr.take() { - self.prev_expn_span = Some(curr.expn_span); self.some_prev = Some(curr); self.prev_original_span = self.curr_original_span; } - while let Some(curr) = self.sorted_spans_iter.as_mut().unwrap().next() { + while let Some(curr) = self.sorted_spans_iter.next() { debug!("FOR curr={:?}", curr); - if self.some_prev.is_some() && self.prev_starts_after_next(&curr) { + if let Some(prev) = &self.some_prev && prev.span.lo() > curr.span.lo() { + // Skip curr because prev has already advanced beyond the end of curr. + // This can only happen if a prior iteration updated `prev` to skip past + // a region of code, such as skipping past a closure. debug!( " prev.span starts after curr.span, so curr will be dropped (skipping past \ - closure?); prev={:?}", - self.prev() + closure?); prev={prev:?}", ); } else { // Save a copy of the original span for `curr` in case the `CoverageSpan` is changed // by `self.curr_mut().merge_from(prev)`. self.curr_original_span = curr.span; self.some_curr.replace(curr); - self.check_pending_dups(); + self.maybe_flush_pending_dups(); return true; } } false } - /// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the - /// `curr` coverage span. - fn take_curr(&mut self) -> CoverageSpan { - self.some_curr.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr")) - } - - /// Returns true if the curr span should be skipped because prev has already advanced beyond the - /// end of curr. This can only happen if a prior iteration updated `prev` to skip past a region - /// of code, such as skipping past a closure. - fn prev_starts_after_next(&self, next_curr: &CoverageSpan) -> bool { - self.prev().span.lo() > next_curr.span.lo() - } - - /// Returns true if the curr span starts past the end of the prev span, which means they don't - /// overlap, so we now know the prev can be added to the refined coverage spans. - fn prev_ends_before_curr(&self) -> bool { - self.prev().span.hi() <= self.curr().span.lo() - } - /// If `prev`s span extends left of the closure (`curr`), carve out the closure's span from /// `prev`'s span. (The closure's coverage counters will be injected when processing the /// closure's own MIR.) Add the portion of the span to the left of the closure; and if the span /// extends to the right of the closure, update `prev` to that portion of the span. For any /// `pending_dups`, repeat the same process. fn carve_out_span_for_closure(&mut self) { - let curr_span = self.curr().span; - let left_cutoff = curr_span.lo(); - let right_cutoff = curr_span.hi(); - let has_pre_closure_span = self.prev().span.lo() < right_cutoff; - let has_post_closure_span = self.prev().span.hi() > right_cutoff; - let mut pending_dups = self.pending_dups.split_off(0); + let prev = self.prev(); + let curr = self.curr(); + + let left_cutoff = curr.span.lo(); + let right_cutoff = curr.span.hi(); + let has_pre_closure_span = prev.span.lo() < right_cutoff; + let has_post_closure_span = prev.span.hi() > right_cutoff; + + // Temporarily steal `pending_dups` into a local, so that we can + // mutate and/or drain it while calling other self methods. + let mut pending_dups = std::mem::take(&mut self.pending_dups); + if has_pre_closure_span { let mut pre_closure = self.prev().clone(); pre_closure.span = pre_closure.span.with_hi(left_cutoff); @@ -653,6 +550,7 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> { } self.push_refined_span(pre_closure); } + if has_post_closure_span { // Mutate `prev.span()` to start after the closure (and discard curr). // (**NEVER** update `prev_original_span` because it affects the assumptions @@ -663,12 +561,15 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> { debug!(" ...and at least one overlapping dup={:?}", dup); dup.span = dup.span.with_lo(right_cutoff); } - self.pending_dups.append(&mut pending_dups); - let closure_covspan = self.take_curr(); + let closure_covspan = self.take_curr(); // Prevent this curr from becoming prev. self.push_refined_span(closure_covspan); // since self.prev() was already updated } else { pending_dups.clear(); } + + // Restore the modified post-closure spans, or the empty vector's capacity. + assert!(self.pending_dups.is_empty()); + self.pending_dups = pending_dups; } /// Called if `curr.span` equals `prev_original_span` (and potentially equal to all @@ -685,26 +586,28 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> { /// neither `CoverageSpan` dominates the other, both (or possibly more than two) are held, /// until their disposition is determined. In this latter case, the `prev` dup is moved into /// `pending_dups` so the new `curr` dup can be moved to `prev` for the next iteration. - fn hold_pending_dups_unless_dominated(&mut self) { + fn update_pending_dups(&mut self) { + let prev_bcb = self.prev().bcb; + let curr_bcb = self.curr().bcb; + // Equal coverage spans are ordered by dominators before dominated (if any), so it should be // impossible for `curr` to dominate any previous `CoverageSpan`. - debug_assert!(!self.span_bcb_dominates(self.curr(), self.prev())); + debug_assert!(!self.basic_coverage_blocks.dominates(curr_bcb, prev_bcb)); let initial_pending_count = self.pending_dups.len(); if initial_pending_count > 0 { - let mut pending_dups = self.pending_dups.split_off(0); - pending_dups.retain(|dup| !self.span_bcb_dominates(dup, self.curr())); - self.pending_dups.append(&mut pending_dups); - if self.pending_dups.len() < initial_pending_count { + self.pending_dups + .retain(|dup| !self.basic_coverage_blocks.dominates(dup.bcb, curr_bcb)); + + let n_discarded = initial_pending_count - self.pending_dups.len(); + if n_discarded > 0 { debug!( - " discarded {} of {} pending_dups that dominated curr", - initial_pending_count - self.pending_dups.len(), - initial_pending_count + " discarded {n_discarded} of {initial_pending_count} pending_dups that dominated curr", ); } } - if self.span_bcb_dominates(self.prev(), self.curr()) { + if self.basic_coverage_blocks.dominates(prev_bcb, curr_bcb) { debug!( " different bcbs but SAME spans, and prev dominates curr. Discard prev={:?}", self.prev() @@ -757,7 +660,7 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> { if self.pending_dups.is_empty() { let curr_span = self.curr().span; self.prev_mut().cutoff_statements_at(curr_span.lo()); - if self.prev().coverage_statements.is_empty() { + if self.prev().merged_spans.is_empty() { debug!(" ... no non-overlapping statements to add"); } else { debug!(" ... adding modified prev={:?}", self.prev()); @@ -769,109 +672,4 @@ impl<'a, 'tcx> CoverageSpansGenerator<'a, 'tcx> { self.pending_dups.clear(); } } - - fn span_bcb_dominates(&self, dom_covspan: &CoverageSpan, covspan: &CoverageSpan) -> bool { - self.basic_coverage_blocks.dominates(dom_covspan.bcb, covspan.bcb) - } -} - -/// If the MIR `Statement` has a span contributive to computing coverage spans, -/// return it; otherwise return `None`. -fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> { - match statement.kind { - // These statements have spans that are often outside the scope of the executed source code - // for their parent `BasicBlock`. - StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - // Coverage should not be encountered, but don't inject coverage coverage - | StatementKind::Coverage(_) - // Ignore `ConstEvalCounter`s - | StatementKind::ConstEvalCounter - // Ignore `Nop`s - | StatementKind::Nop => None, - - // FIXME(#78546): MIR InstrumentCoverage - Can the source_info.span for `FakeRead` - // statements be more consistent? - // - // FakeReadCause::ForGuardBinding, in this example: - // match somenum { - // x if x < 1 => { ... } - // }... - // The BasicBlock within the match arm code included one of these statements, but the span - // for it covered the `1` in this source. The actual statements have nothing to do with that - // source span: - // FakeRead(ForGuardBinding, _4); - // where `_4` is: - // _4 = &_1; (at the span for the first `x`) - // and `_1` is the `Place` for `somenum`. - // - // If and when the Issue is resolved, remove this special case match pattern: - StatementKind::FakeRead(box (FakeReadCause::ForGuardBinding, _)) => None, - - // Retain spans from all other statements - StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding` - | StatementKind::Intrinsic(..) - | StatementKind::Assign(_) - | StatementKind::SetDiscriminant { .. } - | StatementKind::Deinit(..) - | StatementKind::Retag(_, _) - | StatementKind::PlaceMention(..) - | StatementKind::AscribeUserType(_, _) => { - Some(statement.source_info.span) - } - } -} - -/// If the MIR `Terminator` has a span contributive to computing coverage spans, -/// return it; otherwise return `None`. -fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Span> { - match terminator.kind { - // These terminators have spans that don't positively contribute to computing a reasonable - // span of actually executed source code. (For example, SwitchInt terminators extracted from - // an `if condition { block }` has a span that includes the executed block, if true, - // but for coverage, the code region executed, up to *and* through the SwitchInt, - // actually stops before the if's block.) - TerminatorKind::Unreachable // Unreachable blocks are not connected to the MIR CFG - | TerminatorKind::Assert { .. } - | TerminatorKind::Drop { .. } - | TerminatorKind::SwitchInt { .. } - // For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`. - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::Goto { .. } => None, - - // Call `func` operand can have a more specific span when part of a chain of calls - | TerminatorKind::Call { ref func, .. } => { - let mut span = terminator.source_info.span; - if let mir::Operand::Constant(box constant) = func { - if constant.span.lo() > span.lo() { - span = span.with_lo(constant.span.lo()); - } - } - Some(span) - } - - // Retain spans from all other terminators - TerminatorKind::UnwindResume - | TerminatorKind::UnwindTerminate(_) - | TerminatorKind::Return - | TerminatorKind::Yield { .. } - | TerminatorKind::GeneratorDrop - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::InlineAsm { .. } => { - Some(terminator.source_info.span) - } - } -} - -/// Returns an extrapolated span (pre-expansion[^1]) corresponding to a range -/// within the function's body source. This span is guaranteed to be contained -/// within, or equal to, the `body_span`. If the extrapolated span is not -/// contained within the `body_span`, the `body_span` is returned. -/// -/// [^1]Expansions result from Rust syntax including macros, syntactic sugar, -/// etc.). -#[inline] -fn function_source_span(span: Span, body_span: Span) -> Span { - let original_span = original_sp(span, body_span).with_ctxt(body_span.ctxt()); - if body_span.contains(original_span) { original_span } else { body_span } } diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs new file mode 100644 index 00000000000..4c20997e633 --- /dev/null +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -0,0 +1,184 @@ +use rustc_middle::mir::{ + self, FakeReadCause, Statement, StatementKind, Terminator, TerminatorKind, +}; +use rustc_span::Span; + +use crate::coverage::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; +use crate::coverage::spans::CoverageSpan; + +pub(super) fn mir_to_initial_sorted_coverage_spans( + mir_body: &mir::Body<'_>, + fn_sig_span: Span, + body_span: Span, + basic_coverage_blocks: &CoverageGraph, +) -> Vec<CoverageSpan> { + let mut initial_spans = Vec::<CoverageSpan>::with_capacity(mir_body.basic_blocks.len() * 2); + for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() { + initial_spans.extend(bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data)); + } + + if initial_spans.is_empty() { + // This can happen if, for example, the function is unreachable (contains only a + // `BasicBlock`(s) with an `Unreachable` terminator). + return initial_spans; + } + + initial_spans.push(CoverageSpan::for_fn_sig(fn_sig_span)); + + initial_spans.sort_by(|a, b| { + // First sort by span start. + Ord::cmp(&a.span.lo(), &b.span.lo()) + // If span starts are the same, sort by span end in reverse order. + // This ensures that if spans A and B are adjacent in the list, + // and they overlap but are not equal, then either: + // - Span A extends further left, or + // - Both have the same start and span A extends further right + .then_with(|| Ord::cmp(&a.span.hi(), &b.span.hi()).reverse()) + // If both spans are equal, sort the BCBs in dominator order, + // so that dominating BCBs come before other BCBs they dominate. + .then_with(|| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb)) + // If two spans are otherwise identical, put closure spans first, + // as this seems to be what the refinement step expects. + .then_with(|| Ord::cmp(&a.is_closure, &b.is_closure).reverse()) + }); + + initial_spans +} + +// Generate a set of `CoverageSpan`s from the filtered set of `Statement`s and `Terminator`s of +// the `BasicBlock`(s) in the given `BasicCoverageBlockData`. One `CoverageSpan` is generated +// for each `Statement` and `Terminator`. (Note that subsequent stages of coverage analysis will +// merge some `CoverageSpan`s, at which point a `CoverageSpan` may represent multiple +// `Statement`s and/or `Terminator`s.) +fn bcb_to_initial_coverage_spans( + mir_body: &mir::Body<'_>, + body_span: Span, + bcb: BasicCoverageBlock, + bcb_data: &BasicCoverageBlockData, +) -> Vec<CoverageSpan> { + bcb_data + .basic_blocks + .iter() + .flat_map(|&bb| { + let data = &mir_body[bb]; + data.statements + .iter() + .filter_map(move |statement| { + filtered_statement_span(statement).map(|span| { + CoverageSpan::for_statement( + statement, + function_source_span(span, body_span), + span, + bcb, + ) + }) + }) + .chain(filtered_terminator_span(data.terminator()).map(|span| { + CoverageSpan::for_terminator(function_source_span(span, body_span), span, bcb) + })) + }) + .collect() +} + +/// If the MIR `Statement` has a span contributive to computing coverage spans, +/// return it; otherwise return `None`. +fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span> { + match statement.kind { + // These statements have spans that are often outside the scope of the executed source code + // for their parent `BasicBlock`. + StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + // Coverage should not be encountered, but don't inject coverage coverage + | StatementKind::Coverage(_) + // Ignore `ConstEvalCounter`s + | StatementKind::ConstEvalCounter + // Ignore `Nop`s + | StatementKind::Nop => None, + + // FIXME(#78546): MIR InstrumentCoverage - Can the source_info.span for `FakeRead` + // statements be more consistent? + // + // FakeReadCause::ForGuardBinding, in this example: + // match somenum { + // x if x < 1 => { ... } + // }... + // The BasicBlock within the match arm code included one of these statements, but the span + // for it covered the `1` in this source. The actual statements have nothing to do with that + // source span: + // FakeRead(ForGuardBinding, _4); + // where `_4` is: + // _4 = &_1; (at the span for the first `x`) + // and `_1` is the `Place` for `somenum`. + // + // If and when the Issue is resolved, remove this special case match pattern: + StatementKind::FakeRead(box (FakeReadCause::ForGuardBinding, _)) => None, + + // Retain spans from all other statements + StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding` + | StatementKind::Intrinsic(..) + | StatementKind::Assign(_) + | StatementKind::SetDiscriminant { .. } + | StatementKind::Deinit(..) + | StatementKind::Retag(_, _) + | StatementKind::PlaceMention(..) + | StatementKind::AscribeUserType(_, _) => { + Some(statement.source_info.span) + } + } +} + +/// If the MIR `Terminator` has a span contributive to computing coverage spans, +/// return it; otherwise return `None`. +fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option<Span> { + match terminator.kind { + // These terminators have spans that don't positively contribute to computing a reasonable + // span of actually executed source code. (For example, SwitchInt terminators extracted from + // an `if condition { block }` has a span that includes the executed block, if true, + // but for coverage, the code region executed, up to *and* through the SwitchInt, + // actually stops before the if's block.) + TerminatorKind::Unreachable // Unreachable blocks are not connected to the MIR CFG + | TerminatorKind::Assert { .. } + | TerminatorKind::Drop { .. } + | TerminatorKind::SwitchInt { .. } + // For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`. + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::Goto { .. } => None, + + // Call `func` operand can have a more specific span when part of a chain of calls + | TerminatorKind::Call { ref func, .. } => { + let mut span = terminator.source_info.span; + if let mir::Operand::Constant(box constant) = func { + if constant.span.lo() > span.lo() { + span = span.with_lo(constant.span.lo()); + } + } + Some(span) + } + + // Retain spans from all other terminators + TerminatorKind::UnwindResume + | TerminatorKind::UnwindTerminate(_) + | TerminatorKind::Return + | TerminatorKind::Yield { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::FalseUnwind { .. } + | TerminatorKind::InlineAsm { .. } => { + Some(terminator.source_info.span) + } + } +} + +/// Returns an extrapolated span (pre-expansion[^1]) corresponding to a range +/// within the function's body source. This span is guaranteed to be contained +/// within, or equal to, the `body_span`. If the extrapolated span is not +/// contained within the `body_span`, the `body_span` is returned. +/// +/// [^1]Expansions result from Rust syntax including macros, syntactic sugar, +/// etc.). +#[inline] +fn function_source_span(span: Span, body_span: Span) -> Span { + use rustc_span::source_map::original_sp; + + let original_span = original_sp(span, body_span).with_ctxt(body_span.ctxt()); + if body_span.contains(original_span) { original_span } else { body_span } +} diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index 7476d3ce927..795cbce963d 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -241,7 +241,7 @@ fn print_coverage_graphviz( " {:?} [label=\"{:?}: {}\"];\n{}", bcb, bcb, - bcb_data.terminator(mir_body).kind.name(), + mir_body[bcb_data.last_bb()].terminator().kind.name(), basic_coverage_blocks .successors(bcb) .map(|successor| { format!(" {:?} -> {:?};", bcb, successor) }) @@ -628,7 +628,7 @@ fn test_traverse_coverage_with_loops() { let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); let mut traversed_in_order = Vec::new(); let mut traversal = graph::TraverseCoverageGraphWithLoops::new(&basic_coverage_blocks); - while let Some(bcb) = traversal.next(&basic_coverage_blocks) { + while let Some(bcb) = traversal.next() { traversed_in_order.push(bcb); } @@ -656,7 +656,7 @@ fn test_make_bcb_counters() { coverage_counters .make_bcb_counters(&mut basic_coverage_blocks, bcb_has_coverage_spans) .expect("should be Ok"); - assert_eq!(coverage_counters.intermediate_expressions.len(), 0); + assert_eq!(coverage_counters.num_expressions(), 0); let_bcb!(1); assert_eq!( diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs new file mode 100644 index 00000000000..24d081f2ac9 --- /dev/null +++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs @@ -0,0 +1,119 @@ +use rustc_attr::InlineAttr; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::LocalDefId; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::*; +use rustc_middle::query::Providers; +use rustc_middle::ty::TyCtxt; +use rustc_session::config::OptLevel; + +pub fn provide(providers: &mut Providers) { + providers.cross_crate_inlinable = cross_crate_inlinable; +} + +fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id); + // If this has an extern indicator, then this function is globally shared and thus will not + // generate cgu-internal copies which would make it cross-crate inlinable. + if codegen_fn_attrs.contains_extern_indicator() { + return false; + } + + // Obey source annotations first; this is important because it means we can use + // #[inline(never)] to force code generation. + match codegen_fn_attrs.inline { + InlineAttr::Never => return false, + InlineAttr::Hint | InlineAttr::Always => return true, + _ => {} + } + + // This just reproduces the logic from Instance::requires_inline. + match tcx.def_kind(def_id) { + DefKind::Ctor(..) | DefKind::Closure => return true, + DefKind::Fn | DefKind::AssocFn => {} + _ => return false, + } + + // Don't do any inference when incremental compilation is enabled; the additional inlining that + // inference permits also creates more work for small edits. + if tcx.sess.opts.incremental.is_some() { + return false; + } + + // Don't do any inference unless optimizations are enabled. + if matches!(tcx.sess.opts.optimize, OptLevel::No) { + return false; + } + + if !tcx.is_mir_available(def_id) { + return false; + } + + let mir = tcx.optimized_mir(def_id); + let mut checker = + CostChecker { tcx, callee_body: mir, calls: 0, statements: 0, landing_pads: 0, resumes: 0 }; + checker.visit_body(mir); + checker.calls == 0 + && checker.resumes == 0 + && checker.landing_pads == 0 + && checker.statements + <= tcx.sess.opts.unstable_opts.cross_crate_inline_threshold.unwrap_or(100) +} + +struct CostChecker<'b, 'tcx> { + tcx: TyCtxt<'tcx>, + callee_body: &'b Body<'tcx>, + calls: usize, + statements: usize, + landing_pads: usize, + resumes: usize, +} + +impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { + fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) { + // Don't count StorageLive/StorageDead in the inlining cost. + match statement.kind { + StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + | StatementKind::Deinit(_) + | StatementKind::Nop => {} + _ => self.statements += 1, + } + } + + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, _: Location) { + let tcx = self.tcx; + match terminator.kind { + TerminatorKind::Drop { ref place, unwind, .. } => { + let ty = place.ty(self.callee_body, tcx).ty; + if !ty.is_trivially_pure_clone_copy() { + self.calls += 1; + if let UnwindAction::Cleanup(_) = unwind { + self.landing_pads += 1; + } + } + } + TerminatorKind::Call { unwind, .. } => { + self.calls += 1; + if let UnwindAction::Cleanup(_) = unwind { + self.landing_pads += 1; + } + } + TerminatorKind::Assert { unwind, .. } => { + self.calls += 1; + if let UnwindAction::Cleanup(_) = unwind { + self.landing_pads += 1; + } + } + TerminatorKind::UnwindResume => self.resumes += 1, + TerminatorKind::InlineAsm { unwind, .. } => { + self.statements += 1; + if let UnwindAction::Cleanup(_) = unwind { + self.landing_pads += 1; + } + } + TerminatorKind::Return => {} + _ => self.statements += 1, + } + } +} diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 7b14fef6153..85a0be8a44c 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -2,7 +2,6 @@ //! //! Currently, this pass only propagates scalar values. -use rustc_const_eval::const_eval::CheckAlignment; use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; @@ -17,7 +16,7 @@ use rustc_mir_dataflow::value_analysis::{ use rustc_mir_dataflow::{lattice::FlatSet, Analysis, Results, ResultsVisitor}; use rustc_span::def_id::DefId; use rustc_span::DUMMY_SP; -use rustc_target::abi::{Align, FieldIdx, VariantIdx}; +use rustc_target::abi::{FieldIdx, VariantIdx}; use crate::MirPass; @@ -709,23 +708,13 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm const PANIC_ON_ALLOC_FAIL: bool = true; #[inline(always)] - fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> CheckAlignment { - // We do not check for alignment to avoid having to carry an `Align` - // in `ConstValue::ByRef`. - CheckAlignment::No + fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + false // no reason to enforce alignment } fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool { unimplemented!() } - fn alignment_check_failed( - _ecx: &InterpCx<'mir, 'tcx, Self>, - _has: Align, - _required: Align, - _check: CheckAlignment, - ) -> interpret::InterpResult<'tcx, ()> { - unimplemented!() - } fn before_access_global( _tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index d9a132e5cf1..99b070c018e 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -244,7 +244,7 @@ impl<'tcx> MirPass<'tcx> for DestinationPropagation { if round_count != 0 { // Merging can introduce overlap between moved arguments and/or call destination in an // unreachable code, which validator considers to be ill-formed. - remove_dead_blocks(tcx, body); + remove_dead_blocks(body); } trace!(round_count); diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index 319fb4eaf3e..6eb6cb069fe 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -95,6 +95,7 @@ pub struct EarlyOtherwiseBranch; impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + // unsound: https://github.com/rust-lang/rust/issues/95162 sess.mir_opt_level() >= 3 && sess.opts.unstable_opts.unsound_mir_opts } diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index c16f07a453c..a6693519e54 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1088,7 +1088,7 @@ fn create_generator_drop_shim<'tcx>( // Make sure we remove dead blocks to remove // unrelated code from the resume part of the function - simplify::remove_dead_blocks(tcx, &mut body); + 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. @@ -1276,7 +1276,7 @@ fn create_generator_resume_function<'tcx>( // Make sure we remove dead blocks to remove // unrelated code from the drop part of the function - simplify::remove_dead_blocks(tcx, body); + simplify::remove_dead_blocks(body); pm::run_passes_no_validate(tcx, body, &[&abort_unwinding_calls::AbortUnwindingCalls], None); diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 56bdc5a171a..c710e460dcb 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -63,7 +63,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_target::abi::{VariantIdx, FIRST_VARIANT}; -use crate::ssa::SsaLocals; +use crate::ssa::{AssignedValue, SsaLocals}; use crate::MirPass; pub struct GVN; @@ -87,21 +87,28 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let dominators = body.basic_blocks.dominators().clone(); let mut state = VnState::new(tcx, param_env, &ssa, &dominators, &body.local_decls); - for arg in body.args_iter() { - if ssa.is_ssa(arg) { - let value = state.new_opaque().unwrap(); - state.assign(arg, value); - } - } - - ssa.for_each_assignment_mut(&mut body.basic_blocks, |local, rvalue, location| { - let value = state.simplify_rvalue(rvalue, location).or_else(|| state.new_opaque()).unwrap(); - // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark `local` as - // reusable if we have an exact type match. - if state.local_decls[local].ty == rvalue.ty(state.local_decls, tcx) { + ssa.for_each_assignment_mut( + body.basic_blocks.as_mut_preserves_cfg(), + |local, value, location| { + let value = match value { + // We do not know anything of this assigned value. + AssignedValue::Arg | AssignedValue::Terminator(_) => None, + // Try to get some insight. + AssignedValue::Rvalue(rvalue) => { + let value = state.simplify_rvalue(rvalue, location); + // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark `local` as + // reusable if we have an exact type match. + if state.local_decls[local].ty != rvalue.ty(state.local_decls, tcx) { + return; + } + value + } + }; + // `next_opaque` is `Some`, so `new_opaque` must return `Some`. + let value = value.or_else(|| state.new_opaque()).unwrap(); state.assign(local, value); - } - }); + }, + ); // Stop creating opaques during replacement as it is useless. state.next_opaque = None; @@ -312,7 +319,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } if let Some(local) = self.try_as_local(value, location) - && local != place.local // in case we had no projection to begin with. + && local != place.local + // in case we had no projection to begin with. { *place = local.into(); self.reused_locals.insert(local); diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 32dfb743905..8f578b69694 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -63,7 +63,7 @@ impl<'tcx> MirPass<'tcx> for Inline { if inline(tcx, body) { debug!("running simplify cfg on {:?}", body.source); CfgSimplifier::new(body).simplify(); - remove_dead_blocks(tcx, body); + remove_dead_blocks(body); deref_finder(tcx, body); } } @@ -169,8 +169,11 @@ impl<'tcx> Inliner<'tcx> { caller_body: &mut Body<'tcx>, callsite: &CallSite<'tcx>, ) -> Result<std::ops::Range<BasicBlock>, &'static str> { + self.check_mir_is_available(caller_body, &callsite.callee)?; + let callee_attrs = self.tcx.codegen_fn_attrs(callsite.callee.def_id()); - self.check_codegen_attributes(callsite, callee_attrs)?; + let cross_crate_inlinable = self.tcx.cross_crate_inlinable(callsite.callee.def_id()); + self.check_codegen_attributes(callsite, callee_attrs, cross_crate_inlinable)?; let terminator = caller_body[callsite.block].terminator.as_ref().unwrap(); let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() }; @@ -183,9 +186,8 @@ impl<'tcx> Inliner<'tcx> { } } - self.check_mir_is_available(caller_body, &callsite.callee)?; let callee_body = try_instance_mir(self.tcx, callsite.callee.def)?; - self.check_mir_body(callsite, callee_body, callee_attrs)?; + self.check_mir_body(callsite, callee_body, callee_attrs, cross_crate_inlinable)?; if !self.tcx.consider_optimizing(|| { format!("Inline {:?} into {:?}", callsite.callee, caller_body.source) @@ -401,6 +403,7 @@ impl<'tcx> Inliner<'tcx> { &self, callsite: &CallSite<'tcx>, callee_attrs: &CodegenFnAttrs, + cross_crate_inlinable: bool, ) -> Result<(), &'static str> { if let InlineAttr::Never = callee_attrs.inline { return Err("never inline hint"); @@ -414,7 +417,7 @@ impl<'tcx> Inliner<'tcx> { .non_erasable_generics(self.tcx, callsite.callee.def_id()) .next() .is_some(); - if !is_generic && !callee_attrs.requests_inline() { + if !is_generic && !cross_crate_inlinable { return Err("not exported"); } @@ -456,10 +459,11 @@ impl<'tcx> Inliner<'tcx> { callsite: &CallSite<'tcx>, callee_body: &Body<'tcx>, callee_attrs: &CodegenFnAttrs, + cross_crate_inlinable: bool, ) -> Result<(), &'static str> { let tcx = self.tcx; - let mut threshold = if callee_attrs.requests_inline() { + let mut threshold = if cross_crate_inlinable { self.tcx.sess.opts.unstable_opts.inline_mir_hint_threshold.unwrap_or(100) } else { self.tcx.sess.opts.unstable_opts.inline_mir_threshold.unwrap_or(50) @@ -503,7 +507,9 @@ impl<'tcx> Inliner<'tcx> { self.tcx, ty::EarlyBinder::bind(&place.ty(callee_body, tcx).ty), ); - if ty.needs_drop(tcx, self.param_env) && let UnwindAction::Cleanup(unwind) = unwind { + if ty.needs_drop(tcx, self.param_env) + && let UnwindAction::Cleanup(unwind) = unwind + { work_list.push(unwind); } } else if callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set @@ -842,7 +848,9 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => { let fn_ty = self.instance.instantiate_mir(tcx, ty::EarlyBinder::bind(&f.const_.ty())); - self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) { + self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() + && tcx.is_intrinsic(def_id) + { // Don't give intrinsics the extra penalty for calls INSTR_COST } else { diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index a6ef2e11aa8..fbcd6e75ad4 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -93,7 +93,9 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { _ => None, }; - if let Some(new) = new && self.should_simplify(source_info, rvalue) { + if let Some(new) = new + && self.should_simplify(source_info, rvalue) + { *rvalue = new; } } @@ -150,7 +152,8 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { *rvalue = Rvalue::Use(operand.clone()); } else if *kind == CastKind::Transmute { // Transmuting an integer to another integer is just a signedness cast - if let (ty::Int(int), ty::Uint(uint)) | (ty::Uint(uint), ty::Int(int)) = (operand_ty.kind(), cast_ty.kind()) + if let (ty::Int(int), ty::Uint(uint)) | (ty::Uint(uint), ty::Int(int)) = + (operand_ty.kind(), cast_ty.kind()) && int.bit_width() == uint.bit_width() { // The width check isn't strictly necessary, as different widths @@ -172,8 +175,15 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { for (i, field) in variant.fields.iter().enumerate() { let field_ty = field.ty(self.tcx, args); if field_ty == *cast_ty { - let place = place.project_deeper(&[ProjectionElem::Field(FieldIdx::from_usize(i), *cast_ty)], self.tcx); - let operand = if operand.is_move() { Operand::Move(place) } else { Operand::Copy(place) }; + let place = place.project_deeper( + &[ProjectionElem::Field(FieldIdx::from_usize(i), *cast_ty)], + self.tcx, + ); + let operand = if operand.is_move() { + Operand::Move(place) + } else { + Operand::Copy(place) + }; *rvalue = Rvalue::Use(operand); return; } diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs index 886ff760481..0a8b13d6677 100644 --- a/compiler/rustc_mir_transform/src/large_enums.rs +++ b/compiler/rustc_mir_transform/src/large_enums.rs @@ -30,6 +30,9 @@ pub struct EnumSizeOpt { impl<'tcx> MirPass<'tcx> for EnumSizeOpt { fn is_enabled(&self, sess: &Session) -> bool { + // There are some differences in behavior on wasm and ARM that are not properly + // understood, so we conservatively treat this optimization as unsound: + // https://github.com/rust-lang/rust/pull/85158#issuecomment-1101836457 sess.opts.unstable_opts.unsound_mir_opts || sess.mir_opt_level() >= 3 } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index c42888d8791..01136974730 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -62,6 +62,7 @@ mod const_prop; mod const_prop_lint; mod copy_prop; mod coverage; +mod cross_crate_inline; mod ctfe_limit; mod dataflow_const_prop; mod dead_store_elimination; @@ -123,6 +124,7 @@ pub fn provide(providers: &mut Providers) { coverage::query::provide(providers); ffi_unwind_calls::provide(providers); shim::provide(providers); + cross_crate_inline::provide(providers); *providers = Providers { mir_keys, mir_const, @@ -162,37 +164,50 @@ fn remap_mir_for_const_eval_select<'tcx>( && tcx.item_name(def_id) == sym::const_eval_select && tcx.is_intrinsic(def_id) => { - let [tupled_args, called_in_const, called_at_rt]: [_; 3] = std::mem::take(args).try_into().unwrap(); + let [tupled_args, called_in_const, called_at_rt]: [_; 3] = + std::mem::take(args).try_into().unwrap(); let ty = tupled_args.ty(&body.local_decls, tcx); let fields = ty.tuple_fields(); let num_args = fields.len(); - let func = if context == hir::Constness::Const { called_in_const } else { called_at_rt }; - let (method, place): (fn(Place<'tcx>) -> Operand<'tcx>, Place<'tcx>) = match tupled_args { - Operand::Constant(_) => { - // there is no good way of extracting a tuple arg from a constant (const generic stuff) - // so we just create a temporary and deconstruct that. - let local = body.local_decls.push(LocalDecl::new(ty, fn_span)); - bb.statements.push(Statement { - source_info: SourceInfo::outermost(fn_span), - kind: StatementKind::Assign(Box::new((local.into(), Rvalue::Use(tupled_args.clone())))), - }); - (Operand::Move, local.into()) - } - Operand::Move(place) => (Operand::Move, place), - Operand::Copy(place) => (Operand::Copy, place), - }; - let place_elems = place.projection; - let arguments = (0..num_args).map(|x| { - let mut place_elems = place_elems.to_vec(); - place_elems.push(ProjectionElem::Field(x.into(), fields[x])); - let projection = tcx.mk_place_elems(&place_elems); - let place = Place { - local: place.local, - projection, + let func = + if context == hir::Constness::Const { called_in_const } else { called_at_rt }; + let (method, place): (fn(Place<'tcx>) -> Operand<'tcx>, Place<'tcx>) = + match tupled_args { + Operand::Constant(_) => { + // there is no good way of extracting a tuple arg from a constant (const generic stuff) + // so we just create a temporary and deconstruct that. + let local = body.local_decls.push(LocalDecl::new(ty, fn_span)); + bb.statements.push(Statement { + source_info: SourceInfo::outermost(fn_span), + kind: StatementKind::Assign(Box::new(( + local.into(), + Rvalue::Use(tupled_args.clone()), + ))), + }); + (Operand::Move, local.into()) + } + Operand::Move(place) => (Operand::Move, place), + Operand::Copy(place) => (Operand::Copy, place), }; - method(place) - }).collect(); - terminator.kind = TerminatorKind::Call { func, args: arguments, destination, target, unwind, call_source: CallSource::Misc, fn_span }; + let place_elems = place.projection; + let arguments = (0..num_args) + .map(|x| { + let mut place_elems = place_elems.to_vec(); + place_elems.push(ProjectionElem::Field(x.into(), fields[x])); + let projection = tcx.mk_place_elems(&place_elems); + let place = Place { local: place.local, projection }; + method(place) + }) + .collect(); + terminator.kind = TerminatorKind::Call { + func, + args: arguments, + destination, + target, + unwind, + call_source: CallSource::Misc, + fn_span, + }; } _ => {} } @@ -496,7 +511,7 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &elaborate_box_derefs::ElaborateBoxDerefs, &generator::StateTransform, &add_retag::AddRetag, - &Lint(const_prop_lint::ConstProp), + &Lint(const_prop_lint::ConstPropLint), ]; pm::run_passes_no_validate(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::Initial))); } @@ -554,8 +569,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &const_prop::ConstProp, &gvn::GVN, &dataflow_const_prop::DataflowConstProp, - // - // Const-prop runs unconditionally, but doesn't mutate the MIR at mir-opt-level=0. &const_debuginfo::ConstDebugInfo, &o1(simplify_branches::SimplifyConstCondition::AfterConstProp), &early_otherwise_branch::EarlyOtherwiseBranch, diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 22f9c6f4f85..5f3d8dfc6c4 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -166,12 +166,16 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { let [arg] = args.as_slice() else { span_bug!(terminator.source_info.span, "Wrong number of arguments"); }; - let derefed_place = - if let Some(place) = arg.place() && let Some(local) = place.as_local() { - tcx.mk_place_deref(local.into()) - } else { - span_bug!(terminator.source_info.span, "Only passing a local is supported"); - }; + let derefed_place = if let Some(place) = arg.place() + && let Some(local) = place.as_local() + { + tcx.mk_place_deref(local.into()) + } else { + span_bug!( + terminator.source_info.span, + "Only passing a local is supported" + ); + }; // Add new statement at the end of the block that does the read, and patch // up the terminator. block.statements.push(Statement { @@ -198,12 +202,16 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { "Wrong number of arguments for write_via_move intrinsic", ); }; - let derefed_place = - if let Some(place) = ptr.place() && let Some(local) = place.as_local() { - tcx.mk_place_deref(local.into()) - } else { - span_bug!(terminator.source_info.span, "Only passing a local is supported"); - }; + let derefed_place = if let Some(place) = ptr.place() + && let Some(local) = place.as_local() + { + tcx.mk_place_deref(local.into()) + } else { + span_bug!( + terminator.source_info.span, + "Only passing a local is supported" + ); + }; block.statements.push(Statement { source_info: terminator.source_info, kind: StatementKind::Assign(Box::new(( diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs index ac52f0ae112..ae487841179 100644 --- a/compiler/rustc_mir_transform/src/lower_slice_len.rs +++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs @@ -64,8 +64,7 @@ fn lower_slice_len_call<'tcx>( // make new RValue for Len let deref_arg = tcx.mk_place_deref(arg); let r_value = Rvalue::Len(deref_arg); - let len_statement_kind = - StatementKind::Assign(Box::new((*destination, r_value))); + let len_statement_kind = StatementKind::Assign(Box::new((*destination, r_value))); let add_statement = Statement { kind: len_statement_kind, source_info: terminator.source_info }; diff --git a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs index c97d034544a..c9b42e75cb2 100644 --- a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs +++ b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs @@ -38,6 +38,6 @@ impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators { } } - simplify::remove_dead_blocks(tcx, body) + simplify::remove_dead_blocks(body) } } diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index d1a4b26a046..206cdf9fe28 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -57,7 +57,9 @@ fn compute_slice_length<'tcx>( } // The length information is stored in the fat pointer, so we treat `operand` as a value. Rvalue::Use(operand) => { - if let Some(rhs) = operand.place() && let Some(rhs) = rhs.as_local() { + if let Some(rhs) = operand.place() + && let Some(rhs) = rhs.as_local() + { slice_lengths[local] = slice_lengths[rhs]; } } diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs index e1298b0654f..ff309bd10ec 100644 --- a/compiler/rustc_mir_transform/src/nrvo.rs +++ b/compiler/rustc_mir_transform/src/nrvo.rs @@ -34,7 +34,7 @@ pub struct RenameReturnPlace; impl<'tcx> MirPass<'tcx> for RenameReturnPlace { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - // #111005 + // unsound: #111005 sess.mir_opt_level() > 0 && sess.opts.unstable_opts.unsound_mir_opts } diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index 67941cf4395..df39c819ba9 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -210,14 +210,17 @@ fn compute_replacement<'tcx>( // have been visited before. Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) | Rvalue::CopyForDeref(place) => { - if let Some(rhs) = place.as_local() && ssa.is_ssa(rhs) { + if let Some(rhs) = place.as_local() + && ssa.is_ssa(rhs) + { let target = targets[rhs]; // Only see through immutable reference and pointers, as we do not know yet if // mutable references are fully replaced. if !needs_unique && matches!(target, Value::Pointer(..)) { targets[local] = target; } else { - targets[local] = Value::Pointer(tcx.mk_place_deref(rhs.into()), needs_unique); + targets[local] = + Value::Pointer(tcx.mk_place_deref(rhs.into()), needs_unique); } } } @@ -365,7 +368,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { *place = Place::from(target.local).project_deeper(rest, self.tcx); self.any_replacement = true; } else { - break + break; } } diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs index a34d4b02764..b4784b69f7f 100644 --- a/compiler/rustc_mir_transform/src/remove_zsts.rs +++ b/compiler/rustc_mir_transform/src/remove_zsts.rs @@ -126,7 +126,10 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { && let ty = place_for_ty.ty(self.local_decls, self.tcx).ty && self.known_to_be_zst(ty) && self.tcx.consider_optimizing(|| { - format!("RemoveZsts - Place: {:?} SourceInfo: {:?}", place_for_ty, statement.source_info) + format!( + "RemoveZsts - Place: {:?} SourceInfo: {:?}", + place_for_ty, statement.source_info + ) }) { statement.make_nop(); diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 73dae044355..88c89e106fd 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -28,10 +28,8 @@ //! return. use crate::MirPass; -use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; -use rustc_index::bit_set::BitSet; +use rustc_data_structures::fx::FxIndexSet; use rustc_index::{Idx, IndexSlice, IndexVec}; -use rustc_middle::mir::coverage::*; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; @@ -68,7 +66,7 @@ impl SimplifyCfg { pub fn simplify_cfg<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { CfgSimplifier::new(body).simplify(); remove_duplicate_unreachable_blocks(tcx, body); - remove_dead_blocks(tcx, body); + remove_dead_blocks(body); // FIXME: Should probably be moved into some kind of pass manager body.basic_blocks_mut().raw.shrink_to_fit(); @@ -337,7 +335,7 @@ pub fn remove_duplicate_unreachable_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut B } } -pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { +pub fn remove_dead_blocks(body: &mut Body<'_>) { let reachable = traversal::reachable_as_bitset(body); let num_blocks = body.basic_blocks.len(); if num_blocks == reachable.count() { @@ -345,10 +343,6 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { } let basic_blocks = body.basic_blocks.as_mut(); - let source_scopes = &body.source_scopes; - if tcx.sess.instrument_coverage() { - save_unreachable_coverage(basic_blocks, source_scopes, &reachable); - } let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect(); let mut orig_index = 0; @@ -370,99 +364,6 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { } } -/// Some MIR transforms can determine at compile time that a sequences of -/// statements will never be executed, so they can be dropped from the MIR. -/// For example, an `if` or `else` block that is guaranteed to never be executed -/// because its condition can be evaluated at compile time, such as by const -/// evaluation: `if false { ... }`. -/// -/// Those statements are bypassed by redirecting paths in the CFG around the -/// `dead blocks`; but with `-C instrument-coverage`, the dead blocks usually -/// include `Coverage` statements representing the Rust source code regions to -/// be counted at runtime. Without these `Coverage` statements, the regions are -/// lost, and the Rust source code will show no coverage information. -/// -/// What we want to show in a coverage report is the dead code with coverage -/// counts of `0`. To do this, we need to save the code regions, by injecting -/// `Unreachable` coverage statements. These are non-executable statements whose -/// code regions are still recorded in the coverage map, representing regions -/// with `0` executions. -/// -/// If there are no live `Counter` `Coverage` statements remaining, we remove -/// `Coverage` statements along with the dead blocks. Since at least one -/// counter per function is required by LLVM (and necessary, to add the -/// `function_hash` to the counter's call to the LLVM intrinsic -/// `instrprof.increment()`). -/// -/// The `generator::StateTransform` MIR pass and MIR inlining can create -/// atypical conditions, where all live `Counter`s are dropped from the MIR. -/// -/// With MIR inlining we can have coverage counters belonging to different -/// instances in a single body, so the strategy described above is applied to -/// coverage counters from each instance individually. -fn save_unreachable_coverage( - basic_blocks: &mut IndexSlice<BasicBlock, BasicBlockData<'_>>, - source_scopes: &IndexSlice<SourceScope, SourceScopeData<'_>>, - reachable: &BitSet<BasicBlock>, -) { - // Identify instances that still have some live coverage counters left. - let mut live = FxHashSet::default(); - for bb in reachable.iter() { - let basic_block = &basic_blocks[bb]; - for statement in &basic_block.statements { - let StatementKind::Coverage(coverage) = &statement.kind else { continue }; - let CoverageKind::Counter { .. } = coverage.kind else { continue }; - let instance = statement.source_info.scope.inlined_instance(source_scopes); - live.insert(instance); - } - } - - for bb in reachable.iter() { - let block = &mut basic_blocks[bb]; - for statement in &mut block.statements { - let StatementKind::Coverage(_) = &statement.kind else { continue }; - let instance = statement.source_info.scope.inlined_instance(source_scopes); - if !live.contains(&instance) { - statement.make_nop(); - } - } - } - - if live.is_empty() { - return; - } - - // Retain coverage for instances that still have some live counters left. - let mut retained_coverage = Vec::new(); - for dead_block in basic_blocks.indices() { - if reachable.contains(dead_block) { - continue; - } - let dead_block = &basic_blocks[dead_block]; - for statement in &dead_block.statements { - let StatementKind::Coverage(coverage) = &statement.kind else { continue }; - if coverage.code_regions.is_empty() { - continue; - }; - let instance = statement.source_info.scope.inlined_instance(source_scopes); - if live.contains(&instance) { - retained_coverage.push((statement.source_info, coverage.code_regions.clone())); - } - } - } - - let start_block = &mut basic_blocks[START_BLOCK]; - start_block.statements.extend(retained_coverage.into_iter().map( - |(source_info, code_regions)| Statement { - source_info, - kind: StatementKind::Coverage(Box::new(Coverage { - kind: CoverageKind::Unreachable, - code_regions, - })), - }, - )); -} - pub enum SimplifyLocals { BeforeConstProp, Final, diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs index fad58930e3a..8dc7b60c4e5 100644 --- a/compiler/rustc_mir_transform/src/ssa.rs +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -5,7 +5,6 @@ //! As a consequence of rule 2, we consider that borrowed locals are not SSA, even if they are //! `Freeze`, as we do not track that the assignment dominates all uses of the borrow. -use either::Either; use rustc_data_structures::graph::dominators::Dominators; use rustc_index::bit_set::BitSet; use rustc_index::{IndexSlice, IndexVec}; @@ -27,6 +26,12 @@ pub struct SsaLocals { direct_uses: IndexVec<Local, u32>, } +pub enum AssignedValue<'a, 'tcx> { + Arg, + Rvalue(&'a mut Rvalue<'tcx>), + Terminator(&'a mut TerminatorKind<'tcx>), +} + impl SsaLocals { pub fn new<'tcx>(body: &Body<'tcx>) -> SsaLocals { let assignment_order = Vec::with_capacity(body.local_decls.len()); @@ -39,6 +44,7 @@ impl SsaLocals { for local in body.args_iter() { visitor.assignments[local] = Set1::One(DefLocation::Argument); + visitor.assignment_order.push(local); } // For SSA assignments, a RPO visit will see the assignment before it sees any use. @@ -105,8 +111,8 @@ impl SsaLocals { ) -> impl Iterator<Item = (Local, &'a Rvalue<'tcx>, Location)> + 'a { self.assignment_order.iter().filter_map(|&local| { if let Set1::One(DefLocation::Body(loc)) = self.assignments[local] { + let stmt = body.stmt_at(loc).left()?; // `loc` must point to a direct assignment to `local`. - let Either::Left(stmt) = body.stmt_at(loc) else { bug!() }; let Some((target, rvalue)) = stmt.kind.as_assign() else { bug!() }; assert_eq!(target.as_local(), Some(local)); Some((local, rvalue, loc)) @@ -118,18 +124,33 @@ impl SsaLocals { pub fn for_each_assignment_mut<'tcx>( &self, - basic_blocks: &mut BasicBlocks<'tcx>, - mut f: impl FnMut(Local, &mut Rvalue<'tcx>, Location), + basic_blocks: &mut IndexSlice<BasicBlock, BasicBlockData<'tcx>>, + mut f: impl FnMut(Local, AssignedValue<'_, 'tcx>, Location), ) { for &local in &self.assignment_order { - if let Set1::One(DefLocation::Body(loc)) = self.assignments[local] { - // `loc` must point to a direct assignment to `local`. - let bbs = basic_blocks.as_mut_preserves_cfg(); - let bb = &mut bbs[loc.block]; - let stmt = &mut bb.statements[loc.statement_index]; - let StatementKind::Assign(box (target, ref mut rvalue)) = stmt.kind else { bug!() }; - assert_eq!(target.as_local(), Some(local)); - f(local, rvalue, loc) + match self.assignments[local] { + Set1::One(DefLocation::Argument) => f( + local, + AssignedValue::Arg, + Location { block: START_BLOCK, statement_index: 0 }, + ), + Set1::One(DefLocation::Body(loc)) => { + let bb = &mut basic_blocks[loc.block]; + let value = if loc.statement_index < bb.statements.len() { + // `loc` must point to a direct assignment to `local`. + let stmt = &mut bb.statements[loc.statement_index]; + let StatementKind::Assign(box (target, ref mut rvalue)) = stmt.kind else { + bug!() + }; + assert_eq!(target.as_local(), Some(local)); + AssignedValue::Rvalue(rvalue) + } else { + let term = bb.terminator_mut(); + AssignedValue::Terminator(&mut term.kind) + }; + f(local, value, loc) + } + _ => {} } } } @@ -228,8 +249,22 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor<'_> { } fn visit_place(&mut self, place: &Place<'tcx>, ctxt: PlaceContext, loc: Location) { - if place.projection.first() == Some(&PlaceElem::Deref) { - // Do not do anything for storage statements and debuginfo. + let location = match ctxt { + PlaceContext::MutatingUse( + MutatingUseContext::Store | MutatingUseContext::Call | MutatingUseContext::Yield, + ) => Some(DefLocation::Body(loc)), + _ => None, + }; + if let Some(location) = location + && let Some(local) = place.as_local() + { + self.assignments[local].insert(location); + if let Set1::One(_) = self.assignments[local] { + // Only record if SSA-like, to avoid growing the vector needlessly. + self.assignment_order.push(local); + } + } else if place.projection.first() == Some(&PlaceElem::Deref) { + // Do not do anything for debuginfo. if ctxt.is_use() { // Only change the context if it is a real use, not a "use" in debuginfo. let new_ctxt = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy); @@ -237,25 +272,11 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor<'_> { self.visit_projection(place.as_ref(), new_ctxt, loc); self.check_dominates(place.local, loc); } - return; } else { self.visit_projection(place.as_ref(), ctxt, loc); self.visit_local(place.local, ctxt, loc); } } - - fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, loc: Location) { - if let Some(local) = place.as_local() { - self.assignments[local].insert(DefLocation::Body(loc)); - if let Set1::One(_) = self.assignments[local] { - // Only record if SSA-like, to avoid growing the vector needlessly. - self.assignment_order.push(local); - } - } else { - self.visit_place(place, PlaceContext::MutatingUse(MutatingUseContext::Store), loc); - } - self.visit_rvalue(rvalue, loc); - } } #[instrument(level = "trace", skip(ssa, body))] diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs index 0b9311a20ef..ea7aafd866b 100644 --- a/compiler/rustc_mir_transform/src/unreachable_prop.rs +++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs @@ -65,7 +65,7 @@ impl MirPass<'_> for UnreachablePropagation { } if replaced { - simplify::remove_dead_blocks(tcx, body); + simplify::remove_dead_blocks(body); } } } diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs index b50bb47f297..b1bd4ac75e5 100644 --- a/compiler/rustc_parse/src/lexer/diagnostics.rs +++ b/compiler/rustc_parse/src/lexer/diagnostics.rs @@ -111,9 +111,10 @@ pub fn report_suspicious_mismatch_block( // If there is no suspicious span, give the last properly closed block may help if let Some(parent) = diag_info.matching_block_spans.last() && diag_info.open_braces.last().is_none() - && diag_info.empty_block_spans.iter().all(|&sp| sp != parent.0.to(parent.1)) { - err.span_label(parent.0, "this opening brace..."); - err.span_label(parent.1, "...matches this closing brace"); + && diag_info.empty_block_spans.iter().all(|&sp| sp != parent.0.to(parent.1)) + { + err.span_label(parent.0, "this opening brace..."); + err.span_label(parent.1, "...matches this closing brace"); } } } diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index 07910113dee..1d9dbfe4b89 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -55,16 +55,14 @@ impl<'a> TokenTreesReader<'a> { let (this_spacing, next_tok) = loop { let (next_tok, is_next_tok_preceded_by_whitespace) = self.string_reader.next_token(); - if !is_next_tok_preceded_by_whitespace { - if let Some(glued) = self.token.glue(&next_tok) { - self.token = glued; - } else { - let this_spacing = - if next_tok.is_op() { Spacing::Joint } else { Spacing::Alone }; - break (this_spacing, next_tok); - } - } else { + if is_next_tok_preceded_by_whitespace { break (Spacing::Alone, next_tok); + } else if let Some(glued) = self.token.glue(&next_tok) { + self.token = glued; + } else { + let this_spacing = + if next_tok.is_punct() { Spacing::Joint } else { Spacing::Alone }; + break (this_spacing, next_tok); } }; let this_tok = std::mem::replace(&mut self.token, next_tok); diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 06b1b1523ed..75e3393aa96 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -314,11 +314,10 @@ impl<'a> Parser<'a> { // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#` let ident_name = ident.name.to_string(); - Some(SuggEscapeIdentifier { - span: ident.span.shrink_to_lo(), - ident_name - }) - } else { None }; + Some(SuggEscapeIdentifier { span: ident.span.shrink_to_lo(), ident_name }) + } else { + None + }; let suggest_remove_comma = if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) { @@ -375,9 +374,11 @@ impl<'a> Parser<'a> { // and current token should be Ident with the item name (i.e. the function name) // if there is a `<` after the fn name, then don't show a suggestion, show help - if !self.look_ahead(1, |t| *t == token::Lt) && - let Ok(snippet) = self.sess.source_map().span_to_snippet(generic.span) { - err.multipart_suggestion_verbose( + if !self.look_ahead(1, |t| *t == token::Lt) + && let Ok(snippet) = + self.sess.source_map().span_to_snippet(generic.span) + { + err.multipart_suggestion_verbose( format!("place the generic parameter name after the {ident_name} name"), vec![ (self.token.span.shrink_to_hi(), snippet), @@ -385,11 +386,11 @@ impl<'a> Parser<'a> { ], Applicability::MaybeIncorrect, ); - } else { - err.help(format!( - "place the generic parameter name after the {ident_name} name" - )); - } + } else { + err.help(format!( + "place the generic parameter name after the {ident_name} name" + )); + } } } Err(err) => { @@ -402,7 +403,9 @@ impl<'a> Parser<'a> { } } - if let Some(recovered_ident) = recovered_ident && recover { + if let Some(recovered_ident) = recovered_ident + && recover + { err.emit(); Ok(recovered_ident) } else { @@ -617,19 +620,19 @@ impl<'a> Parser<'a> { } if let TokenKind::Ident(prev, _) = &self.prev_token.kind - && let TokenKind::Ident(cur, _) = &self.token.kind + && let TokenKind::Ident(cur, _) = &self.token.kind { - let concat = Symbol::intern(&format!("{prev}{cur}")); - let ident = Ident::new(concat, DUMMY_SP); - if ident.is_used_keyword() || ident.is_reserved() || ident.is_raw_guess() { - let span = self.prev_token.span.to(self.token.span); - err.span_suggestion_verbose( - span, - format!("consider removing the space to spell keyword `{concat}`"), - concat, - Applicability::MachineApplicable, - ); - } + let concat = Symbol::intern(&format!("{prev}{cur}")); + let ident = Ident::new(concat, DUMMY_SP); + if ident.is_used_keyword() || ident.is_reserved() || ident.is_raw_guess() { + let span = self.prev_token.span.to(self.token.span); + err.span_suggestion_verbose( + span, + format!("consider removing the space to spell keyword `{concat}`"), + concat, + Applicability::MachineApplicable, + ); + } } // `pub` may be used for an item or `pub(crate)` @@ -827,6 +830,65 @@ impl<'a> Parser<'a> { None } + pub(super) fn recover_closure_body( + &mut self, + mut err: DiagnosticBuilder<'a, ErrorGuaranteed>, + before: token::Token, + prev: token::Token, + token: token::Token, + lo: Span, + decl_hi: Span, + ) -> PResult<'a, P<Expr>> { + err.span_label(lo.to(decl_hi), "while parsing the body of this closure"); + match before.kind { + token::OpenDelim(Delimiter::Brace) + if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) => + { + // `{ || () }` should have been `|| { () }` + err.multipart_suggestion( + "you might have meant to open the body of the closure, instead of enclosing \ + the closure in a block", + vec![ + (before.span, String::new()), + (prev.span.shrink_to_hi(), " {".to_string()), + ], + Applicability::MaybeIncorrect, + ); + err.emit(); + self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Brace)]); + } + token::OpenDelim(Delimiter::Parenthesis) + if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) => + { + // We are within a function call or tuple, we can emit the error + // and recover. + self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Parenthesis), &token::Comma]); + + err.multipart_suggestion_verbose( + "you might have meant to open the body of the closure", + vec![ + (prev.span.shrink_to_hi(), " {".to_string()), + (self.token.span.shrink_to_lo(), "}".to_string()), + ], + Applicability::MaybeIncorrect, + ); + err.emit(); + } + _ if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) => { + // We don't have a heuristic to correctly identify where the block + // should be closed. + err.multipart_suggestion_verbose( + "you might have meant to open the body of the closure", + vec![(prev.span.shrink_to_hi(), " {".to_string())], + Applicability::HasPlaceholders, + ); + return Err(err); + } + _ => return Err(err), + } + Ok(self.mk_expr_err(lo.to(self.token.span))) + } + /// Eats and discards tokens until one of `kets` is encountered. Respects token trees, /// passes through any errors encountered. Used for error recovery. pub(super) fn eat_to_tokens(&mut self, kets: &[&TokenKind]) { @@ -1025,8 +1087,7 @@ impl<'a> Parser<'a> { .emit(); match self.parse_expr() { Ok(_) => { - *expr = - self.mk_expr_err(expr.span.to(self.prev_token.span)); + *expr = self.mk_expr_err(expr.span.to(self.prev_token.span)); return Ok(()); } Err(err) => { @@ -1218,7 +1279,9 @@ impl<'a> Parser<'a> { return if token::ModSep == self.token.kind { // We have some certainty that this was a bad turbofish at this point. // `foo< bar >::` - if let ExprKind::Binary(o, ..) = inner_op.kind && o.node == BinOpKind::Lt { + if let ExprKind::Binary(o, ..) = inner_op.kind + && o.node == BinOpKind::Lt + { err.suggest_turbofish = Some(op.span.shrink_to_lo()); } else { err.help_turbofish = Some(()); @@ -1248,7 +1311,9 @@ impl<'a> Parser<'a> { } else if token::OpenDelim(Delimiter::Parenthesis) == self.token.kind { // We have high certainty that this was a bad turbofish at this point. // `foo< bar >(` - if let ExprKind::Binary(o, ..) = inner_op.kind && o.node == BinOpKind::Lt { + if let ExprKind::Binary(o, ..) = inner_op.kind + && o.node == BinOpKind::Lt + { err.suggest_turbofish = Some(op.span.shrink_to_lo()); } else { err.help_turbofish = Some(()); @@ -1826,19 +1891,21 @@ impl<'a> Parser<'a> { 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 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() - }; + 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], diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 91bb2d9eb66..44cb90227e7 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1007,8 +1007,9 @@ impl<'a> Parser<'a> { let span = self.token.span; let sm = self.sess.source_map(); let (span, actual) = match (&self.token.kind, self.subparser_name) { - (token::Eof, Some(_)) if let Ok(actual) = sm.span_to_snippet(sm.next_point(span)) => - (span.shrink_to_hi(), actual.into()), + (token::Eof, Some(_)) if let Ok(actual) = sm.span_to_snippet(sm.next_point(span)) => { + (span.shrink_to_hi(), actual.into()) + } _ => (span, actual), }; self.sess.emit_err(errors::UnexpectedTokenAfterDot { span, actual }); @@ -1550,10 +1551,7 @@ impl<'a> Parser<'a> { self.sess.emit_err(errors::MacroInvocationWithQualifiedPath(path.span)); } let lo = path.span; - let mac = P(MacCall { - path, - args: self.parse_delim_args()?, - }); + let mac = P(MacCall { path, args: self.parse_delim_args()? }); (lo.to(self.prev_token.span), ExprKind::MacCall(mac)) } else if self.check(&token::OpenDelim(Delimiter::Brace)) && let Some(expr) = self.maybe_parse_struct_expr(&qself, &path) @@ -1592,7 +1590,7 @@ impl<'a> Parser<'a> { } else if !ate_colon && self.may_recover() && (matches!(self.token.kind, token::CloseDelim(_) | token::Comma) - || self.token.is_op()) + || self.token.is_punct()) { let (lit, _) = self.recover_unclosed_char(label_.ident, Parser::mk_token_lit_char, |self_| { @@ -1771,7 +1769,9 @@ impl<'a> Parser<'a> { fn parse_expr_break(&mut self) -> PResult<'a, P<Expr>> { let lo = self.prev_token.span; let mut label = self.eat_label(); - let kind = if self.token == token::Colon && let Some(label) = label.take() { + let kind = if self.token == token::Colon + && let Some(label) = label.take() + { // The value expression can be a labeled loop, see issue #86948, e.g.: // `loop { break 'label: loop { break 'label 42; }; }` let lexpr = self.parse_expr_labeled(label, true)?; @@ -2209,6 +2209,7 @@ impl<'a> Parser<'a> { fn parse_expr_closure(&mut self) -> PResult<'a, P<Expr>> { let lo = self.token.span; + let before = self.prev_token.clone(); let binder = if self.check_keyword(kw::For) { let lo = self.token.span; let lifetime_defs = self.parse_late_bound_lifetime_defs()?; @@ -2239,7 +2240,12 @@ impl<'a> Parser<'a> { FnRetTy::Default(_) => { let restrictions = self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET; - self.parse_expr_res(restrictions, None)? + let prev = self.prev_token.clone(); + let token = self.token.clone(); + match self.parse_expr_res(restrictions, None) { + Ok(expr) => expr, + Err(err) => self.recover_closure_body(err, before, prev, token, lo, decl_hi)?, + } } _ => { // If an explicit return type is given, require a block to appear (RFC 968). @@ -2371,16 +2377,18 @@ impl<'a> Parser<'a> { let mut recover_block_from_condition = |this: &mut Self| { let block = match &mut cond.kind { ExprKind::Binary(Spanned { span: binop_span, .. }, _, right) - if let ExprKind::Block(_, None) = right.kind => { - self.sess.emit_err(errors::IfExpressionMissingThenBlock { - if_span: lo, - missing_then_block_sub: - errors::IfExpressionMissingThenBlockSub::UnfinishedCondition(cond_span.shrink_to_lo().to(*binop_span)), - let_else_sub: None, - - }); - std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi())) - }, + if let ExprKind::Block(_, None) = right.kind => + { + self.sess.emit_err(errors::IfExpressionMissingThenBlock { + if_span: lo, + missing_then_block_sub: + errors::IfExpressionMissingThenBlockSub::UnfinishedCondition( + cond_span.shrink_to_lo().to(*binop_span), + ), + let_else_sub: None, + }); + std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi())) + } ExprKind::Block(_, None) => { self.sess.emit_err(errors::IfExpressionMissingCondition { if_span: lo.shrink_to_hi(), @@ -2459,10 +2467,16 @@ impl<'a> Parser<'a> { /// Parses a `let $pat = $expr` pseudo-expression. fn parse_expr_let(&mut self, restrictions: Restrictions) -> PResult<'a, P<Expr>> { let is_recovered = if !restrictions.contains(Restrictions::ALLOW_LET) { - Some(self.sess.emit_err(errors::ExpectedExpressionFoundLet { + let err = errors::ExpectedExpressionFoundLet { span: self.token.span, reason: ForbiddenLetReason::OtherForbidden, - })) + }; + if self.prev_token.kind == token::BinOp(token::Or) { + // This was part of a closure, the that part of the parser recover. + return Err(err.into_diagnostic(&self.sess.span_diagnostic)); + } else { + Some(self.sess.emit_err(err)) + } } else { None }; @@ -2557,13 +2571,16 @@ impl<'a> Parser<'a> { } fn error_on_extra_if(&mut self, cond: &P<Expr>) -> PResult<'a, ()> { - if let ExprKind::Binary(Spanned { span: binop_span, node: binop}, _, right) = &cond.kind && - let BinOpKind::And = binop && - let ExprKind::If(cond, ..) = &right.kind { - Err(self.sess.create_err(errors::UnexpectedIfWithIf(binop_span.shrink_to_hi().to(cond.span.shrink_to_lo())))) - } else { - Ok(()) - } + if let ExprKind::Binary(Spanned { span: binop_span, node: binop }, _, right) = &cond.kind + && let BinOpKind::And = binop + && let ExprKind::If(cond, ..) = &right.kind + { + Err(self.sess.create_err(errors::UnexpectedIfWithIf( + binop_span.shrink_to_hi().to(cond.span.shrink_to_lo()), + ))) + } else { + Ok(()) + } } /// Parses `for <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten). @@ -2911,9 +2928,9 @@ impl<'a> Parser<'a> { .or_else(|mut err| { if this.token == token::FatArrow { if let Ok(expr_lines) = sm.span_to_lines(expr.span) - && let Ok(arm_start_lines) = sm.span_to_lines(arm_start_span) - && arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col - && expr_lines.lines.len() == 2 + && let Ok(arm_start_lines) = sm.span_to_lines(arm_start_span) + && arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col + && expr_lines.lines.len() == 2 { // We check whether there's any trailing code in the parse span, // if there isn't, we very likely have the following: @@ -3169,7 +3186,7 @@ impl<'a> Parser<'a> { e.span_suggestion_verbose( self.token.span.shrink_to_lo(), "try naming a field", - &format!("{ident}: ", ), + &format!("{ident}: ",), Applicability::MaybeIncorrect, ); } @@ -3562,8 +3579,7 @@ impl MutVisitor for CondChecker<'_> { noop_visit_expr(e, self); self.forbid_let_reason = forbid_let_reason; } - ExprKind::Cast(ref mut op, _) - | ExprKind::Type(ref mut op, _) => { + ExprKind::Cast(ref mut op, _) | ExprKind::Type(ref mut op, _) => { let forbid_let_reason = self.forbid_let_reason; self.forbid_let_reason = Some(OtherForbidden); self.visit_expr(op); diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index cc54cc5bebb..982f601c0d5 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -122,7 +122,9 @@ impl<'a> Parser<'a> { ) -> PResult<'a, Option<Item>> { // Don't use `maybe_whole` so that we have precise control // over when we bump the parser - if let token::Interpolated(nt) = &self.token.kind && let token::NtItem(item) = &**nt { + if let token::Interpolated(nt) = &self.token.kind + && let token::NtItem(item) = &**nt + { let mut item = item.clone(); self.bump(); @@ -623,11 +625,10 @@ impl<'a> Parser<'a> { // `impl<T: Default> impl Default for Wrapper<T>` // ^^^^^ let extra_impl_kw = ty_first.span.until(bound.span()); - self.sess - .emit_err(errors::ExtraImplKeywordInTraitImpl { - extra_impl_kw, - impl_trait_span: ty_first.span - }); + self.sess.emit_err(errors::ExtraImplKeywordInTraitImpl { + extra_impl_kw, + impl_trait_span: ty_first.span, + }); } else { self.sess.emit_err(errors::ExpectedTraitInTraitImplFoundType { span: ty_first.span, @@ -1306,7 +1307,9 @@ impl<'a> Parser<'a> { // Provide a nice error message if the user placed a where-clause before the item body. // Users may be tempted to write such code if they are still used to the deprecated // where-clause location on type aliases and associated types. See also #89122. - if before_where_clause.has_where_token && let Some(expr) = &expr { + if before_where_clause.has_where_token + && let Some(expr) = &expr + { self.sess.emit_err(errors::WhereClauseBeforeConstBody { span: before_where_clause.span, name: ident.span, @@ -1949,7 +1952,8 @@ impl<'a> Parser<'a> { let mut err = self.expected_ident_found_err(); if self.eat_keyword_noexpect(kw::Let) && let removal_span = self.prev_token.span.until(self.token.span) - && let Ok(ident) = self.parse_ident_common(false) + && let Ok(ident) = self + .parse_ident_common(false) // Cancel this error, we don't need it. .map_err(|err| err.cancel()) && self.token.kind == TokenKind::Colon diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 6c24646f39a..597303cae73 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -558,8 +558,9 @@ impl<'a> Parser<'a> { } if case == Case::Insensitive - && let Some((ident, /* is_raw */ false)) = self.token.ident() - && ident.as_str().to_lowercase() == kw.as_str().to_lowercase() { + && let Some((ident, /* is_raw */ false)) = self.token.ident() + && ident.as_str().to_lowercase() == kw.as_str().to_lowercase() + { true } else { false @@ -587,12 +588,10 @@ impl<'a> Parser<'a> { } if case == Case::Insensitive - && let Some((ident, /* is_raw */ false)) = self.token.ident() - && ident.as_str().to_lowercase() == kw.as_str().to_lowercase() { - self.sess.emit_err(errors::KwBadCase { - span: ident.span, - kw: kw.as_str() - }); + && let Some((ident, /* is_raw */ false)) = self.token.ident() + && ident.as_str().to_lowercase() == kw.as_str().to_lowercase() + { + self.sess.emit_err(errors::KwBadCase { span: ident.span, kw: kw.as_str() }); self.bump(); return true; } diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index ff059a7e865..025b0615a7e 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -115,7 +115,7 @@ impl<'a> Parser<'a> { Some(item) => NtItem(item), None => { return Err(UnexpectedNonterminal::Item(self.token.span) - .into_diagnostic(&self.sess.span_diagnostic)); + .into_diagnostic(&self.sess.span_diagnostic)); } }, NonterminalKind::Block => { @@ -127,7 +127,7 @@ impl<'a> Parser<'a> { Some(s) => NtStmt(P(s)), None => { return Err(UnexpectedNonterminal::Statement(self.token.span) - .into_diagnostic(&self.sess.span_diagnostic)); + .into_diagnostic(&self.sess.span_diagnostic)); } }, NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => { @@ -146,19 +146,15 @@ impl<'a> Parser<'a> { NonterminalKind::Expr => NtExpr(self.parse_expr_force_collect()?), NonterminalKind::Literal => { // The `:literal` matcher does not support attributes - NtLiteral( - self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?, - ) + NtLiteral(self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?) } - NonterminalKind::Ty => NtTy( - self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?, - ), + NonterminalKind::Ty => { + NtTy(self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?) + } // this could be handled like a token, since it is one - NonterminalKind::Ident - if let Some((ident, is_raw)) = get_macro_ident(&self.token) => - { + NonterminalKind::Ident if let Some((ident, is_raw)) = get_macro_ident(&self.token) => { self.bump(); NtIdent(ident, is_raw) } @@ -166,15 +162,17 @@ impl<'a> Parser<'a> { return Err(UnexpectedNonterminal::Ident { span: self.token.span, token: self.token.clone(), - }.into_diagnostic(&self.sess.span_diagnostic)); + } + .into_diagnostic(&self.sess.span_diagnostic)); + } + NonterminalKind::Path => { + NtPath(P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?)) } - NonterminalKind::Path => NtPath( - P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?), - ), NonterminalKind::Meta => NtMeta(P(self.parse_attr_item(true)?)), - NonterminalKind::Vis => NtVis( - P(self.collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?), - ), + NonterminalKind::Vis => { + NtVis(P(self + .collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?)) + } NonterminalKind::Lifetime => { if self.check_lifetime() { NtLifetime(self.expect_lifetime().ident) @@ -182,7 +180,8 @@ impl<'a> Parser<'a> { return Err(UnexpectedNonterminal::Lifetime { span: self.token.span, token: self.token.clone(), - }.into_diagnostic(&self.sess.span_diagnostic)); + } + .into_diagnostic(&self.sess.span_diagnostic)); } } }; diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 445516c03a1..2fcb9a78cfd 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -764,7 +764,8 @@ impl<'a> Parser<'a> { if let ast::TyKind::Slice(inner_ty) | ast::TyKind::Array(inner_ty, _) = &ty.kind && let ast::TyKind::Err = inner_ty.kind && let Some(snapshot) = snapshot - && let Some(expr) = self.recover_unbraced_const_arg_that_can_begin_ty(snapshot) + && let Some(expr) = + self.recover_unbraced_const_arg_that_can_begin_ty(snapshot) { return Ok(Some(self.dummy_const_arg_needs_braces( self.struct_span_err(expr.span, "invalid const generic expression"), @@ -776,12 +777,10 @@ impl<'a> Parser<'a> { } Err(err) => { if let Some(snapshot) = snapshot - && let Some(expr) = self.recover_unbraced_const_arg_that_can_begin_ty(snapshot) + && let Some(expr) = + self.recover_unbraced_const_arg_that_can_begin_ty(snapshot) { - return Ok(Some(self.dummy_const_arg_needs_braces( - err, - expr.span, - ))); + return Ok(Some(self.dummy_const_arg_needs_braces(err, expr.span))); } // Try to recover from possible `const` arg without braces. return self.recover_const_arg(start, err).map(Some); diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 12c267351b9..e2f59cb2071 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -52,7 +52,9 @@ impl<'a> Parser<'a> { // Don't use `maybe_whole` so that we have precise control // over when we bump the parser - if let token::Interpolated(nt) = &self.token.kind && let token::NtStmt(stmt) = &**nt { + if let token::Interpolated(nt) = &self.token.kind + && let token::NtStmt(stmt) = &**nt + { let mut stmt = stmt.clone(); self.bump(); stmt.visit_attrs(|stmt_attrs| { @@ -227,8 +229,9 @@ impl<'a> Parser<'a> { /// Also error if the previous token was a doc comment. fn error_outer_attrs(&self, attrs: AttrWrapper) { if !attrs.is_empty() - && let attrs = attrs.take_for_recovery(self.sess) - && let attrs @ [.., last] = &*attrs { + && let attrs = attrs.take_for_recovery(self.sess) + && let attrs @ [.., last] = &*attrs + { if last.is_doc_comment() { self.sess.emit_err(errors::DocCommentDoesNotDocumentAnything { span: last.span, @@ -616,15 +619,17 @@ impl<'a> Parser<'a> { match &mut stmt.kind { // Expression without semicolon. StmtKind::Expr(expr) - if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => { + if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => + { // Just check for errors and recover; do not eat semicolon yet. // `expect_one_of` returns PResult<'a, bool /* recovered */> - let expect_result = self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]); + let expect_result = + self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]); let replace_with_err = 'break_recover: { match expect_result { - // Recover from parser, skip type error to avoid extra errors. + // Recover from parser, skip type error to avoid extra errors. Ok(true) => true, Err(mut e) => { if let TokenKind::DocComment(..) = self.token.kind @@ -654,14 +659,19 @@ impl<'a> Parser<'a> { } match &expr.kind { - ExprKind::Path(None, ast::Path { segments, .. }) if segments.len() == 1 => { + ExprKind::Path(None, ast::Path { segments, .. }) + if segments.len() == 1 => + { if self.token == token::Colon && self.look_ahead(1, |token| { - token.is_whole_block() || matches!( - token.kind, - token::Ident(kw::For | kw::Loop | kw::While, false) - | token::OpenDelim(Delimiter::Brace) - ) + token.is_whole_block() + || matches!( + token.kind, + token::Ident( + kw::For | kw::Loop | kw::While, + false + ) | token::OpenDelim(Delimiter::Brace) + ) }) { let snapshot = self.create_snapshot_for_diagnostic(); @@ -702,9 +712,8 @@ impl<'a> Parser<'a> { } true - } - Ok(false) => false + Ok(false) => false, } }; @@ -727,7 +736,9 @@ impl<'a> Parser<'a> { } eat_semi = false; } - StmtKind::Empty | StmtKind::Item(_) | StmtKind::Local(_) | StmtKind::Semi(_) => eat_semi = false, + StmtKind::Empty | StmtKind::Item(_) | StmtKind::Local(_) | StmtKind::Semi(_) => { + eat_semi = false + } } if add_semi_to_stmt || (eat_semi && self.eat(&token::Semi)) { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 0a64b2f806a..badea5d6133 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -893,13 +893,15 @@ impl<'a> Parser<'a> { // to recover from errors, not make more). let path = if self.may_recover() { let (span, message, sugg, path, applicability) = match &ty.kind { - TyKind::Ptr(..) | TyKind::Ref(..) if let TyKind::Path(_, path) = &ty.peel_refs().kind => { + TyKind::Ptr(..) | TyKind::Ref(..) + if let TyKind::Path(_, path) = &ty.peel_refs().kind => + { ( ty.span.until(path.span), "consider removing the indirection", "", path, - Applicability::MaybeIncorrect + Applicability::MaybeIncorrect, ) } TyKind::ImplTrait(_, bounds) @@ -910,10 +912,10 @@ impl<'a> Parser<'a> { "use the trait bounds directly", "", &tr.trait_ref.path, - Applicability::MachineApplicable + Applicability::MachineApplicable, ) } - _ => return Err(err) + _ => return Err(err), }; err.span_suggestion_verbose(span, message, sugg, applicability); @@ -1027,7 +1029,8 @@ impl<'a> Parser<'a> { args.into_iter() .filter_map(|arg| { if let ast::AngleBracketedArg::Arg(generic_arg) = arg - && let ast::GenericArg::Lifetime(lifetime) = generic_arg { + && let ast::GenericArg::Lifetime(lifetime) = generic_arg + { Some(lifetime) } else { None diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 90ac436a91f..7b6153eea09 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -9,6 +9,9 @@ html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))) )] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), allow(internal_features))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] // We want to be able to build this crate with a stable compiler, so no diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 214c6d70960..25ef5245cf1 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -580,6 +580,8 @@ passes_outside_loop = *[false] {""} } +passes_outside_loop_suggestion = consider labeling this block to be able to break within it + passes_params_not_allowed = referencing function parameters is not allowed in naked functions .help = follow the calling convention in asm block to use parameters diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 52fb193f3da..8b408d8202e 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1076,7 +1076,9 @@ impl CheckAttrVisitor<'_> { ) -> bool { let mut is_valid = true; - if let Some(mi) = attr.meta() && let Some(list) = mi.meta_item_list() { + if let Some(mi) = attr.meta() + && let Some(list) = mi.meta_item_list() + { for meta in list { if let Some(i_meta) = meta.meta_item() { match i_meta.name_or_empty() { @@ -1108,6 +1110,7 @@ impl CheckAttrVisitor<'_> { | sym::html_root_url | sym::html_no_source | sym::test + | sym::rust_logo if !self.check_attr_crate_level(attr, meta, hir_id) => { is_valid = false; @@ -1132,14 +1135,7 @@ impl CheckAttrVisitor<'_> { is_valid = false; } - sym::masked - if !self.check_doc_masked( - attr, - meta, - hir_id, - target, - ) => - { + sym::masked if !self.check_doc_masked(attr, meta, hir_id, target) => { is_valid = false; } @@ -1166,6 +1162,18 @@ impl CheckAttrVisitor<'_> { | sym::plugins | sym::fake_variadic => {} + sym::rust_logo => { + if !self.tcx.features().rustdoc_internals { + feature_err( + &self.tcx.sess.parse_sess, + sym::rustdoc_internals, + meta.span(), + "the `#[doc(rust_logo)]` attribute is used for Rust branding", + ) + .emit(); + } + } + sym::test => { if !self.check_test_attr(meta, hir_id) { is_valid = false; @@ -1179,13 +1187,11 @@ impl CheckAttrVisitor<'_> { INVALID_DOC_ATTRIBUTES, hir_id, i_meta.span, - errors::DocTestUnknownSpotlight { - path, - span: i_meta.span - } + errors::DocTestUnknownSpotlight { path, span: i_meta.span }, ); - } else if i_meta.has_name(sym::include) && - let Some(value) = i_meta.value_str() { + } else if i_meta.has_name(sym::include) + && let Some(value) = i_meta.value_str() + { let applicability = if list.len() == 1 { Applicability::MachineApplicable } else { @@ -1200,16 +1206,19 @@ impl CheckAttrVisitor<'_> { errors::DocTestUnknownInclude { path, value: value.to_string(), - inner: match attr.style { AttrStyle::Inner=> "!" , AttrStyle::Outer => "" }, + inner: match attr.style { + AttrStyle::Inner => "!", + AttrStyle::Outer => "", + }, sugg: (attr.meta().unwrap().span, applicability), - } + }, ); } else { self.tcx.emit_spanned_lint( INVALID_DOC_ATTRIBUTES, hir_id, i_meta.span, - errors::DocTestUnknownAny { path } + errors::DocTestUnknownAny { path }, ); } is_valid = false; @@ -2182,8 +2191,9 @@ impl CheckAttrVisitor<'_> { attr.span, errors::MacroExport::Normal, ); - } else if let Some(meta_item_list) = attr.meta_item_list() && - !meta_item_list.is_empty() { + } else if let Some(meta_item_list) = attr.meta_item_list() + && !meta_item_list.is_empty() + { if meta_item_list.len() > 1 { self.tcx.emit_spanned_lint( INVALID_MACRO_EXPORT_ARGUMENTS, @@ -2248,9 +2258,9 @@ impl CheckAttrVisitor<'_> { { errors::UnusedNote::EmptyList { name: attr.name_or_empty() } } else if matches!( - attr.name_or_empty(), - sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect - ) && let Some(meta) = attr.meta_item_list() + attr.name_or_empty(), + sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect + ) && let Some(meta) = attr.meta_item_list() && meta.len() == 1 && let Some(item) = meta[0].meta_item() && let MetaItemKind::NameValue(_) = &item.kind diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 6d176af8098..7188c177feb 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -86,7 +86,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { let is_feature_allowed = |feature_gate| { // All features require that the corresponding gate be enabled, // even if the function has `#[rustc_allow_const_fn_unstable(the_gate)]`. - if !tcx.features().enabled(feature_gate) { + if !tcx.features().active(feature_gate) { return false; } @@ -134,7 +134,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { let required_gates = required_gates.unwrap_or(&[]); let missing_gates: Vec<_> = - required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect(); + required_gates.iter().copied().filter(|&g| !features.active(g)).collect(); match missing_gates.as_slice() { [] => { diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index f853039f72c..87d4850b475 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -193,15 +193,15 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { if let hir::ExprKind::Assign(lhs, rhs, _) = assign.kind && check_for_self_assign_helper(self.typeck_results(), lhs, rhs) - && !assign.span.from_expansion() + && !assign.span.from_expansion() { - let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..)); - self.tcx.emit_spanned_lint( - lint::builtin::DEAD_CODE, - assign.hir_id, - assign.span, - UselessAssignment { is_field_assign, ty: self.typeck_results().expr_ty(lhs) } - ) + let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..)); + self.tcx.emit_spanned_lint( + lint::builtin::DEAD_CODE, + assign.hir_id, + assign.span, + UselessAssignment { is_field_assign, ty: self.typeck_results().expr_ty(lhs) }, + ) } } @@ -671,7 +671,8 @@ fn check_trait_item( if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) { let trait_item = tcx.hir().trait_item(id); if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_))) - && let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id) + && let Some(comes_from_allow) = + has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id) { worklist.push((trait_item.owner_id.def_id, comes_from_allow)); } diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index c92d0b878ea..51a64b3855f 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -121,9 +121,13 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, let def_id = local_def_id.to_def_id(); Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx, def_id) })) } else { - if let Some(main_def) = tcx.resolutions(()).main_def && let Some(def_id) = main_def.opt_fn_def_id() { + if let Some(main_def) = tcx.resolutions(()).main_def + && let Some(def_id) = main_def.opt_fn_def_id() + { // non-local main imports are handled below - if let Some(def_id) = def_id.as_local() && matches!(tcx.hir().find_by_def_id(def_id), Some(Node::ForeignItem(_))) { + if let Some(def_id) = def_id.as_local() + && matches!(tcx.hir().find_by_def_id(def_id), Some(Node::ForeignItem(_))) + { tcx.sess.emit_err(ExternMain { span: tcx.def_span(def_id) }); return None; } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index bcf5abbfe7d..a4397ceeb8c 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1099,6 +1099,16 @@ pub struct OutsideLoop<'a> { pub span: Span, pub name: &'a str, pub is_break: bool, + #[subdiagnostic] + pub suggestion: Option<OutsideLoopSuggestion>, +} +#[derive(Subdiagnostic)] +#[multipart_suggestion(passes_outside_loop_suggestion, applicability = "maybe-incorrect")] +pub struct OutsideLoopSuggestion { + #[suggestion_part(code = "'block: ")] + pub block_span: Span, + #[suggestion_part(code = " 'block")] + pub break_span: Span, } #[derive(Diagnostic)] @@ -1301,7 +1311,9 @@ impl<'a> IntoDiagnostic<'a> for NoMainErr { diag.span_label(self.sp.shrink_to_hi(), note); } - if let Some(main_def) = self.main_def_opt && main_def.opt_fn_def_id().is_none(){ + if let Some(main_def) = self.main_def_opt + && main_def.opt_fn_def_id().is_none() + { // There is something at `crate::main`, but it is not a function definition. diag.span_label(main_def.span, fluent::passes_non_function_main); } diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 51f3c9ad76f..946a9e68da6 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -6,6 +6,9 @@ #![allow(rustc::potential_query_instability)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), allow(internal_features))] #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(map_try_insert)] diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index 44174b1b89d..ceb8f58cac0 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -56,7 +56,9 @@ impl<'tcx> LibFeatureCollector<'tcx> { } } - if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER { + if let Some(s) = since + && s.as_str() == VERSION_PLACEHOLDER + { since = Some(rust_version_symbol()); } diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 20e996eaec4..1fe44b2b877 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1512,13 +1512,15 @@ impl<'tcx> Liveness<'_, 'tcx> { Some(body), |spans, hir_id, ln, var| { if !self.live_on_entry(ln, var) - && let Some(name) = self.should_warn(var) { - self.ir.tcx.emit_spanned_lint( - lint::builtin::UNUSED_ASSIGNMENTS, - hir_id, - spans, - errors::UnusedAssignPassed { name }, - ); } + && let Some(name) = self.should_warn(var) + { + self.ir.tcx.emit_spanned_lint( + lint::builtin::UNUSED_ASSIGNMENTS, + hir_id, + spans, + errors::UnusedAssignPassed { name }, + ); + } }, ); } @@ -1707,13 +1709,14 @@ impl<'tcx> Liveness<'_, 'tcx> { fn warn_about_dead_assign(&self, spans: Vec<Span>, hir_id: HirId, ln: LiveNode, var: Variable) { if !self.live_on_exit(ln, var) - && let Some(name) = self.should_warn(var) { - self.ir.tcx.emit_spanned_lint( - lint::builtin::UNUSED_ASSIGNMENTS, - hir_id, - spans, - errors::UnusedAssign { name }, - ); - } + && let Some(name) = self.should_warn(var) + { + self.ir.tcx.emit_spanned_lint( + lint::builtin::UNUSED_ASSIGNMENTS, + hir_id, + spans, + errors::UnusedAssign { name }, + ); + } } } diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index 0aaf85086e4..25e131d7477 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -1,7 +1,7 @@ use Context::*; use rustc_hir as hir; -use rustc_hir::def_id::LocalModDefId; +use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Destination, Movability, Node}; use rustc_middle::hir::map::Map; @@ -10,19 +10,21 @@ use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::hygiene::DesugaringKind; -use rustc_span::Span; +use rustc_span::{BytePos, Span}; use crate::errors::{ BreakInsideAsyncBlock, BreakInsideClosure, BreakNonLoop, ContinueLabeledBlock, OutsideLoop, - UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock, + OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock, }; #[derive(Clone, Copy, Debug, PartialEq)] enum Context { Normal, + Fn, Loop(hir::LoopSource), Closure(Span), AsyncClosure(Span), + UnlabeledBlock(Span), LabeledBlock, Constant, } @@ -60,6 +62,25 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { self.with_context(Constant, |v| intravisit::walk_inline_const(v, c)); } + fn visit_fn( + &mut self, + fk: hir::intravisit::FnKind<'hir>, + fd: &'hir hir::FnDecl<'hir>, + b: hir::BodyId, + _: Span, + id: LocalDefId, + ) { + self.with_context(Fn, |v| intravisit::walk_fn(v, fk, fd, b, id)); + } + + fn visit_trait_item(&mut self, trait_item: &'hir hir::TraitItem<'hir>) { + self.with_context(Fn, |v| intravisit::walk_trait_item(v, trait_item)); + } + + fn visit_impl_item(&mut self, impl_item: &'hir hir::ImplItem<'hir>) { + self.with_context(Fn, |v| intravisit::walk_impl_item(v, impl_item)); + } + fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { match e.kind { hir::ExprKind::Loop(ref b, _, source, _) => { @@ -83,6 +104,14 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { hir::ExprKind::Block(ref b, Some(_label)) => { self.with_context(LabeledBlock, |v| v.visit_block(&b)); } + hir::ExprKind::Block(ref b, None) if matches!(self.cx, Fn) => { + self.with_context(Normal, |v| v.visit_block(&b)); + } + hir::ExprKind::Block(ref b, None) + if matches!(self.cx, Normal | Constant | UnlabeledBlock(_)) => + { + self.with_context(UnlabeledBlock(b.span.shrink_to_lo()), |v| v.visit_block(&b)); + } hir::ExprKind::Break(break_label, ref opt_expr) => { if let Some(e) = opt_expr { self.visit_expr(e); @@ -147,7 +176,12 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { } } - self.require_break_cx("break", e.span); + let sp_lo = e.span.with_lo(e.span.lo() + BytePos("break".len() as u32)); + let label_sp = match break_label.label { + Some(label) => sp_lo.with_hi(label.ident.span.hi()), + None => sp_lo.shrink_to_lo(), + }; + self.require_break_cx("break", e.span, label_sp); } hir::ExprKind::Continue(destination) => { self.require_label_in_labeled_block(e.span, &destination, "continue"); @@ -169,7 +203,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { } Err(_) => {} } - self.require_break_cx("continue", e.span) + self.require_break_cx("continue", e.span, e.span) } _ => intravisit::walk_expr(self, e), } @@ -187,7 +221,8 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { self.cx = old_cx; } - fn require_break_cx(&self, name: &str, span: Span) { + fn require_break_cx(&self, name: &str, span: Span, break_span: Span) { + let is_break = name == "break"; match self.cx { LabeledBlock | Loop(_) => {} Closure(closure_span) => { @@ -196,8 +231,12 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { AsyncClosure(closure_span) => { self.sess.emit_err(BreakInsideAsyncBlock { span, closure_span, name }); } - Normal | Constant => { - self.sess.emit_err(OutsideLoop { span, name, is_break: name == "break" }); + UnlabeledBlock(block_span) if is_break && block_span.eq_ctxt(break_span) => { + let suggestion = Some(OutsideLoopSuggestion { block_span, break_span }); + self.sess.emit_err(OutsideLoop { span, name, is_break, suggestion }); + } + Normal | Constant | Fn | UnlabeledBlock(_) => { + self.sess.emit_err(OutsideLoop { span, name, is_break, suggestion: None }); } } } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 1239d6d91ac..650bb97c4d1 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -18,43 +18,10 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::CrateType; use rustc_target::spec::abi::Abi; -// Returns true if the given item must be inlined because it may be -// monomorphized or it was marked with `#[inline]`. This will only return -// true for functions. -fn item_might_be_inlined(tcx: TyCtxt<'_>, item: &hir::Item<'_>, attrs: &CodegenFnAttrs) -> bool { - if attrs.requests_inline() { - return true; - } - - match item.kind { - hir::ItemKind::Fn(ref sig, ..) if sig.header.is_const() => true, - hir::ItemKind::Impl { .. } | hir::ItemKind::Fn(..) => { - let generics = tcx.generics_of(item.owner_id); - generics.requires_monomorphization(tcx) - } - _ => false, - } -} - -fn method_might_be_inlined( - tcx: TyCtxt<'_>, - impl_item: &hir::ImplItem<'_>, - impl_src: LocalDefId, -) -> bool { - let codegen_fn_attrs = tcx.codegen_fn_attrs(impl_item.hir_id().owner.to_def_id()); - let generics = tcx.generics_of(impl_item.owner_id); - if codegen_fn_attrs.requests_inline() || generics.requires_monomorphization(tcx) { - return true; - } - if let hir::ImplItemKind::Fn(method_sig, _) = &impl_item.kind { - if method_sig.header.is_const() { - return true; - } - } - match tcx.hir().find_by_def_id(impl_src) { - Some(Node::Item(item)) => item_might_be_inlined(tcx, &item, codegen_fn_attrs), - Some(..) | None => span_bug!(impl_item.span, "impl did is not an item"), - } +fn item_might_be_inlined(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + tcx.generics_of(def_id).requires_monomorphization(tcx) + || tcx.cross_crate_inlinable(def_id) + || tcx.is_const_fn(def_id) } // Information needed while computing reachability. @@ -97,7 +64,9 @@ impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> { _ => None, }; - if let Some(res) = res && let Some(def_id) = res.opt_def_id().and_then(|el| el.as_local()) { + if let Some(res) = res + && let Some(def_id) = res.opt_def_id().and_then(|el| el.as_local()) + { if self.def_id_represents_local_inlined_item(def_id.to_def_id()) { self.worklist.push(def_id); } else { @@ -148,9 +117,7 @@ impl<'tcx> ReachableContext<'tcx> { match self.tcx.hir().find_by_def_id(def_id) { Some(Node::Item(item)) => match item.kind { - hir::ItemKind::Fn(..) => { - item_might_be_inlined(self.tcx, &item, self.tcx.codegen_fn_attrs(def_id)) - } + hir::ItemKind::Fn(..) => item_might_be_inlined(self.tcx, def_id.into()), _ => false, }, Some(Node::TraitItem(trait_method)) => match trait_method.kind { @@ -162,9 +129,7 @@ impl<'tcx> ReachableContext<'tcx> { Some(Node::ImplItem(impl_item)) => match impl_item.kind { hir::ImplItemKind::Const(..) => true, hir::ImplItemKind::Fn(..) => { - let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); - let impl_did = self.tcx.hir().get_parent_item(hir_id); - method_might_be_inlined(self.tcx, impl_item, impl_did.def_id) + item_might_be_inlined(self.tcx, impl_item.hir_id().owner.to_def_id()) } hir::ImplItemKind::Type(_) => false, }, @@ -224,11 +189,7 @@ impl<'tcx> ReachableContext<'tcx> { Node::Item(item) => { match item.kind { hir::ItemKind::Fn(.., body) => { - if item_might_be_inlined( - self.tcx, - &item, - self.tcx.codegen_fn_attrs(item.owner_id), - ) { + if item_might_be_inlined(self.tcx, item.owner_id.into()) { self.visit_nested_body(body); } } @@ -277,8 +238,7 @@ impl<'tcx> ReachableContext<'tcx> { self.visit_nested_body(body); } hir::ImplItemKind::Fn(_, body) => { - let impl_def_id = self.tcx.local_parent(search_item); - if method_might_be_inlined(self.tcx, impl_item, impl_def_id) { + if item_might_be_inlined(self.tcx, impl_item.hir_id().owner.to_def_id()) { self.visit_nested_body(body) } } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 9c265e8ec11..bb23dc257d7 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -998,14 +998,17 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { all_implications: &FxHashMap<Symbol, Symbol>, ) { for (feature, since) in defined_features { - if let Some(since) = since && let Some(span) = remaining_lib_features.get(&feature) { + if let Some(since) = since + && let Some(span) = remaining_lib_features.get(&feature) + { // Warn if the user has enabled an already-stable lib feature. if let Some(implies) = all_implications.get(&feature) { - unnecessary_partially_stable_feature_lint(tcx, *span, *feature, *implies, *since); + unnecessary_partially_stable_feature_lint( + tcx, *span, *feature, *implies, *since, + ); } else { unnecessary_stable_feature_lint(tcx, *span, *feature, *since); } - } remaining_lib_features.remove(feature); diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 75e071f1fcf..9a6fb88c281 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -26,7 +26,9 @@ pub fn check_crate(tcx: TyCtxt<'_>, items: &mut lang_items::LanguageItems) { for id in crate_items.foreign_items() { let attrs = tcx.hir().attrs(id.hir_id()); if let Some((lang_item, _)) = lang_items::extract(attrs) { - if let Some(item) = LangItem::from_name(lang_item) && item.is_weak() { + if let Some(item) = LangItem::from_name(lang_item) + && item.is_weak() + { if items.get(item).is_none() { items.missing.push(item); } diff --git a/compiler/rustc_plugin_impl/src/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs index faa7495ef9f..0e1c80a1f64 100644 --- a/compiler/rustc_plugin_impl/src/lib.rs +++ b/compiler/rustc_plugin_impl/src/lib.rs @@ -7,6 +7,9 @@ //! of the Unstable Book for some examples. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), allow(internal_features))] #![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index ab85f680fcf..5599c6100a5 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,4 +1,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), allow(internal_features))] #![feature(associated_type_defaults)] #![feature(rustc_private)] #![feature(try_blocks)] @@ -570,7 +573,8 @@ impl<'tcx> EmbargoVisitor<'tcx> { if !child.reexport_chain.is_empty() && child.vis.is_accessible_from(defining_mod, self.tcx) && let Res::Def(def_kind, def_id) = child.res - && let Some(def_id) = def_id.as_local() { + && let Some(def_id) = def_id.as_local() + { let vis = self.tcx.local_visibility(def_id); self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod, macro_ev); } @@ -671,7 +675,8 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { if self.impl_trait_pass && let hir::ItemKind::OpaqueTy(ref opaque) = item.kind - && !opaque.in_trait { + && !opaque.in_trait + { // FIXME: This is some serious pessimization intended to workaround deficiencies // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time // reachable if they are returned via `impl Trait`, even from private functions. diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 30621a135eb..a1465dabed6 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -1,6 +1,8 @@ //! Support for serializing the dep-graph and reloading it. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] // this shouldn't be necessary, but the check for `&mut _` is too naive and denies returning a function pointer that takes a mut ref #![feature(const_mut_refs)] #![feature(const_refs_to_cell)] diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index ae8414ebba6..69a9c0eb95a 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -459,7 +459,9 @@ where // Similarly, fingerprint the result to assert that // it doesn't have anything not considered hashable. - if cfg!(debug_assertions) && let Some(hash_result) = query.hash_result() { + if cfg!(debug_assertions) + && let Some(hash_result) = query.hash_result() + { qcx.dep_context().with_stable_hashing_context(|mut hcx| { hash_result(&mut hcx, &result); }); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 110286255c5..925ee615b09 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -187,7 +187,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } else if let Some((span, msg, sugg, appl)) = suggestion { err.span_suggestion_verbose(span, msg, sugg, appl); err.emit(); - } else if let [segment] = path.as_slice() && is_call { + } else if let [segment] = path.as_slice() + && is_call + { err.stash(segment.ident.span, rustc_errors::StashKey::CallIntoMethod); } else { err.emit(); @@ -1690,7 +1692,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { non_exhaustive = Some(attr.span); } else if let Some(span) = ctor_fields_span { err.span_label(span, "a constructor is private if any of the fields is private"); - if let Res::Def(_, d) = res && let Some(fields) = self.field_visibility_spans.get(&d) { + if let Res::Def(_, d) = res + && let Some(fields) = self.field_visibility_spans.get(&d) + { err.multipart_suggestion_verbose( format!( "consider making the field{} publicly accessible", @@ -1739,7 +1743,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } // Final step in the import chain, point out if the ADT is `non_exhaustive` // which is probably why this privacy violation occurred. - if next_binding.is_none() && let Some(span) = non_exhaustive { + if next_binding.is_none() + && let Some(span) = non_exhaustive + { note_span.push_span_label( span, "cannot be constructed because it is `#[non_exhaustive]`", @@ -1846,7 +1852,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { parent_scope, None, ignore_binding, - ).ok() + ) + .ok() } else if let Some(ribs) = ribs && let Some(TypeNS | ValueNS) = opt_ns { @@ -1870,7 +1877,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None, false, ignore_binding, - ).ok() + ) + .ok() }; if let Some(binding) = binding { let mut found = |what| { @@ -2232,7 +2240,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Add the import to the start, with a `{` if required. let start_point = source_map.start_point(after_crate_name); - if is_definitely_crate && let Ok(start_snippet) = source_map.span_to_snippet(start_point) { + if is_definitely_crate + && let Ok(start_snippet) = source_map.span_to_snippet(start_point) + { corrections.push(( start_point, if has_nested { @@ -2247,7 +2257,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Add a `};` to the end if nested, matching the `{` added at the start. if !has_nested { - corrections.push((source_map.end_point(after_crate_name), "};".to_string())); + corrections + .push((source_map.end_point(after_crate_name), "};".to_string())); } } else { // If the root import is module-relative, add the import separately @@ -2586,7 +2597,13 @@ fn show_candidates( for candidate in &mut accessible_path_strings { // produce an additional newline to separate the new use statement // from the directly following item. - let additional_newline = if let FoundUse::No = found_use && let DiagnosticMode::Normal = mode { "\n" } else { "" }; + let additional_newline = if let FoundUse::No = found_use + && let DiagnosticMode::Normal = mode + { + "\n" + } else { + "" + }; candidate.0 = format!("{add_use}{}{append}{trailing}{additional_newline}", &candidate.0); } diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 46f5df5ca6f..4477b967283 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -147,7 +147,8 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { warn_ambiguity |= nested_binding.warn_ambiguity; } if !is_ambiguity(binding, warn_ambiguity) - && let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) { + && let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) + { self.update_def(def_id, binding.vis.expect_local(), parent_id); } } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 54388f80f15..f2fd4b0bf60 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -896,7 +896,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if !restricted_shadowing && binding.expansion != LocalExpnId::ROOT { if let NameBindingKind::Import { import, .. } = binding.kind - && matches!(import.kind, ImportKind::MacroExport) { + && matches!(import.kind, ImportKind::MacroExport) + { self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); } } @@ -928,9 +929,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if !self.is_accessible_from(import_vis, parent_scope.module) { continue; } - if let Some(ignored) = ignore_binding && - let NameBindingKind::Import { import, .. } = ignored.kind && - import == *single_import { + if let Some(ignored) = ignore_binding + && let NameBindingKind::Import { import, .. } = ignored.kind + && import == *single_import + { // Ignore not just the binding itself, but if it has a shadowed_glob, // ignore that, too, because this loop is supposed to only process // named imports. @@ -1440,7 +1442,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { finalize, ignore_binding, ) - } else if let Some(ribs) = ribs && let Some(TypeNS | ValueNS) = opt_ns { + } else if let Some(ribs) = ribs + && let Some(TypeNS | ValueNS) = opt_ns + { match self.resolve_ident_in_lexical_scope( ident, ns, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index d271519a8a3..b34790a925e 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -313,26 +313,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { (true, true) => { // FIXME: remove `!binding.is_ambiguity()` after delete the warning ambiguity. if !binding.is_ambiguity() - && let NameBindingKind::Import { import: old_import, .. } = old_binding.kind + && let NameBindingKind::Import { import: old_import, .. } = + old_binding.kind && let NameBindingKind::Import { import, .. } = binding.kind - && old_import == import { + && old_import == import + { // We should replace the `old_binding` with `binding` regardless // of whether they has same resolution or not when they are // imported from the same glob-import statement. resolution.binding = Some(binding); } else if res != old_binding.res() { let binding = if warn_ambiguity { - this.warn_ambiguity( - AmbiguityKind::GlobVsGlob, - old_binding, - binding, - ) + this.warn_ambiguity(AmbiguityKind::GlobVsGlob, old_binding, binding) } else { - this.ambiguity( - AmbiguityKind::GlobVsGlob, - old_binding, - binding, - ) + this.ambiguity(AmbiguityKind::GlobVsGlob, old_binding, binding) }; resolution.binding = Some(binding); } else if !old_binding.vis.is_at_least(binding.vis, this.tcx) { @@ -434,7 +428,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let t = f(self, resolution); - if let Some(binding) = resolution.binding() && old_binding != Some(binding) { + if let Some(binding) = resolution.binding() + && old_binding != Some(binding) + { (binding, t, warn_ambiguity || old_binding.is_some()) } else { return t; @@ -637,7 +633,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if binding.res() != Res::Err && glob_binding.res() != Res::Err - && let NameBindingKind::Import { import: glob_import, .. } = glob_binding.kind + && let NameBindingKind::Import { import: glob_import, .. } = + glob_binding.kind && let Some(binding_id) = binding_id && let Some(glob_import_id) = glob_import.id() && let glob_import_def_id = self.local_def_id(glob_import_id) @@ -738,11 +735,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match &import.kind { ImportKind::Single { source, .. } => { if let Some(ModuleOrUniformRoot::Module(module)) = import.imported_module.get() - && let Some(module) = module.opt_def_id() + && let Some(module) = module.opt_def_id() { self.find_cfg_stripped(&mut diag, &source.name, module) } - }, + } _ => {} } } @@ -989,10 +986,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } if !is_prelude - && let Some(max_vis) = max_vis.get() - && !max_vis.is_at_least(import.expect_vis(), self.tcx) + && let Some(max_vis) = max_vis.get() + && !max_vis.is_at_least(import.expect_vis(), self.tcx) { - self.lint_buffer.buffer_lint(UNUSED_IMPORTS, id, import.span, fluent::resolve_glob_import_doesnt_reexport); + self.lint_buffer.buffer_lint( + UNUSED_IMPORTS, + id, + import.span, + fluent::resolve_glob_import_doesnt_reexport, + ); } return None; } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index ece8b7f6ec9..42ca407cddf 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -736,7 +736,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, // Check whether we should interpret this as a bare trait object. if qself.is_none() && let Some(partial_res) = self.r.partial_res_map.get(&ty.id) - && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = partial_res.full_res() + && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) = + partial_res.full_res() { // This path is actually a bare trait object. In case of a bare `Fn`-trait // object with anonymous lifetimes, we need this rib to correctly place the @@ -2046,7 +2047,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { if lifetime_count != 0 { parameter_info.push(ElisionFnParameter { index, - ident: if let Some(pat) = pat && let PatKind::Ident(_, ident, _) = pat.kind { + ident: if let Some(pat) = pat + && let PatKind::Ident(_, ident, _) = pat.kind + { Some(ident) } else { None @@ -2140,7 +2143,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { impl<'a> Visitor<'a> for SelfVisitor<'_, '_, '_> { fn visit_ty(&mut self, ty: &'a Ty) { trace!("SelfVisitor considering ty={:?}", ty); - if let TyKind::Ref(lt, ref mt) = ty.kind && self.is_self_ty(&mt.ty) { + if let TyKind::Ref(lt, ref mt) = ty.kind + && self.is_self_ty(&mt.ty) + { let lt_id = if let Some(lt) = lt { lt.id } else { @@ -3602,7 +3607,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { sugg.to_string(), Applicability::MaybeIncorrect, )) - } else if res.is_none() && let PathSource::Type | PathSource::Expr(_) = source { + } else if res.is_none() + && let PathSource::Type | PathSource::Expr(_) = source + { this.suggest_adding_generic_parameter(path, source) } else { None @@ -4004,7 +4011,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { "unnecessary qualification", lint::BuiltinLintDiagnostics::UnusedQualifications { removal_span: finalize.path_span.until(last_segment.ident.span), - } + }, ) } } @@ -4057,13 +4064,13 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { (block.could_be_bare_literal, &block.stmts[..]) && let ExprKind::Type(..) = expr.kind { - self.diagnostic_metadata.current_block_could_be_bare_struct_literal = - Some(block.span); + self.diagnostic_metadata.current_block_could_be_bare_struct_literal = Some(block.span); } // Descend into the block. for stmt in &block.stmts { if let StmtKind::Item(ref item) = stmt.kind - && let ItemKind::MacroDef(..) = item.kind { + && let ItemKind::MacroDef(..) = item.kind + { num_macro_definition_ribs += 1; let res = self.r.local_def_id(item.id).to_def_id(); self.ribs[ValueNS].push(Rib::new(RibKind::MacroDefinition(res))); @@ -4419,7 +4426,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { && let Some(def_id) = res.opt_def_id() && !def_id.is_local() && self.r.tcx.crate_types().contains(&CrateType::ProcMacro) - && matches!(self.r.tcx.sess.opts.resolve_doc_links, ResolveDocLinks::ExportedMetadata) { + && matches!( + self.r.tcx.sess.opts.resolve_doc_links, + ResolveDocLinks::ExportedMetadata + ) + { // Encoding foreign def ids in proc macro crate metadata will ICE. return None; } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index bc5f8a37b0f..a5f8f61f3db 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -229,8 +229,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { i.ident.name == item_str.name // Don't suggest if the item is in Fn signature arguments (#112590). && !sig.span.contains(item_span) - }) - { + }) { let sp = item_span.shrink_to_lo(); // Account for `Foo { field }` when suggesting `self.field` so we result on @@ -241,7 +240,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } _ => None, }; - let pre = if let Some(field) = field && field.is_shorthand { + let pre = if let Some(field) = field + && field.is_shorthand + { format!("{item_ident}: ") } else { String::new() @@ -254,13 +255,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } _ => matches!( source, - PathSource::Expr(Some(Expr { kind: ExprKind::Call(..), ..})), + PathSource::Expr(Some(Expr { kind: ExprKind::Call(..), .. })), ), }; match &item.kind { AssocItemKind::Fn(fn_) - if (!sig.decl.has_self() || !is_call) && fn_.sig.decl.has_self() => { + if (!sig.decl.has_self() || !is_call) && fn_.sig.decl.has_self() => + { // Ensure that we only suggest `self.` if `self` is available, // you can't call `fn foo(&self)` from `fn bar()` (#115992). // We also want to mention that the method exists. @@ -270,19 +272,16 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { )); None } - AssocItemKind::Fn(fn_) - if !fn_.sig.decl.has_self() && !is_call => { + AssocItemKind::Fn(fn_) if !fn_.sig.decl.has_self() && !is_call => { span_label = Some(( item.ident.span, "an associated function by that name is available on `Self` here", )); None } - AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => Some(( - sp, - "consider using the method on `Self`", - format!("{pre}self."), - )), + AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => { + Some((sp, "consider using the method on `Self`", format!("{pre}self."))) + } AssocItemKind::Fn(_) => Some(( sp, "consider using the associated function on `Self`", @@ -293,7 +292,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { "consider using the associated constant on `Self`", format!("{pre}Self::"), )), - _ => None + _ => None, } } else { None @@ -379,8 +378,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { prefix_path: &[Segment], following_seg: Option<&Segment>, ) -> Vec<ImportSuggestion> { - if let Some(segment) = prefix_path.last() && - let Some(following_seg) = following_seg + if let Some(segment) = prefix_path.last() + && let Some(following_seg) = following_seg { let candidates = self.r.lookup_import_candidates( segment.ident, @@ -392,12 +391,16 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { candidates .into_iter() .filter(|candidate| { - if let Some(def_id) = candidate.did && - let Some(module) = self.r.get_module(def_id) { - Some(def_id) != self.parent_scope.module.opt_def_id() && - self.r.resolutions(module).borrow().iter().any(|(key, _r)| { - key.ident.name == following_seg.ident.name - }) + if let Some(def_id) = candidate.did + && let Some(module) = self.r.get_module(def_id) + { + Some(def_id) != self.parent_scope.module.opt_def_id() + && self + .r + .resolutions(module) + .borrow() + .iter() + .any(|(key, _r)| key.ident.name == following_seg.ident.name) } else { false } @@ -747,11 +750,15 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } // Try to find in last block rib - if let Some(rib) = &self.last_block_rib && let RibKind::Normal = rib.kind { + if let Some(rib) = &self.last_block_rib + && let RibKind::Normal = rib.kind + { for (ident, &res) in &rib.bindings { - if let Res::Local(_) = res && path.len() == 1 && - ident.span.eq_ctxt(path[0].ident.span) && - ident.name == path[0].ident.name { + if let Res::Local(_) = res + && path.len() == 1 + && ident.span.eq_ctxt(path[0].ident.span) + && ident.name == path[0].ident.name + { err.span_help( ident.span, format!("the binding `{path_str}` is available in a different scope in the same function"), @@ -867,9 +874,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { // (could be in a different file) or introduced in the same file as the typo // (could belong to a different crate) if let TypoCandidate::Shadowed(res, Some(sugg_span)) = typo_sugg - && res - .opt_def_id() - .is_some_and(|id| id.is_local() || is_in_same_file(span, sugg_span)) + && res.opt_def_id().is_some_and(|id| id.is_local() || is_in_same_file(span, sugg_span)) { err.span_label( sugg_span, @@ -1074,12 +1079,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { && trait_ref.path.span == span && let PathSource::Trait(_) = source && let Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)) = res - && let Ok(self_ty_str) = - self.r.tcx.sess.source_map().span_to_snippet(self_ty.span) + && let Ok(self_ty_str) = self.r.tcx.sess.source_map().span_to_snippet(self_ty.span) && let Ok(trait_ref_str) = self.r.tcx.sess.source_map().span_to_snippet(trait_ref.path.span) { - err.multipart_suggestion( + err.multipart_suggestion( "`impl` items mention the trait being implemented first and the type it is being implemented for second", vec![(trait_ref.path.span, self_ty_str), (self_ty.span, trait_ref_str)], Applicability::MaybeIncorrect, @@ -1106,12 +1110,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { source: PathSource<'_>, span: Span, ) -> bool { - if let PathSource::Expr(_) = source && - let Some(Expr { - span: expr_span, - kind: ExprKind::Assign(lhs, _, _), - .. - }) = self.diagnostic_metadata.in_if_condition { + if let PathSource::Expr(_) = source + && let Some(Expr { span: expr_span, kind: ExprKind::Assign(lhs, _, _), .. }) = + self.diagnostic_metadata.in_if_condition + { // Icky heuristic so we don't suggest: // `if (i + 2) = 2` => `if let (i + 2) = 2` (approximately pattern) // `if 2 = i` => `if let 2 = i` (lhs needs to contain error span) @@ -1240,31 +1242,32 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { let mut has_self_arg = None; if let PathSource::Expr(Some(parent)) = source && let ExprKind::Call(_, args) = &parent.kind - && !args.is_empty() { - let mut expr_kind = &args[0].kind; - loop { - match expr_kind { - ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => { - if arg_name.segments[0].ident.name == kw::SelfLower { - let call_span = parent.span; - let tail_args_span = if args.len() > 1 { - Some(Span::new( - args[1].span.lo(), - args.last().unwrap().span.hi(), - call_span.ctxt(), - None, - )) - } else { - None - }; - has_self_arg = Some((call_span, tail_args_span)); - } - break; + && !args.is_empty() + { + let mut expr_kind = &args[0].kind; + loop { + match expr_kind { + ExprKind::Path(_, arg_name) if arg_name.segments.len() == 1 => { + if arg_name.segments[0].ident.name == kw::SelfLower { + let call_span = parent.span; + let tail_args_span = if args.len() > 1 { + Some(Span::new( + args[1].span.lo(), + args.last().unwrap().span.hi(), + call_span.ctxt(), + None, + )) + } else { + None + }; + has_self_arg = Some((call_span, tail_args_span)); } - ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind, - _ => break, + break; } + ExprKind::AddrOf(_, _, expr) => expr_kind = &expr.kind, + _ => break, } + } } has_self_arg } @@ -1321,8 +1324,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { ); true } else if kind == DefKind::Struct - && let Some(lhs_source_span) = lhs_span.find_ancestor_inside(expr.span) - && let Ok(snippet) = self.r.tcx.sess.source_map().span_to_snippet(lhs_source_span) + && let Some(lhs_source_span) = lhs_span.find_ancestor_inside(expr.span) + && let Ok(snippet) = self.r.tcx.sess.source_map().span_to_snippet(lhs_source_span) { // The LHS is a type that originates from a macro call. // We have to add angle brackets around it. @@ -1427,7 +1430,13 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { .map(|(idx, new)| (new, old_fields.get(idx))) .map(|(new, old)| { let new = new.to_ident_string(); - if let Some(Some(old)) = old && new != *old { format!("{new}: {old}") } else { new } + if let Some(Some(old)) = old + && new != *old + { + format!("{new}: {old}") + } else { + new + } }) .collect::<Vec<String>>() } else { @@ -1813,7 +1822,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } } - if let RibKind::MacroDefinition(def) = rib.kind && def == self.r.macro_def(ctxt) { + if let RibKind::MacroDefinition(def) = rib.kind + && def == self.r.macro_def(ctxt) + { // If an invocation of this macro created `ident`, give up on `ident` // and switch to `ident`'s source from the macro definition. ctxt.remove_mark(); @@ -1934,18 +1945,20 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { // try to give a suggestion for this pattern: `name = blah`, which is common in other languages // suggest `let name = blah` to introduce a new binding fn let_binding_suggestion(&mut self, err: &mut Diagnostic, ident_span: Span) -> bool { - if let Some(Expr { kind: ExprKind::Assign(lhs, .. ), .. }) = self.diagnostic_metadata.in_assignment && - let ast::ExprKind::Path(None, _) = lhs.kind { - if !ident_span.from_expansion() { - err.span_suggestion_verbose( - ident_span.shrink_to_lo(), - "you might have meant to introduce a new binding", - "let ".to_string(), - Applicability::MaybeIncorrect, - ); - return true; - } + if let Some(Expr { kind: ExprKind::Assign(lhs, ..), .. }) = + self.diagnostic_metadata.in_assignment + && let ast::ExprKind::Path(None, _) = lhs.kind + { + if !ident_span.from_expansion() { + err.span_suggestion_verbose( + ident_span.shrink_to_lo(), + "you might have meant to introduce a new binding", + "let ".to_string(), + Applicability::MaybeIncorrect, + ); + return true; } + } false } @@ -2406,7 +2419,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { continue; } - if !span.can_be_used_for_suggestions() && suggest_note && let Some(name) = name { + if !span.can_be_used_for_suggestions() + && suggest_note + && let Some(name) = name + { suggest_note = false; // Avoid displaying the same help multiple times. err.span_label( span, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 5f012ec29fe..501747df5c9 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -7,6 +7,8 @@ //! Type-relative name resolution (methods, fields, associated items) happens in `rustc_hir_analysis`. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(extract_if)] @@ -824,8 +826,10 @@ impl<'a> NameBindingData<'a> { matches!(import.kind, ImportKind::ExternCrate { .. }) } NameBindingKind::Module(module) - if let ModuleKind::Def(DefKind::Mod, def_id, _) = module.kind - => def_id.is_crate_root(), + if let ModuleKind::Def(DefKind::Mod, def_id, _) = module.kind => + { + def_id.is_crate_root() + } _ => false, } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index f0a1a4ff931..2ff6fb424e6 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -748,33 +748,45 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } path_res @ (PathResult::NonModule(..) | PathResult::Failed { .. }) => { let mut suggestion = None; - let (span, label, module) = if let PathResult::Failed { span, label, module, .. } = path_res { - // try to suggest if it's not a macro, maybe a function - if let PathResult::NonModule(partial_res) = self.maybe_resolve_path(&path, Some(ValueNS), &parent_scope) - && partial_res.unresolved_segments() == 0 { - let sm = self.tcx.sess.source_map(); - let exclamation_span = sm.next_point(span); - suggestion = Some(( - vec![(exclamation_span, "".to_string())], - format!("{} is not a macro, but a {}, try to remove `!`", Segment::names_to_string(&path), partial_res.base_res().descr()), - Applicability::MaybeIncorrect + let (span, label, module) = + if let PathResult::Failed { span, label, module, .. } = path_res { + // try to suggest if it's not a macro, maybe a function + if let PathResult::NonModule(partial_res) = + self.maybe_resolve_path(&path, Some(ValueNS), &parent_scope) + && partial_res.unresolved_segments() == 0 + { + let sm = self.tcx.sess.source_map(); + let exclamation_span = sm.next_point(span); + suggestion = Some(( + vec![(exclamation_span, "".to_string())], + format!( + "{} is not a macro, but a {}, try to remove `!`", + Segment::names_to_string(&path), + partial_res.base_res().descr() + ), + Applicability::MaybeIncorrect, )); - } - (span, label, module) - } else { - ( - path_span, - format!( - "partially resolved path in {} {}", - kind.article(), - kind.descr() - ), - None, - ) - }; + } + (span, label, module) + } else { + ( + path_span, + format!( + "partially resolved path in {} {}", + kind.article(), + kind.descr() + ), + None, + ) + }; self.report_error( span, - ResolutionError::FailedToResolve { last_segment: path.last().map(|segment| segment.ident.name), label, suggestion, module }, + ResolutionError::FailedToResolve { + last_segment: path.last().map(|segment| segment.ident.name), + label, + suggestion, + module, + }, ); } PathResult::Module(..) | PathResult::Indeterminate => unreachable!(), diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 7c41c32d022..fe4b8c7f69c 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -346,7 +346,9 @@ pub fn has_primitive_or_keyword_docs(attrs: &[ast::Attribute]) -> bool { for attr in attrs { if attr.has_name(sym::rustc_doc_primitive) { return true; - } else if attr.has_name(sym::doc) && let Some(items) = attr.meta_item_list() { + } else if attr.has_name(sym::doc) + && let Some(items) = attr.meta_item_list() + { for item in items { if item.has_name(sym::keyword) { return true; diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index 5360aa9ea6a..cfa54072eb9 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -5,6 +5,9 @@ html_playground_url = "https://play.rust-lang.org/", test(attr(allow(unused_variables), deny(warnings))) )] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), allow(internal_features))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![feature(allocator_api)] #![feature(associated_type_bounds)] #![feature(const_option)] diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index e26d25d9a41..3af83aaaaa8 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -4,7 +4,6 @@ version = "0.0.0" edition = "2021" [dependencies] -bitflags = "1.2.1" getopts = "0.2" rustc_macros = { path = "../rustc_macros" } tracing = "0.1" diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index b356b503aa5..fa1b6f9f13d 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -5,9 +5,6 @@ session_cannot_enable_crt_static_linux = sanitizer is incompatible with statical session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible with `-Zsanitizer={$second}` -session_cgu_not_recorded = - CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded - session_cli_feature_diagnostic_help = add `-Zcrate-attr="feature({$feature})"` to the command-line options to enable @@ -34,12 +31,6 @@ session_hexadecimal_float_literal_not_supported = hexadecimal float literal is n session_incompatible_linker_flavor = linker flavor `{$flavor}` is incompatible with the current target .note = compatible flavors are: {$compatible_list} -session_incorrect_cgu_reuse_type = - CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least -> - [one] {"at least "} - *[other] {""} - }`{$expected_reuse}` - session_instrumentation_not_supported = {$us} instrumentation is not supported for this target session_int_literal_too_large = integer literal is too large diff --git a/compiler/rustc_session/src/cgu_reuse_tracker.rs b/compiler/rustc_session/src/cgu_reuse_tracker.rs deleted file mode 100644 index 8703e575465..00000000000 --- a/compiler/rustc_session/src/cgu_reuse_tracker.rs +++ /dev/null @@ -1,136 +0,0 @@ -//! Some facilities for tracking how codegen-units are reused during incremental -//! compilation. This is used for incremental compilation tests and debug -//! output. - -use crate::errors::{CguNotRecorded, IncorrectCguReuseType}; -use crate::Session; -use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; -use rustc_span::{Span, Symbol}; -use std::borrow::Cow; -use std::fmt::{self}; -use std::sync::{Arc, Mutex}; - -#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] -pub enum CguReuse { - No, - PreLto, - PostLto, -} - -impl fmt::Display for CguReuse { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - CguReuse::No => write!(f, "No"), - CguReuse::PreLto => write!(f, "PreLto "), - CguReuse::PostLto => write!(f, "PostLto "), - } - } -} - -impl IntoDiagnosticArg for CguReuse { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(self.to_string())) - } -} - -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum ComparisonKind { - Exact, - AtLeast, -} - -struct TrackerData { - actual_reuse: FxHashMap<String, CguReuse>, - expected_reuse: FxHashMap<String, (String, SendSpan, CguReuse, ComparisonKind)>, -} - -// Span does not implement `Send`, so we can't just store it in the shared -// `TrackerData` object. Instead of splitting up `TrackerData` into shared and -// non-shared parts (which would be complicated), we just mark the `Span` here -// explicitly as `Send`. That's safe because the span data here is only ever -// accessed from the main thread. -struct SendSpan(Span); -unsafe impl Send for SendSpan {} - -#[derive(Clone)] -pub struct CguReuseTracker { - data: Option<Arc<Mutex<TrackerData>>>, -} - -impl CguReuseTracker { - pub fn new() -> CguReuseTracker { - let data = - TrackerData { actual_reuse: Default::default(), expected_reuse: Default::default() }; - - CguReuseTracker { data: Some(Arc::new(Mutex::new(data))) } - } - - pub fn new_disabled() -> CguReuseTracker { - CguReuseTracker { data: None } - } - - pub fn set_actual_reuse(&self, cgu_name: &str, kind: CguReuse) { - if let Some(ref data) = self.data { - debug!("set_actual_reuse({cgu_name:?}, {kind:?})"); - - let prev_reuse = data.lock().unwrap().actual_reuse.insert(cgu_name.to_string(), kind); - - if let Some(prev_reuse) = prev_reuse { - // The only time it is legal to overwrite reuse state is when - // we discover during ThinLTO that we can actually reuse the - // post-LTO version of a CGU. - assert_eq!(prev_reuse, CguReuse::PreLto); - } - } - } - - pub fn set_expectation( - &self, - cgu_name: Symbol, - cgu_user_name: &str, - error_span: Span, - expected_reuse: CguReuse, - comparison_kind: ComparisonKind, - ) { - if let Some(ref data) = self.data { - debug!("set_expectation({cgu_name:?}, {expected_reuse:?}, {comparison_kind:?})"); - let mut data = data.lock().unwrap(); - - data.expected_reuse.insert( - cgu_name.to_string(), - (cgu_user_name.to_string(), SendSpan(error_span), expected_reuse, comparison_kind), - ); - } - } - - pub fn check_expected_reuse(&self, sess: &Session) { - if let Some(ref data) = self.data { - let data = data.lock().unwrap(); - - for (cgu_name, &(ref cgu_user_name, ref error_span, expected_reuse, comparison_kind)) in - &data.expected_reuse - { - if let Some(&actual_reuse) = data.actual_reuse.get(cgu_name) { - let (error, at_least) = match comparison_kind { - ComparisonKind::Exact => (expected_reuse != actual_reuse, false), - ComparisonKind::AtLeast => (actual_reuse < expected_reuse, true), - }; - - if error { - let at_least = if at_least { 1 } else { 0 }; - IncorrectCguReuseType { - span: error_span.0, - cgu_user_name, - actual_reuse, - expected_reuse, - at_least, - }; - } - } else { - sess.emit_fatal(CguNotRecorded { cgu_user_name, cgu_name }); - } - } - } - } -} diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 3970b751af7..bbba800e840 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -12,6 +12,7 @@ use crate::{EarlyErrorHandler, Session}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey}; use rustc_target::abi::Align; +use rustc_target::spec::LinkSelfContainedComponents; use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, SplitDebuginfo}; use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS}; @@ -232,63 +233,35 @@ pub struct LinkSelfContained { /// Used for compatibility with the existing opt-in and target inference. pub explicitly_set: Option<bool>, - /// The components that are enabled. - components: LinkSelfContainedComponents, -} - -bitflags::bitflags! { - #[derive(Default)] - /// The `-C link-self-contained` components that can individually be enabled or disabled. - pub struct LinkSelfContainedComponents: u8 { - /// CRT objects (e.g. on `windows-gnu`, `musl`, `wasi` targets) - const CRT_OBJECTS = 1 << 0; - /// libc static library (e.g. on `musl`, `wasi` targets) - const LIBC = 1 << 1; - /// libgcc/libunwind (e.g. on `windows-gnu`, `fuchsia`, `fortanix`, `gnullvm` targets) - const UNWIND = 1 << 2; - /// Linker, dlltool, and their necessary libraries (e.g. on `windows-gnu` and for `rust-lld`) - const LINKER = 1 << 3; - /// Sanitizer runtime libraries - const SANITIZERS = 1 << 4; - /// Other MinGW libs and Windows import libs - const MINGW = 1 << 5; - } -} - -impl FromStr for LinkSelfContainedComponents { - type Err = (); + /// The components that are enabled on the CLI, using the `+component` syntax or one of the + /// `true` shorcuts. + enabled_components: LinkSelfContainedComponents, - fn from_str(s: &str) -> Result<Self, Self::Err> { - Ok(match s { - "crto" => LinkSelfContainedComponents::CRT_OBJECTS, - "libc" => LinkSelfContainedComponents::LIBC, - "unwind" => LinkSelfContainedComponents::UNWIND, - "linker" => LinkSelfContainedComponents::LINKER, - "sanitizers" => LinkSelfContainedComponents::SANITIZERS, - "mingw" => LinkSelfContainedComponents::MINGW, - _ => return Err(()), - }) - } + /// The components that are disabled on the CLI, using the `-component` syntax or one of the + /// `false` shortcuts. + disabled_components: LinkSelfContainedComponents, } impl LinkSelfContained { /// Incorporates an enabled or disabled component as specified on the CLI, if possible. /// For example: `+linker`, and `-crto`. - pub(crate) fn handle_cli_component(&mut self, component: &str) -> Result<(), ()> { + pub(crate) fn handle_cli_component(&mut self, component: &str) -> Option<()> { // Note that for example `-Cself-contained=y -Cself-contained=-linker` is not an explicit // set of all values like `y` or `n` used to be. Therefore, if this flag had previously been // set in bulk with its historical values, then manually setting a component clears that // `explicitly_set` state. if let Some(component_to_enable) = component.strip_prefix('+') { self.explicitly_set = None; - self.components.insert(component_to_enable.parse()?); - Ok(()) + self.enabled_components + .insert(LinkSelfContainedComponents::from_str(component_to_enable)?); + Some(()) } else if let Some(component_to_disable) = component.strip_prefix('-') { self.explicitly_set = None; - self.components.remove(component_to_disable.parse()?); - Ok(()) + self.disabled_components + .insert(LinkSelfContainedComponents::from_str(component_to_disable)?); + Some(()) } else { - Err(()) + None } } @@ -296,11 +269,14 @@ impl LinkSelfContained { /// purposes. pub(crate) fn set_all_explicitly(&mut self, enabled: bool) { self.explicitly_set = Some(enabled); - self.components = if enabled { - LinkSelfContainedComponents::all() + + if enabled { + self.enabled_components = LinkSelfContainedComponents::all(); + self.disabled_components = LinkSelfContainedComponents::empty(); } else { - LinkSelfContainedComponents::empty() - }; + self.enabled_components = LinkSelfContainedComponents::empty(); + self.disabled_components = LinkSelfContainedComponents::all(); + } } /// Helper creating a fully enabled `LinkSelfContained` instance. Used in tests. @@ -314,13 +290,32 @@ impl LinkSelfContained { /// components was set individually. This would also require the `-Zunstable-options` flag, to /// be allowed. fn are_unstable_variants_set(&self) -> bool { - let any_component_set = !self.components.is_empty(); + let any_component_set = + !self.enabled_components.is_empty() || !self.disabled_components.is_empty(); self.explicitly_set.is_none() && any_component_set } - /// Returns whether the self-contained linker component is enabled. - pub fn linker(&self) -> bool { - self.components.contains(LinkSelfContainedComponents::LINKER) + /// Returns whether the self-contained linker component was enabled on the CLI, using the + /// `-C link-self-contained=+linker` syntax, or one of the `true` shorcuts. + pub fn is_linker_enabled(&self) -> bool { + self.enabled_components.contains(LinkSelfContainedComponents::LINKER) + } + + /// Returns whether the self-contained linker component was disabled on the CLI, using the + /// `-C link-self-contained=-linker` syntax, or one of the `false` shorcuts. + pub fn is_linker_disabled(&self) -> bool { + self.disabled_components.contains(LinkSelfContainedComponents::LINKER) + } + + /// Returns CLI inconsistencies to emit errors: individual components were both enabled and + /// disabled. + fn check_consistency(&self) -> Option<LinkSelfContainedComponents> { + if self.explicitly_set.is_some() { + None + } else { + let common = self.enabled_components.intersection(self.disabled_components); + if common.is_empty() { None } else { Some(common) } + } } } @@ -1052,6 +1047,7 @@ impl Default for Options { target_triple: TargetTriple::from_triple(host_triple()), test: false, incremental: None, + untracked_state_hash: Default::default(), unstable_opts: Default::default(), prints: Vec::new(), cg: Default::default(), @@ -2758,9 +2754,8 @@ pub fn build_session_options( } // For testing purposes, until we have more feedback about these options: ensure `-Z - // unstable-options` is required when using the unstable `-C link-self-contained` options, like - // `-C link-self-contained=+linker`, and when using the unstable `-C linker-flavor` options, like - // `-C linker-flavor=gnu-lld-cc`. + // unstable-options` is required when using the unstable `-C link-self-contained` and `-C + // linker-flavor` options. if !nightly_options::is_unstable_enabled(matches) { let uses_unstable_self_contained_option = cg.link_self_contained.are_unstable_variants_set(); @@ -2782,6 +2777,19 @@ pub fn build_session_options( } } + // Check `-C link-self-contained` for consistency: individual components cannot be both enabled + // and disabled at the same time. + if let Some(erroneous_components) = cg.link_self_contained.check_consistency() { + let names: String = erroneous_components + .into_iter() + .map(|c| c.as_str().unwrap()) + .intersperse(", ") + .collect(); + handler.early_error(format!( + "some `-C link-self-contained` components were both enabled and disabled: {names}" + )); + } + let prints = collect_print_requests(handler, &mut cg, &mut unstable_opts, matches); let cg = cg; @@ -2882,6 +2890,7 @@ pub fn build_session_options( target_triple, test, incremental, + untracked_state_hash: Default::default(), unstable_opts, prints, cg, @@ -2918,8 +2927,8 @@ fn parse_pretty(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions) -> "expanded" => Source(PpSourceMode::Expanded), "expanded,identified" => Source(PpSourceMode::ExpandedIdentified), "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene), - "ast-tree" => AstTree(PpAstTreeMode::Normal), - "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded), + "ast-tree" => AstTree, + "ast-tree,expanded" => AstTreeExpanded, "hir" => Hir(PpHirMode::Normal), "hir,identified" => Hir(PpHirMode::Identified), "hir,typed" => Hir(PpHirMode::Typed), @@ -3077,14 +3086,6 @@ pub enum PpSourceMode { } #[derive(Copy, Clone, PartialEq, Debug)] -pub enum PpAstTreeMode { - /// `-Zunpretty=ast` - Normal, - /// `-Zunpretty=ast,expanded` - Expanded, -} - -#[derive(Copy, Clone, PartialEq, Debug)] pub enum PpHirMode { /// `-Zunpretty=hir` Normal, @@ -3099,7 +3100,10 @@ pub enum PpMode { /// Options that print the source code, i.e. /// `-Zunpretty=normal` and `-Zunpretty=expanded` Source(PpSourceMode), - AstTree(PpAstTreeMode), + /// `-Zunpretty=ast-tree` + AstTree, + /// `-Zunpretty=ast-tree,expanded` + AstTreeExpanded, /// Options that print the HIR, i.e. `-Zunpretty=hir` Hir(PpHirMode), /// `-Zunpretty=hir-tree` @@ -3119,10 +3123,10 @@ impl PpMode { use PpMode::*; use PpSourceMode::*; match *self { - Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false, + Source(Normal | Identified) | AstTree => false, Source(Expanded | ExpandedIdentified | ExpandedHygiene) - | AstTree(PpAstTreeMode::Expanded) + | AstTreeExpanded | Hir(_) | HirTree | ThirTree @@ -3134,7 +3138,7 @@ impl PpMode { pub fn needs_hir(&self) -> bool { use PpMode::*; match *self { - Source(_) | AstTree(_) => false, + Source(_) | AstTree | AstTreeExpanded => false, Hir(_) | HirTree | ThirTree | ThirFlat | Mir | MirCFG => true, } @@ -3142,7 +3146,7 @@ impl PpMode { pub fn needs_analysis(&self) -> bool { use PpMode::*; - matches!(*self, Mir | MirCFG | ThirTree | ThirFlat) + matches!(*self, Hir(PpHirMode::Typed) | Mir | MirCFG | ThirTree | ThirFlat) } } @@ -3168,13 +3172,14 @@ pub(crate) mod dep_tracking { use super::{ BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail, - LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Passes, + LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Polonius, ResolveDocLinks, SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, TraitSolver, TrimmedDefPaths, }; use crate::lint; use crate::options::WasiExecModel; - use crate::utils::{NativeLib, NativeLibKind}; + use crate::utils::NativeLib; + use rustc_data_structures::stable_hasher::Hash64; use rustc_errors::LanguageIdentifier; use rustc_feature::UnstableFeatures; use rustc_span::edition::Edition; @@ -3230,6 +3235,7 @@ pub(crate) mod dep_tracking { usize, NonZeroUsize, u64, + Hash64, String, PathBuf, lint::Level, @@ -3244,14 +3250,12 @@ pub(crate) mod dep_tracking { MergeFunctions, PanicStrategy, RelroLevel, - Passes, OptLevel, LtoCli, DebugInfo, DebugInfoCompression, UnstableFeatures, NativeLib, - NativeLibKind, SanitizerSet, CFGuard, CFProtection, @@ -3274,6 +3278,7 @@ pub(crate) mod dep_tracking { OomStrategy, LanguageIdentifier, TraitSolver, + Polonius, ); impl<T1, T2> DepTrackingHash for (T1, T2) @@ -3412,3 +3417,35 @@ impl DumpMonoStatsFormat { } } } + +/// `-Zpolonius` values, enabling the borrow checker polonius analysis, and which version: legacy, +/// or future prototype. +#[derive(Clone, Copy, PartialEq, Hash, Debug)] +pub enum Polonius { + /// The default value: disabled. + Off, + + /// Legacy version, using datalog and the `polonius-engine` crate. Historical value for `-Zpolonius`. + Legacy, + + /// In-tree prototype, extending the NLL infrastructure. + Next, +} + +impl Default for Polonius { + fn default() -> Self { + Polonius::Off + } +} + +impl Polonius { + /// Returns whether the legacy version of polonius is enabled + pub fn is_legacy_enabled(&self) -> bool { + matches!(self, Polonius::Legacy) + } + + /// Returns whether the "next" version of polonius is enabled + pub fn is_next_enabled(&self) -> bool { + matches!(self, Polonius::Next) + } +} diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 5f8bbfca890..31094e0d266 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -1,6 +1,5 @@ use std::num::NonZeroU32; -use crate::cgu_reuse_tracker::CguReuse; use crate::parse::ParseSess; use rustc_ast::token; use rustc_ast::util::literal::LitError; @@ -9,24 +8,6 @@ use rustc_macros::Diagnostic; use rustc_span::{BytePos, Span, Symbol}; use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple}; -#[derive(Diagnostic)] -#[diag(session_incorrect_cgu_reuse_type)] -pub struct IncorrectCguReuseType<'a> { - #[primary_span] - pub span: Span, - pub cgu_user_name: &'a str, - pub actual_reuse: CguReuse, - pub expected_reuse: CguReuse, - pub at_least: u8, -} - -#[derive(Diagnostic)] -#[diag(session_cgu_not_recorded)] -pub struct CguNotRecorded<'a> { - pub cgu_user_name: &'a str, - pub cgu_name: &'a str, -} - pub struct FeatureGateError { pub span: MultiSpan, pub explain: DiagnosticMessage, diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index d6c746a7bd8..7da0bcf01bf 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -6,6 +6,7 @@ #![feature(option_get_or_insert_default)] #![feature(rustc_attrs)] #![feature(map_many_mut)] +#![feature(iter_intersperse)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] @@ -22,7 +23,6 @@ extern crate tracing; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; -pub mod cgu_reuse_tracker; pub mod utils; pub use lint::{declare_lint, declare_lint_pass, declare_tool_lint, impl_lint_pass}; pub use rustc_lint_defs as lint; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index f7c000c8bd6..11fbd9f8f86 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -4,6 +4,7 @@ use crate::search_paths::SearchPath; use crate::utils::NativeLib; use crate::{lint, EarlyErrorHandler}; use rustc_data_structures::profiling::TimePassesFormat; +use rustc_data_structures::stable_hasher::Hash64; use rustc_errors::ColorConfig; use rustc_errors::{LanguageIdentifier, TerminalUrl}; use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet}; @@ -158,6 +159,10 @@ top_level_options!( /// directory to store intermediate results. incremental: Option<PathBuf> [UNTRACKED], assert_incr_state: Option<IncrementalStateAssertion> [UNTRACKED], + /// Set by the `Config::hash_untracked_state` callback for custom + /// drivers to invalidate the incremental cache + #[rustc_lint_opt_deny_field_access("should only be used via `Config::hash_untracked_state`")] + untracked_state_hash: Hash64 [TRACKED_NO_CRATE_HASH], unstable_opts: UnstableOptions [SUBSTRUCT], prints: Vec<PrintRequest> [UNTRACKED], @@ -414,6 +419,7 @@ mod desc { "one of supported split dwarf modes (`split` or `single`)"; pub const parse_link_self_contained: &str = "one of: `y`, `yes`, `on`, `n`, `no`, `off`, or a list of enabled (`+` prefix) and disabled (`-` prefix) \ components: `crto`, `libc`, `unwind`, `linker`, `sanitizers`, `mingw`"; + pub const parse_polonius: &str = "either no value or `legacy` (the default), or `next`"; pub const parse_stack_protector: &str = "one of (`none` (default), `basic`, `strong`, or `all`)"; pub const parse_branch_protection: &str = @@ -471,6 +477,21 @@ mod parse { } } + /// Parses whether polonius is enabled, and if so, which version. + pub(crate) fn parse_polonius(slot: &mut Polonius, v: Option<&str>) -> bool { + match v { + Some("legacy") | None => { + *slot = Polonius::Legacy; + true + } + Some("next") => { + *slot = Polonius::Next; + true + } + _ => false, + } + } + /// Use this for any string option that has a static default. pub(crate) fn parse_string(slot: &mut String, v: Option<&str>) -> bool { match v { @@ -1165,7 +1186,7 @@ mod parse { // 2. Parse a list of enabled and disabled components. for comp in s.split(',') { - if slot.handle_cli_component(comp).is_err() { + if slot.handle_cli_component(comp).is_none() { return false; } } @@ -1431,6 +1452,8 @@ options! { "combine CGUs into a single one"), crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED], "inject the given attribute in the crate"), + cross_crate_inline_threshold: Option<usize> = (None, parse_opt_number, [TRACKED], + "threshold to allow cross crate inlining of functions"), debug_info_for_profiling: bool = (false, parse_bool, [TRACKED], "emit discriminators and other data necessary for AutoFDO"), debug_macros: bool = (false, parse_bool, [TRACKED], @@ -1599,9 +1622,10 @@ options! { "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \ (default: no)"), mir_enable_passes: Vec<(String, bool)> = (Vec::new(), parse_list_with_polarity, [TRACKED], - "use like `-Zmir-enable-passes=+DestinationPropagation,-InstSimplify`. Forces the specified passes to be \ - enabled, overriding all other checks. Passes that are not specified are enabled or \ - disabled by other flags as usual."), + "use like `-Zmir-enable-passes=+DestinationPropagation,-InstSimplify`. Forces the \ + specified passes to be enabled, overriding all other checks. In particular, this will \ + enable unsound (known-buggy and hence usually disabled) passes without further warning! \ + Passes that are not specified are enabled or disabled by other flags as usual."), mir_include_spans: bool = (false, parse_bool, [UNTRACKED], "use line numbers relative to the function in mir pretty printing"), mir_keep_place_mention: bool = (false, parse_bool, [TRACKED], @@ -1658,7 +1682,7 @@ options! { "whether to use the PLT when calling into shared libraries; only has effect for PIC code on systems with ELF binaries (default: PLT is disabled if full relro is enabled on x86_64)"), - polonius: bool = (false, parse_bool, [TRACKED], + polonius: Polonius = (Polonius::default(), parse_polonius, [TRACKED], "enable polonius-based borrow-checker (default: no)"), polymorphize: bool = (false, parse_bool, [TRACKED], "perform polymorphization analysis"), diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index 7a57b0621cd..9cd96895a61 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -186,10 +186,14 @@ pub fn invalid_output_for_target(sess: &Session, crate_type: CrateType) -> bool return true; } } - if let CrateType::ProcMacro | CrateType::Dylib = crate_type && sess.target.only_cdylib { + if let CrateType::ProcMacro | CrateType::Dylib = crate_type + && sess.target.only_cdylib + { return true; } - if let CrateType::Executable = crate_type && !sess.target.executables { + if let CrateType::Executable = crate_type + && !sess.target.executables + { return true; } diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 671204c0d8e..abb0ab5630c 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -39,7 +39,7 @@ pub struct GatedSpans { impl GatedSpans { /// Feature gate the given `span` under the given `feature` - /// which is same `Symbol` used in `active.rs`. + /// which is same `Symbol` used in `unstable.rs`. pub fn gate(&self, feature: Symbol, span: Span) { self.spans.borrow_mut().entry(feature).or_default().push(span); } @@ -78,7 +78,7 @@ impl SymbolGallery { } /// Construct a diagnostic for a language feature error due to the given `span`. -/// The `feature`'s `Symbol` is the one you used in `active.rs` and `rustc_span::symbols`. +/// The `feature`'s `Symbol` is the one you used in `unstable.rs` and `rustc_span::symbols`. #[track_caller] pub fn feature_err( sess: &ParseSess, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index b484978eed2..5cac11cc8f7 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1,4 +1,3 @@ -use crate::cgu_reuse_tracker::CguReuseTracker; use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo}; use crate::config::{ @@ -153,9 +152,6 @@ pub struct Session { pub io: CompilerIO, incr_comp_session: OneThread<RefCell<IncrCompSession>>, - /// Used for incremental compilation tests. Will only be populated if - /// `-Zquery-dep-graph` is specified. - pub cgu_reuse_tracker: CguReuseTracker, /// Used by `-Z self-profile`. pub prof: SelfProfilerRef, @@ -1431,12 +1427,6 @@ pub fn build_session( }); let print_fuel = AtomicU64::new(0); - let cgu_reuse_tracker = if sopts.unstable_opts.query_dep_graph { - CguReuseTracker::new() - } else { - CguReuseTracker::new_disabled() - }; - let prof = SelfProfilerRef::new( self_profiler, sopts.unstable_opts.time_passes.then(|| sopts.unstable_opts.time_passes_format), @@ -1461,7 +1451,6 @@ pub fn build_session( sysroot, io, incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)), - cgu_reuse_tracker, prof, perf_stats: PerfStats { symbol_hash_time: Lock::new(Duration::from_secs(0)), diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index aea7c6c2842..3ed044ad769 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -161,7 +161,9 @@ pub fn extra_compiler_flags() -> Option<(Vec<String>, bool)> { pub(crate) fn is_ascii_ident(string: &str) -> bool { let mut chars = string.chars(); - if let Some(start) = chars.next() && (start.is_ascii_alphabetic() || start == '_') { + if let Some(start) = chars.next() + && (start.is_ascii_alphabetic() || start == '_') + { chars.all(|char| char.is_ascii_alphanumeric() || char == '_') } else { false diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml index 3e0d6baab6a..2b77044d6bf 100644 --- a/compiler/rustc_smir/Cargo.toml +++ b/compiler/rustc_smir/Cargo.toml @@ -4,6 +4,7 @@ version = "0.0.0" edition = "2021" [dependencies] +rustc_data_structures = { path = "../rustc_data_structures" } rustc_driver = { path = "../rustc_driver" } rustc_hir = { path = "../rustc_hir" } rustc_interface = { path = "../rustc_interface" } diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs index d10f46fad9e..c24b9efe865 100644 --- a/compiler/rustc_smir/src/lib.rs +++ b/compiler/rustc_smir/src/lib.rs @@ -10,6 +10,9 @@ html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(allow(unused_variables), deny(warnings))) )] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), allow(internal_features))] pub mod rustc_internal; diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 36eb2247253..5ea805e5739 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -3,24 +3,29 @@ //! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs //! until stable MIR is complete. -use std::ops::{ControlFlow, Index}; - use crate::rustc_internal; use crate::rustc_smir::Tables; +use rustc_data_structures::fx; +use rustc_data_structures::fx::FxIndexMap; use rustc_driver::{Callbacks, Compilation, RunCompiler}; use rustc_interface::{interface, Queries}; use rustc_middle::mir::interpret::AllocId; +use rustc_middle::ty; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::Span; +use stable_mir::ty::IndexedVal; use stable_mir::CompilerError; +use std::fmt::Debug; +use std::hash::Hash; +use std::ops::{ControlFlow, Index}; impl<'tcx> Index<stable_mir::DefId> for Tables<'tcx> { type Output = DefId; #[inline(always)] fn index(&self, index: stable_mir::DefId) -> &Self::Output { - &self.def_ids[index.0] + &self.def_ids[index] } } @@ -29,7 +34,7 @@ impl<'tcx> Index<stable_mir::ty::Span> for Tables<'tcx> { #[inline(always)] fn index(&self, index: stable_mir::ty::Span) -> &Self::Output { - &self.spans[index.0] + &self.spans[index] } } @@ -94,37 +99,27 @@ impl<'tcx> Tables<'tcx> { stable_mir::ty::Prov(self.create_alloc_id(aid)) } - fn create_def_id(&mut self, did: DefId) -> stable_mir::DefId { - // FIXME: this becomes inefficient when we have too many ids - for (i, &d) in self.def_ids.iter().enumerate() { - if d == did { - return stable_mir::DefId(i); - } - } - let id = self.def_ids.len(); - self.def_ids.push(did); - stable_mir::DefId(id) + pub(crate) fn create_def_id(&mut self, did: DefId) -> stable_mir::DefId { + self.def_ids.create_or_fetch(did) } fn create_alloc_id(&mut self, aid: AllocId) -> stable_mir::AllocId { - // FIXME: this becomes inefficient when we have too many ids - if let Some(i) = self.alloc_ids.iter().position(|a| *a == aid) { - return stable_mir::AllocId(i); - }; - let id = self.def_ids.len(); - self.alloc_ids.push(aid); - stable_mir::AllocId(id) + self.alloc_ids.create_or_fetch(aid) } pub(crate) fn create_span(&mut self, span: Span) -> stable_mir::ty::Span { - for (i, &sp) in self.spans.iter().enumerate() { - if sp == span { - return stable_mir::ty::Span(i); - } - } - let id = self.spans.len(); - self.spans.push(span); - stable_mir::ty::Span(id) + self.spans.create_or_fetch(span) + } + + pub(crate) fn instance_def( + &mut self, + instance: ty::Instance<'tcx>, + ) -> stable_mir::mir::mono::InstanceDef { + self.instances.create_or_fetch(instance) + } + + pub(crate) fn static_def(&mut self, did: DefId) -> stable_mir::mir::mono::StaticDef { + stable_mir::mir::mono::StaticDef(self.create_def_id(did)) } } @@ -134,7 +129,14 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum { pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) { stable_mir::run( - Tables { tcx, def_ids: vec![], alloc_ids: vec![], spans: vec![], types: vec![] }, + Tables { + tcx, + def_ids: IndexMap::default(), + alloc_ids: IndexMap::default(), + spans: IndexMap::default(), + types: vec![], + instances: IndexMap::default(), + }, f, ); } @@ -197,3 +199,35 @@ where }) } } + +/// Simmilar to rustc's `FxIndexMap`, `IndexMap` with extra +/// safety features added. +pub struct IndexMap<K, V> { + index_map: fx::FxIndexMap<K, V>, +} + +impl<K, V> Default for IndexMap<K, V> { + fn default() -> Self { + Self { index_map: FxIndexMap::default() } + } +} + +impl<K: PartialEq + Hash + Eq, V: Copy + Debug + PartialEq + IndexedVal> IndexMap<K, V> { + pub fn create_or_fetch(&mut self, key: K) -> V { + let len = self.index_map.len(); + let v = self.index_map.entry(key).or_insert(V::to_val(len)); + *v + } +} + +impl<K: PartialEq + Hash + Eq, V: Copy + Debug + PartialEq + IndexedVal> Index<V> + for IndexMap<K, V> +{ + type Output = K; + + fn index(&self, index: V) -> &Self::Output { + let (k, v) = self.index_map.get_index(index.to_index()).unwrap(); + assert_eq!(*v, index, "Provided value doesn't match with indexed value"); + k + } +} diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 0c474192240..94dc15b4767 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -7,17 +7,22 @@ //! //! For now, we are developing everything inside `rustc`, thus, we keep this module private. +use crate::rustc_internal::IndexMap; use crate::rustc_smir::hir::def::DefKind; use crate::rustc_smir::stable_mir::ty::{BoundRegion, EarlyBoundRegion, Region}; use rustc_hir as hir; use rustc_middle::mir; use rustc_middle::mir::interpret::{alloc_range, AllocId}; -use rustc_middle::ty::{self, Ty, TyCtxt, Variance}; +use rustc_middle::mir::mono::MonoItem; +use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt, Variance}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_target::abi::FieldIdx; -use stable_mir::mir::{CopyNonOverlapping, Statement, UserTypeProjection, VariantIdx}; -use stable_mir::ty::{FloatTy, GenericParamDef, IntTy, Movability, RigidTy, Span, TyKind, UintTy}; -use stable_mir::{self, opaque, Context}; +use stable_mir::mir::mono::InstanceDef; +use stable_mir::mir::{Body, CopyNonOverlapping, Statement, UserTypeProjection, VariantIdx}; +use stable_mir::ty::{ + FloatTy, GenericParamDef, IntTy, LineInfo, Movability, RigidTy, Span, TyKind, UintTy, +}; +use stable_mir::{self, opaque, Context, Filename}; use tracing::debug; mod alloc; @@ -49,10 +54,27 @@ impl<'tcx> Context for Tables<'tcx> { self.tcx.def_path_str(self[def_id]) } - fn print_span(&self, span: stable_mir::ty::Span) -> String { + fn span_to_string(&self, span: stable_mir::ty::Span) -> String { self.tcx.sess.source_map().span_to_diagnostic_string(self[span]) } + fn get_filename(&self, span: &Span) -> Filename { + opaque( + &self + .tcx + .sess + .source_map() + .span_to_filename(self[*span]) + .display(rustc_span::FileNameDisplayPreference::Local) + .to_string(), + ) + } + + fn get_lines(&self, span: &Span) -> LineInfo { + let lines = &self.tcx.sess.source_map().span_to_location_info(self[*span]); + LineInfo { start_line: lines.1, start_col: lines.2, end_line: lines.3, end_col: lines.4 } + } + fn def_kind(&mut self, def_id: stable_mir::DefId) -> stable_mir::DefKind { self.tcx.def_kind(self[def_id]).stable(self) } @@ -99,29 +121,7 @@ impl<'tcx> Context for Tables<'tcx> { fn mir_body(&mut self, item: stable_mir::DefId) -> stable_mir::mir::Body { let def_id = self[item]; - let mir = self.tcx.instance_mir(ty::InstanceDef::Item(def_id)); - stable_mir::mir::Body { - blocks: mir - .basic_blocks - .iter() - .map(|block| stable_mir::mir::BasicBlock { - terminator: block.terminator().stable(self), - statements: block - .statements - .iter() - .map(|statement| statement.stable(self)) - .collect(), - }) - .collect(), - locals: mir - .local_decls - .iter() - .map(|decl| stable_mir::mir::LocalDecl { - ty: self.intern_ty(decl.ty), - span: decl.source_info.span.stable(self), - }) - .collect(), - } + self.tcx.instance_mir(ty::InstanceDef::Item(def_id)).stable(self) } fn ty_kind(&mut self, ty: stable_mir::ty::Ty) -> TyKind { @@ -170,6 +170,34 @@ impl<'tcx> Context for Tables<'tcx> { .collect(), } } + + fn instance_body(&mut self, _def: InstanceDef) -> Body { + todo!("Monomorphize the body") + } + + fn instance_ty(&mut self, def: InstanceDef) -> stable_mir::ty::Ty { + let instance = self.instances[def]; + let ty = instance.ty(self.tcx, ParamEnv::empty()); + self.intern_ty(ty) + } + + fn instance_def_id(&mut self, def: InstanceDef) -> stable_mir::DefId { + let def_id = self.instances[def].def_id(); + self.create_def_id(def_id) + } + + fn mono_instance(&mut self, item: stable_mir::CrateItem) -> stable_mir::mir::mono::Instance { + let def_id = self[item.0]; + Instance::mono(self.tcx, def_id).stable(self) + } + + fn requires_monomorphization(&self, def_id: stable_mir::DefId) -> bool { + let def_id = self[def_id]; + let generics = self.tcx.generics_of(def_id); + let result = generics.requires_monomorphization(self.tcx); + println!("req {result}: {def_id:?}"); + result + } } #[derive(Clone)] @@ -201,10 +229,11 @@ impl<S, R: PartialEq> PartialEq<R> for MaybeStable<S, R> { pub struct Tables<'tcx> { pub tcx: TyCtxt<'tcx>, - pub def_ids: Vec<DefId>, - pub alloc_ids: Vec<AllocId>, - pub spans: Vec<rustc_span::Span>, - pub types: Vec<MaybeStable<stable_mir::ty::TyKind, Ty<'tcx>>>, + pub def_ids: IndexMap<DefId, stable_mir::DefId>, + pub alloc_ids: IndexMap<AllocId, stable_mir::AllocId>, + pub spans: IndexMap<rustc_span::Span, Span>, + pub types: Vec<MaybeStable<TyKind, Ty<'tcx>>>, + pub instances: IndexMap<ty::Instance<'tcx>, InstanceDef>, } impl<'tcx> Tables<'tcx> { @@ -234,6 +263,35 @@ pub(crate) trait Stable<'tcx> { fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T; } +impl<'tcx> Stable<'tcx> for mir::Body<'tcx> { + type T = stable_mir::mir::Body; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + stable_mir::mir::Body { + blocks: self + .basic_blocks + .iter() + .map(|block| stable_mir::mir::BasicBlock { + terminator: block.terminator().stable(tables), + statements: block + .statements + .iter() + .map(|statement| statement.stable(tables)) + .collect(), + }) + .collect(), + locals: self + .local_decls + .iter() + .map(|decl| stable_mir::mir::LocalDecl { + ty: tables.intern_ty(decl.ty), + span: decl.source_info.span.stable(tables), + }) + .collect(), + } + } +} + impl<'tcx> Stable<'tcx> for mir::Statement<'tcx> { type T = stable_mir::mir::Statement; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { @@ -1617,3 +1675,38 @@ impl<'tcx> Stable<'tcx> for DefKind { opaque(self) } } + +impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> { + type T = stable_mir::mir::mono::Instance; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + let def = tables.instance_def(*self); + let kind = match self.def { + ty::InstanceDef::Item(..) => stable_mir::mir::mono::InstanceKind::Item, + ty::InstanceDef::Intrinsic(..) => stable_mir::mir::mono::InstanceKind::Intrinsic, + ty::InstanceDef::Virtual(..) => stable_mir::mir::mono::InstanceKind::Virtual, + ty::InstanceDef::VTableShim(..) + | ty::InstanceDef::ReifyShim(..) + | ty::InstanceDef::FnPtrAddrShim(..) + | ty::InstanceDef::ClosureOnceShim { .. } + | ty::InstanceDef::ThreadLocalShim(..) + | ty::InstanceDef::DropGlue(..) + | ty::InstanceDef::CloneShim(..) + | ty::InstanceDef::FnPtrShim(..) => stable_mir::mir::mono::InstanceKind::Shim, + }; + stable_mir::mir::mono::Instance { def, kind } + } +} + +impl<'tcx> Stable<'tcx> for MonoItem<'tcx> { + type T = stable_mir::mir::mono::MonoItem; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + use stable_mir::mir::mono::MonoItem as StableMonoItem; + match self { + MonoItem::Fn(instance) => StableMonoItem::Fn(instance.stable(tables)), + MonoItem::Static(def_id) => StableMonoItem::Static(tables.static_def(*def_id)), + MonoItem::GlobalAsm(item_id) => StableMonoItem::GlobalAsm(opaque(item_id)), + } + } +} diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 6fd61e45fcc..e62efab5793 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -14,6 +14,8 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![feature(array_windows)] #![feature(if_let_guard)] #![feature(negative_impls)] diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 93ab154601f..f7d17a267d6 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -126,7 +126,7 @@ impl Span { return Span { lo_or_index: lo2, len_with_tag_or_marker: PARENT_TAG | len as u16, - ctxt_or_parent_or_marker: parent2 as u16 + ctxt_or_parent_or_marker: parent2 as u16, }; } } @@ -212,6 +212,7 @@ impl Span { /// This function is used as a fast path when decoding the full `SpanData` is not necessary. /// It's a cut-down version of `data_untracked`. + #[cfg_attr(not(test), rustc_diagnostic_item = "SpanCtxt")] #[inline] pub fn ctxt(self) -> SyntaxContext { if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a62fa246ac4..be8c65862dc 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -303,6 +303,7 @@ symbols! { SliceIndex, SliceIter, Some, + SpanCtxt, String, StructuralEq, StructuralPartialEq, @@ -1327,6 +1328,7 @@ symbols! { rust_cold_cc, rust_eh_catch_typeinfo, rust_eh_personality, + rust_logo, rustc, rustc_abi, rustc_allocator, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 2fc102bda13..5290da9a25b 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -1,7 +1,7 @@ use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_hir::def_id::CrateNum; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; -use rustc_middle::ty::print::{PrettyPrinter, Print, Printer}; +use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{GenericArg, GenericArgKind}; use rustc_middle::util::common::record_time; @@ -200,23 +200,15 @@ struct SymbolPrinter<'tcx> { // symbol names should have their own printing machinery. impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> { - type Error = fmt::Error; - - type Path = Self; - type Region = Self; - type Type = Self; - type DynExistential = Self; - type Const = Self; - fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } - fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> { + fn print_region(self, _region: ty::Region<'_>) -> Result<Self, PrintError> { Ok(self) } - fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> { + fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self, PrintError> { match *ty.kind() { // Print all nominal types as paths (unlike `pretty_print_type`). ty::FnDef(def_id, args) @@ -250,7 +242,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> { fn print_dyn_existential( mut self, predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, - ) -> Result<Self::DynExistential, Self::Error> { + ) -> Result<Self, PrintError> { let mut first = true; for p in predicates { if !first { @@ -262,7 +254,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> { Ok(self) } - fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { + fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self, PrintError> { // only print integers match (ct.kind(), ct.ty().kind()) { (ty::ConstKind::Value(ty::ValTree::Leaf(scalar)), ty::Int(_) | ty::Uint(_)) => { @@ -280,7 +272,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> { Ok(self) } - fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { + fn path_crate(self, cnum: CrateNum) -> Result<Self, PrintError> { self.write_str(self.tcx.crate_name(cnum).as_str())?; Ok(self) } @@ -288,7 +280,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> { self, self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { // Similar to `pretty_path_qualified`, but for the other // types that are printed as paths (see `print_type` above). match self_ty.kind() { @@ -304,11 +296,11 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> { fn path_append_impl( self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, _disambiguated_data: &DisambiguatedDefPathData, self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { self.pretty_path_append_impl( |mut cx| { cx = print_prefix(cx)?; @@ -328,9 +320,9 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> { } fn path_append( mut self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, disambiguated_data: &DisambiguatedDefPathData, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { self = print_prefix(self)?; // Skip `::{{extern}}` blocks and `::{{constructor}}` on tuple/unit structs. @@ -351,9 +343,9 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> { } fn path_generic_args( mut self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, args: &[GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { self = print_prefix(self)?; let args = @@ -371,9 +363,9 @@ impl<'tcx> PrettyPrinter<'tcx> for &mut SymbolPrinter<'tcx> { fn should_print_region(&self, _region: ty::Region<'_>) -> bool { false } - fn comma_sep<T>(mut self, mut elems: impl Iterator<Item = T>) -> Result<Self, Self::Error> + fn comma_sep<T>(mut self, mut elems: impl Iterator<Item = T>) -> Result<Self, PrintError> where - T: Print<'tcx, Self, Output = Self, Error = Self::Error>, + T: Print<'tcx, Self>, { if let Some(first) = elems.next() { self = first.print(self)?; @@ -387,8 +379,8 @@ impl<'tcx> PrettyPrinter<'tcx> for &mut SymbolPrinter<'tcx> { fn generic_delimiters( mut self, - f: impl FnOnce(Self) -> Result<Self, Self::Error>, - ) -> Result<Self, Self::Error> { + f: impl FnOnce(Self) -> Result<Self, PrintError>, + ) -> Result<Self, PrintError> { write!(self, "<")?; let kept_within_component = mem::replace(&mut self.keep_within_component, true); diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 535a3ea2d7e..6ade2d777c7 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -88,6 +88,9 @@ //! DefPaths which are much more robust in the face of changes to the code base. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), allow(internal_features))] #![feature(never_type)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 82b1a772e3d..99c5d016439 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -6,7 +6,7 @@ use rustc_hir::def::CtorKind; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use rustc_middle::ty::layout::IntegerExt; -use rustc_middle::ty::print::{Print, Printer}; +use rustc_middle::ty::print::{Print, PrintError, Printer}; use rustc_middle::ty::{ self, EarlyBinder, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeVisitable, TypeVisitableExt, UintTy, @@ -181,11 +181,11 @@ impl<'tcx> SymbolMangler<'tcx> { fn path_append_ns<'a>( mut self: &'a mut Self, - print_prefix: impl FnOnce(&'a mut Self) -> Result<&'a mut Self, !>, + print_prefix: impl FnOnce(&'a mut Self) -> Result<&'a mut Self, PrintError>, ns: char, disambiguator: u64, name: &str, - ) -> Result<&'a mut Self, !> { + ) -> Result<&'a mut Self, PrintError> { self.push("N"); self.out.push(ns); self = print_prefix(self)?; @@ -194,7 +194,7 @@ impl<'tcx> SymbolMangler<'tcx> { Ok(self) } - fn print_backref(&mut self, i: usize) -> Result<&mut Self, !> { + fn print_backref(&mut self, i: usize) -> Result<&mut Self, PrintError> { self.push("B"); self.push_integer_62((i - self.start_offset) as u64); Ok(self) @@ -203,8 +203,8 @@ impl<'tcx> SymbolMangler<'tcx> { fn in_binder<'a, T>( mut self: &'a mut Self, value: &ty::Binder<'tcx, T>, - print_value: impl FnOnce(&'a mut Self, &T) -> Result<&'a mut Self, !>, - ) -> Result<&'a mut Self, !> + print_value: impl FnOnce(&'a mut Self, &T) -> Result<&'a mut Self, PrintError>, + ) -> Result<&'a mut Self, PrintError> where T: TypeVisitable<TyCtxt<'tcx>>, { @@ -230,14 +230,6 @@ impl<'tcx> SymbolMangler<'tcx> { } impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { - type Error = !; - - type Path = Self; - type Region = Self; - type Type = Self; - type DynExistential = Self; - type Const = Self; - fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -246,7 +238,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { mut self, def_id: DefId, args: &'tcx [GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { if let Some(&i) = self.paths.get(&(def_id, args)) { return self.print_backref(i); } @@ -268,7 +260,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { args: &'tcx [GenericArg<'tcx>], mut self_ty: Ty<'tcx>, mut impl_trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { let key = self.tcx.def_key(impl_def_id); let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id }; @@ -321,7 +313,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { Ok(self) } - fn print_region(self, region: ty::Region<'_>) -> Result<Self::Region, Self::Error> { + fn print_region(self, region: ty::Region<'_>) -> Result<Self, PrintError> { let i = match *region { // Erased lifetimes use the index 0, for a // shorter mangling of `L_`. @@ -343,7 +335,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { Ok(self) } - fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> { + fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self, PrintError> { // Basic types, never cached (single-character). let basic_type = match ty.kind() { ty::Bool => "b", @@ -498,7 +490,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { fn print_dyn_existential( mut self, predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, - ) -> Result<Self::DynExistential, Self::Error> { + ) -> Result<Self, PrintError> { // Okay, so this is a bit tricky. Imagine we have a trait object like // `dyn for<'a> Foo<'a, Bar = &'a ()>`. When we mangle this, the // output looks really close to the syntax, where the `Bar = &'a ()` bit @@ -559,7 +551,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { Ok(self) } - fn print_const(mut self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { + fn print_const(mut self, ct: ty::Const<'tcx>) -> Result<Self, PrintError> { // We only mangle a typed value if the const can be evaluated. let ct = ct.normalize(self.tcx, ty::ParamEnv::reveal_all()); match ct.kind() { @@ -731,7 +723,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { Ok(self) } - fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { + fn path_crate(self, cnum: CrateNum) -> Result<Self, PrintError> { self.push("C"); let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id(); self.push_disambiguator(stable_crate_id.as_u64()); @@ -744,7 +736,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { mut self, self_ty: Ty<'tcx>, trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { assert!(trait_ref.is_some()); let trait_ref = trait_ref.unwrap(); @@ -755,20 +747,20 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { fn path_append_impl( self, - _: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + _: impl FnOnce(Self) -> Result<Self, PrintError>, _: &DisambiguatedDefPathData, _: Ty<'tcx>, _: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { // Inlined into `print_impl_path` unreachable!() } fn path_append( self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, disambiguated_data: &DisambiguatedDefPathData, - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { let ns = match disambiguated_data.data { // Extern block segments can be skipped, names from extern blocks // are effectively living in their parent modules. @@ -806,9 +798,9 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { fn path_generic_args( mut self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + print_prefix: impl FnOnce(Self) -> Result<Self, PrintError>, args: &[GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { + ) -> Result<Self, PrintError> { // Don't print any regions if they're all erased. let print_regions = args.iter().any(|arg| match arg.unpack() { GenericArgKind::Lifetime(r) => !r.is_erased(), diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs index afa1b70efc2..c27f1e6ddda 100644 --- a/compiler/rustc_target/src/abi/call/x86.rs +++ b/compiler/rustc_target/src/abi/call/x86.rs @@ -72,7 +72,8 @@ where // - For backwards compatibility, arguments with natural alignment > 4 are still passed // on stack (via `byval`). For example, this includes `double`, `int64_t`, // and structs containing them, provided they lack an explicit alignment attribute. - assert!(arg.layout.align.abi >= max_repr_align, + assert!( + arg.layout.align.abi >= max_repr_align, "abi alignment {:?} less than requested alignment {max_repr_align:?}", arg.layout.align.abi, ); diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index e838e11131f..9c5ce889418 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -8,6 +8,8 @@ //! LLVM. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![feature(assert_matches)] #![feature(associated_type_bounds)] #![feature(exhaustive_patterns)] diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs index a99cccd42c4..4c1f0c01a04 100644 --- a/compiler/rustc_target/src/spec/abi.rs +++ b/compiler/rustc_target/src/spec/abi.rs @@ -182,7 +182,7 @@ pub fn is_enabled( ) -> Result<(), AbiDisabled> { let s = is_stable(name); if let Err(AbiDisabled::Unstable { feature, .. }) = s { - if features.enabled(feature) || span.allows_unstable(feature) { + if features.active(feature) || span.allows_unstable(feature) { return Ok(()); } } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index d4774386e2e..16f70cf43b3 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -164,11 +164,11 @@ pub enum LinkerFlavor { /// Linker flavors available externally through command line (`-Clinker-flavor`) /// or json target specifications. -/// FIXME: This set has accumulated historically, bring it more in line with the internal -/// linker flavors (`LinkerFlavor`). +/// This set has accumulated historically, and contains both (stable and unstable) legacy values, as +/// well as modern ones matching the internal linker flavors (`LinkerFlavor`). #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub enum LinkerFlavorCli { - // New (unstable) flavors, with direct counterparts in `LinkerFlavor`. + // Modern (unstable) flavors, with direct counterparts in `LinkerFlavor`. Gnu(Cc, Lld), Darwin(Cc, Lld), WasmLld(Cc), @@ -179,7 +179,7 @@ pub enum LinkerFlavorCli { Bpf, Ptx, - // Below: the legacy stable values. + // Legacy stable values Gcc, Ld, Lld(LldFlavor), @@ -504,7 +504,7 @@ linker_flavor_cli_impls! { (LinkerFlavorCli::Bpf) "bpf" (LinkerFlavorCli::Ptx) "ptx" - // Below: legacy stable values + // Legacy stable flavors (LinkerFlavorCli::Gcc) "gcc" (LinkerFlavorCli::Ld) "ld" (LinkerFlavorCli::Lld(LldFlavor::Ld)) "ld.lld" @@ -520,6 +520,80 @@ impl ToJson for LinkerFlavorCli { } } +bitflags::bitflags! { + #[derive(Default)] + /// The `-C link-self-contained` components that can individually be enabled or disabled. + pub struct LinkSelfContainedComponents: u8 { + /// CRT objects (e.g. on `windows-gnu`, `musl`, `wasi` targets) + const CRT_OBJECTS = 1 << 0; + /// libc static library (e.g. on `musl`, `wasi` targets) + const LIBC = 1 << 1; + /// libgcc/libunwind (e.g. on `windows-gnu`, `fuchsia`, `fortanix`, `gnullvm` targets) + const UNWIND = 1 << 2; + /// Linker, dlltool, and their necessary libraries (e.g. on `windows-gnu` and for `rust-lld`) + const LINKER = 1 << 3; + /// Sanitizer runtime libraries + const SANITIZERS = 1 << 4; + /// Other MinGW libs and Windows import libs + const MINGW = 1 << 5; + } +} + +impl LinkSelfContainedComponents { + /// Parses a single `-Clink-self-contained` well-known component, not a set of flags. + pub fn from_str(s: &str) -> Option<LinkSelfContainedComponents> { + Some(match s { + "crto" => LinkSelfContainedComponents::CRT_OBJECTS, + "libc" => LinkSelfContainedComponents::LIBC, + "unwind" => LinkSelfContainedComponents::UNWIND, + "linker" => LinkSelfContainedComponents::LINKER, + "sanitizers" => LinkSelfContainedComponents::SANITIZERS, + "mingw" => LinkSelfContainedComponents::MINGW, + _ => return None, + }) + } + + /// Return the component's name. + /// + /// Returns `None` if the bitflags aren't a singular component (but a mix of multiple flags). + pub fn as_str(self) -> Option<&'static str> { + Some(match self { + LinkSelfContainedComponents::CRT_OBJECTS => "crto", + LinkSelfContainedComponents::LIBC => "libc", + LinkSelfContainedComponents::UNWIND => "unwind", + LinkSelfContainedComponents::LINKER => "linker", + LinkSelfContainedComponents::SANITIZERS => "sanitizers", + LinkSelfContainedComponents::MINGW => "mingw", + _ => return None, + }) + } + + /// Returns an array of all the components. + fn all_components() -> [LinkSelfContainedComponents; 6] { + [ + LinkSelfContainedComponents::CRT_OBJECTS, + LinkSelfContainedComponents::LIBC, + LinkSelfContainedComponents::UNWIND, + LinkSelfContainedComponents::LINKER, + LinkSelfContainedComponents::SANITIZERS, + LinkSelfContainedComponents::MINGW, + ] + } +} + +impl IntoIterator for LinkSelfContainedComponents { + type Item = LinkSelfContainedComponents; + type IntoIter = std::vec::IntoIter<LinkSelfContainedComponents>; + + fn into_iter(self) -> Self::IntoIter { + LinkSelfContainedComponents::all_components() + .into_iter() + .filter(|&s| self.contains(s)) + .collect::<Vec<_>>() + .into_iter() + } +} + #[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)] pub enum PanicStrategy { Unwind, diff --git a/compiler/rustc_target/src/spec/riscv64_linux_android.rs b/compiler/rustc_target/src/spec/riscv64_linux_android.rs index 91f5e562d8b..121237f6ba4 100644 --- a/compiler/rustc_target/src/spec/riscv64_linux_android.rs +++ b/compiler/rustc_target/src/spec/riscv64_linux_android.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { options: TargetOptions { code_model: Some(CodeModel::Medium), cpu: "generic-rv64".into(), - features: "+m,+a,+f,+d,+c,+Zba,+Zbb,+Zbs".into(), + features: "+m,+a,+f,+d,+c,+zba,+zbb,+zbs,+v".into(), llvm_abiname: "lp64d".into(), supported_sanitizers: SanitizerSet::ADDRESS, max_atomic_width: Some(64), diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 56d37d58de7..5ba29f87855 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -11,6 +11,9 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), allow(internal_features))] #![feature(associated_type_bounds)] #![feature(box_patterns)] #![feature(control_flow_enum)] diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 066129d8e47..066129d8e47 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 77a3b5e1284..d45fe102805 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -32,14 +32,11 @@ mod assembly; mod canonicalize; mod eval_ctxt; mod fulfill; -mod inherent_projection; pub mod inspect; mod normalize; -mod opaques; mod project_goals; mod search_graph; mod trait_goals; -mod weak_types; pub use eval_ctxt::{ EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt, UseGlobalCache, diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index 872f0c87916..b0a34898570 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -129,7 +129,7 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> { self.at.cause.clone(), self.at.param_env, ty::ProjectionPredicate { - projection_ty: tcx.mk_alias_ty(uv.def, uv.args), + projection_ty: AliasTy::new(tcx, uv.def, uv.args), term: new_infer_ct.into(), }, ); diff --git a/compiler/rustc_trait_selection/src/solve/inherent_projection.rs b/compiler/rustc_trait_selection/src/solve/project_goals/inherent_projection.rs index 28fe59b7f6a..28fe59b7f6a 100644 --- a/compiler/rustc_trait_selection/src/solve/inherent_projection.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals/inherent_projection.rs diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs index 339a3e73846..73c8d0c85dd 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs @@ -18,6 +18,10 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ToPredicate, TypeVisitableExt}; use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP}; +mod inherent_projection; +mod opaques; +mod weak_types; + impl<'tcx> EvalCtxt<'_, 'tcx> { #[instrument(level = "debug", skip(self), ret)] pub(super) fn compute_projection_goal( @@ -348,8 +352,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { let pred = tupled_inputs_and_output .map_bound(|(inputs, output)| ty::ProjectionPredicate { - projection_ty: tcx - .mk_alias_ty(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]), + projection_ty: ty::AliasTy::new( + tcx, + goal.predicate.def_id(), + [goal.predicate.self_ty(), inputs], + ), term: output.into(), }) .to_predicate(tcx); @@ -468,7 +475,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ecx, goal, ty::ProjectionPredicate { - projection_ty: ecx.tcx().mk_alias_ty(goal.predicate.def_id(), [self_ty]), + projection_ty: ty::AliasTy::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]), term, } .to_predicate(tcx), @@ -508,9 +515,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ecx, goal, ty::ProjectionPredicate { - projection_ty: ecx - .tcx() - .mk_alias_ty(goal.predicate.def_id(), [self_ty, generator.resume_ty()]), + projection_ty: ty::AliasTy::new( + ecx.tcx(), + goal.predicate.def_id(), + [self_ty, generator.resume_ty()], + ), term, } .to_predicate(tcx), diff --git a/compiler/rustc_trait_selection/src/solve/opaques.rs b/compiler/rustc_trait_selection/src/solve/project_goals/opaques.rs index f08adc0208b..ebd129f32b9 100644 --- a/compiler/rustc_trait_selection/src/solve/opaques.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals/opaques.rs @@ -7,7 +7,7 @@ use rustc_middle::traits::Reveal; use rustc_middle::ty; use rustc_middle::ty::util::NotUniqueParam; -use super::{EvalCtxt, SolverMode}; +use crate::solve::{EvalCtxt, SolverMode}; impl<'tcx> EvalCtxt<'_, 'tcx> { pub(super) fn normalize_opaque_type( diff --git a/compiler/rustc_trait_selection/src/solve/weak_types.rs b/compiler/rustc_trait_selection/src/solve/project_goals/weak_types.rs index 54de32cf618..54de32cf618 100644 --- a/compiler/rustc_trait_selection/src/solve/weak_types.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals/weak_types.rs diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph.rs index 33513f6bd43..33513f6bd43 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph.rs diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 8055c63b9f3..d87e05ad02f 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -136,12 +136,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // `assemble_candidates_after_normalizing_self_ty`, and we'd // just be registering an identical candidate here. // - // Returning `Err(NoSolution)` here is ok in `SolverMode::Coherence` - // since we'll always be registering an ambiguous candidate in + // We always return `Err(NoSolution)` here in `SolverMode::Coherence` + // since we'll always register an ambiguous candidate in // `assemble_candidates_after_normalizing_self_ty` due to normalizing // the TAIT. if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() { if matches!(goal.param_env.reveal(), Reveal::All) + || matches!(ecx.solver_mode(), SolverMode::Coherence) || opaque_ty .def_id .as_local() diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs index fd813ca4ecb..5bc5a12a8fe 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs @@ -87,7 +87,9 @@ pub fn recompute_applicable_impls<'tcx>( if let ty::ClauseKind::Trait(trait_pred) = kind.skip_binder() && param_env_candidate_may_apply(kind.rebind(trait_pred)) { - if kind.rebind(trait_pred.trait_ref) == ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_pred.def_id())) { + if kind.rebind(trait_pred.trait_ref) + == ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_pred.def_id())) + { ambiguities.push(Ambiguity::ParamEnv(tcx.def_span(trait_pred.def_id()))) } else { ambiguities.push(Ambiguity::ParamEnv(span)) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index d9059e46a8c..9c9b78f4152 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -1,6 +1,6 @@ use super::{ObligationCauseCode, PredicateObligation}; use crate::infer::error_reporting::TypeErrCtxt; -use rustc_ast::{MetaItem, NestedMetaItem}; +use rustc_ast::{Attribute, MetaItem, NestedMetaItem}; use rustc_attr as attr; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{struct_span_err, ErrorGuaranteed}; @@ -180,8 +180,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { flags.push((sym::cause, Some("MainFunctionType".to_string()))); } - // Add all types without trimmed paths. - ty::print::with_no_trimmed_paths!({ + // Add all types without trimmed paths or visible paths, ensuring they end up with + // their "canonical" def path. + ty::print::with_no_trimmed_paths!(ty::print::with_no_visible_paths!({ let generics = self.tcx.generics_of(def_id); let self_ty = trait_ref.self_ty(); // This is also included through the generics list as `Self`, @@ -296,7 +297,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { { flags.push((sym::_Self, Some("&[{integral}]".to_owned()))); } - }); + })); if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) { command.evaluate(self.tcx, trait_ref, &flags) @@ -368,7 +369,9 @@ impl<'tcx> OnUnimplementedDirective { .meta_item() .ok_or_else(|| tcx.sess.emit_err(InvalidOnClauseInOnUnimplemented { span }))?; attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |cfg| { - if let Some(value) = cfg.value && let Err(guar) = parse_value(value) { + if let Some(value) = cfg.value + && let Err(guar) = parse_value(value) + { errored = Some(guar); } true @@ -474,18 +477,40 @@ impl<'tcx> OnUnimplementedDirective { } pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> { - let mut is_diagnostic_namespace_variant = false; - let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented).or_else(|| { - if tcx.features().diagnostic_namespace { - is_diagnostic_namespace_variant = true; - tcx.get_attrs_by_path(item_def_id, &[sym::diagnostic, sym::on_unimplemented]).next() - } else { - None - } - }) else { - return Ok(None); - }; + if let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) { + return Self::parse_attribute(attr, false, tcx, item_def_id); + } else if tcx.features().diagnostic_namespace { + tcx.get_attrs_by_path(item_def_id, &[sym::diagnostic, sym::on_unimplemented]) + .filter_map(|attr| Self::parse_attribute(attr, true, tcx, item_def_id).transpose()) + .try_fold(None, |aggr: Option<Self>, directive| { + let directive = directive?; + if let Some(aggr) = aggr { + let mut subcommands = aggr.subcommands; + subcommands.extend(directive.subcommands); + Ok(Some(Self { + condition: aggr.condition.or(directive.condition), + subcommands, + message: aggr.message.or(directive.message), + label: aggr.label.or(directive.label), + note: aggr.note.or(directive.note), + parent_label: aggr.parent_label.or(directive.parent_label), + append_const_msg: aggr.append_const_msg.or(directive.append_const_msg), + })) + } else { + Ok(Some(directive)) + } + }) + } else { + Ok(None) + } + } + fn parse_attribute( + attr: &Attribute, + is_diagnostic_namespace_variant: bool, + tcx: TyCtxt<'tcx>, + item_def_id: DefId, + ) -> Result<Option<Self>, ErrorGuaranteed> { let result = if let Some(items) = attr.meta_item_list() { Self::parse(tcx, item_def_id, &items, attr.span, true, is_diagnostic_namespace_variant) } else if let Some(value) = attr.value_str() { @@ -547,18 +572,22 @@ impl<'tcx> OnUnimplementedDirective { options.iter().filter_map(|(k, v)| v.clone().map(|v| (*k, v))).collect(); for command in self.subcommands.iter().chain(Some(self)).rev() { - if let Some(ref condition) = command.condition && !attr::eval_condition( - condition, - &tcx.sess.parse_sess, - Some(tcx.features()), - &mut |cfg| { - let value = cfg.value.map(|v| { - OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map) - }); - - options.contains(&(cfg.name, value)) - }, - ) { + if let Some(ref condition) = command.condition + && !attr::eval_condition( + condition, + &tcx.sess.parse_sess, + Some(tcx.features()), + &mut |cfg| { + let value = cfg.value.map(|v| { + // `with_no_visible_paths` is also used when generating the options, + // so we need to match it here. + ty::print::with_no_visible_paths!(OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map)) + }); + + options.contains(&(cfg.name, value)) + }, + ) + { debug!("evaluate: skipping {:?} due to condition", command); continue; } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 9aebe77a104..66529b67c17 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -313,6 +313,18 @@ pub trait TypeErrCtxtExt<'tcx> { predicate: ty::Predicate<'tcx>, call_hir_id: HirId, ); + + fn look_for_iterator_item_mistakes( + &self, + assocs_in_this_method: &[Option<(Span, (DefId, Ty<'tcx>))>], + typeck_results: &TypeckResults<'tcx>, + type_diffs: &[TypeError<'tcx>], + param_env: ty::ParamEnv<'tcx>, + path_segment: &hir::PathSegment<'_>, + args: &[hir::Expr<'_>], + err: &mut Diagnostic, + ); + fn point_at_chain( &self, expr: &hir::Expr<'_>, @@ -321,6 +333,7 @@ pub trait TypeErrCtxtExt<'tcx> { param_env: ty::ParamEnv<'tcx>, err: &mut Diagnostic, ); + fn probe_assoc_types_at_expr( &self, type_diffs: &[TypeError<'tcx>], @@ -364,7 +377,7 @@ fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) - /// Type parameter needs more bounds. The trivial case is `T` `where T: Bound`, but /// it can also be an `impl Trait` param that needs to be decomposed to a type /// param for cleaner code. -fn suggest_restriction<'tcx>( +pub fn suggest_restriction<'tcx>( tcx: TyCtxt<'tcx>, item_id: LocalDefId, hir_generics: &hir::Generics<'tcx>, @@ -884,7 +897,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { return false; } - if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = obligation.predicate.kind().skip_binder() + if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = + obligation.predicate.kind().skip_binder() && Some(trait_pred.def_id()) == self.tcx.lang_items().sized_trait() { // Don't suggest calling to turn an unsized type into a sized type @@ -1156,15 +1170,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() // args tuple will always be args[1] && let ty::Tuple(args) = proj.projection_ty.args.type_at(1).kind() - { - Some(( - DefIdOrName::DefId(def_id), - pred.kind().rebind(proj.term.ty().unwrap()), - pred.kind().rebind(args.as_slice()), - )) - } else { - None - } + { + Some(( + DefIdOrName::DefId(def_id), + pred.kind().rebind(proj.term.ty().unwrap()), + pred.kind().rebind(args.as_slice()), + )) + } else { + None + } }, ) } @@ -1174,43 +1188,43 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { && Some(proj.def_id) == self.tcx.lang_items().fn_once_output() // for existential projection, args are shifted over by 1 && let ty::Tuple(args) = proj.args.type_at(0).kind() - { - Some(( - DefIdOrName::Name("trait object"), - pred.rebind(proj.term.ty().unwrap()), - pred.rebind(args.as_slice()), - )) - } else { - None - } + { + Some(( + DefIdOrName::Name("trait object"), + pred.rebind(proj.term.ty().unwrap()), + pred.rebind(args.as_slice()), + )) + } else { + None + } }) } ty::Param(param) => { let generics = self.tcx.generics_of(body_id); let name = if generics.count() > param.index as usize - && let def = generics.param_at(param.index as usize, self.tcx) - && matches!(def.kind, ty::GenericParamDefKind::Type { .. }) - && def.name == param.name - { - DefIdOrName::DefId(def.def_id) - } else { - DefIdOrName::Name("type parameter") - }; + && let def = generics.param_at(param.index as usize, self.tcx) + && matches!(def.kind, ty::GenericParamDefKind::Type { .. }) + && def.name == param.name + { + DefIdOrName::DefId(def.def_id) + } else { + DefIdOrName::Name("type parameter") + }; param_env.caller_bounds().iter().find_map(|pred| { if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder() && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() && proj.projection_ty.self_ty() == found // args tuple will always be args[1] && let ty::Tuple(args) = proj.projection_ty.args.type_at(1).kind() - { - Some(( - name, - pred.kind().rebind(proj.term.ty().unwrap()), - pred.kind().rebind(args.as_slice()), - )) - } else { - None - } + { + Some(( + name, + pred.kind().rebind(proj.term.ty().unwrap()), + pred.kind().rebind(args.as_slice()), + )) + } else { + None + } }) } _ => None, @@ -1316,7 +1330,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref); let (ref_inner_ty_satisfies_pred, ref_inner_ty_mut) = - if let ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::ExprItemObligation(..) = obligation.cause.code() + if let ObligationCauseCode::ItemObligation(_) + | ObligationCauseCode::ExprItemObligation(..) = obligation.cause.code() && let ty::Ref(_, ty, mutability) = old_pred.self_ty().skip_binder().kind() { ( @@ -1618,7 +1633,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic) { let hir = self.tcx.hir(); - if let ObligationCauseCode::AwaitableExpr(Some(hir_id)) = obligation.cause.code().peel_derives() + if let ObligationCauseCode::AwaitableExpr(Some(hir_id)) = + obligation.cause.code().peel_derives() && let hir::Node::Expr(expr) = hir.get(*hir_id) { // FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()` @@ -1630,7 +1646,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let Some((_, hir::Node::Expr(await_expr))) = hir.parent_iter(*hir_id).nth(1) && let Some(expr_span) = expr.span.find_ancestor_inside(await_expr.span) { - let removal_span = self.tcx + let removal_span = self + .tcx .sess .source_map() .span_extend_while(expr_span, char::is_whitespace) @@ -1654,30 +1671,28 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.span_label(*span, format!("this call returns `{}`", pred.self_ty())); } if let Some(typeck_results) = &self.typeck_results - && let ty = typeck_results.expr_ty_adjusted(base) - && let ty::FnDef(def_id, _args) = ty.kind() - && let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) = - hir.get_if_local(*def_id) - { - let msg = format!( - "alternatively, consider making `fn {ident}` asynchronous" + && let ty = typeck_results.expr_ty_adjusted(base) + && let ty::FnDef(def_id, _args) = ty.kind() + && let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) = + hir.get_if_local(*def_id) + { + let msg = format!("alternatively, consider making `fn {ident}` asynchronous"); + if vis_span.is_empty() { + err.span_suggestion_verbose( + span.shrink_to_lo(), + msg, + "async ", + Applicability::MaybeIncorrect, + ); + } else { + err.span_suggestion_verbose( + vis_span.shrink_to_hi(), + msg, + " async", + Applicability::MaybeIncorrect, ); - if vis_span.is_empty() { - err.span_suggestion_verbose( - span.shrink_to_lo(), - msg, - "async ", - Applicability::MaybeIncorrect, - ); - } else { - err.span_suggestion_verbose( - vis_span.shrink_to_hi(), - msg, - " async", - Applicability::MaybeIncorrect, - ); - } } + } } } } @@ -1791,13 +1806,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { "this expression has type `{}`, which implements `{}`", ty, trait_pred.print_modifiers_and_trait_path() - ) + ), ); err.span_suggestion( self.tcx.sess.source_map().end_point(stmt.span), "remove this semicolon", "", - Applicability::MachineApplicable + Applicability::MachineApplicable, ); return true; } @@ -1856,14 +1871,18 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut sugg = vec![(span.shrink_to_lo(), "Box<".to_string()), (span.shrink_to_hi(), ">".to_string())]; sugg.extend(visitor.returns.into_iter().flat_map(|expr| { - let span = expr.span.find_ancestor_in_same_ctxt(obligation.cause.span).unwrap_or(expr.span); + let span = + expr.span.find_ancestor_in_same_ctxt(obligation.cause.span).unwrap_or(expr.span); if !span.can_be_used_for_suggestions() { vec![] } else if let hir::ExprKind::Call(path, ..) = expr.kind && let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, method)) = path.kind && method.ident.name == sym::new && let hir::TyKind::Path(hir::QPath::Resolved(.., box_path)) = ty.kind - && box_path.res.opt_def_id().is_some_and(|def_id| Some(def_id) == self.tcx.lang_items().owned_box()) + && box_path + .res + .opt_def_id() + .is_some_and(|def_id| Some(def_id) == self.tcx.lang_items().owned_box()) { // Don't box `Box::new` vec![] @@ -2013,15 +2032,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { { let expected_self = self.tcx.anonymize_bound_vars(pred.kind().rebind(trait_pred.self_ty())); - let expected_args = self - .tcx - .anonymize_bound_vars(pred.kind().rebind(trait_pred.trait_ref.args)); + let expected_args = + self.tcx.anonymize_bound_vars(pred.kind().rebind(trait_pred.trait_ref.args)); // Find another predicate whose self-type is equal to the expected self type, // but whose args don't match. - let other_pred = predicates.into_iter() - .enumerate() - .find(|(other_idx, (pred, _))| match pred.kind().skip_binder() { + let other_pred = predicates.into_iter().enumerate().find(|(other_idx, (pred, _))| { + match pred.kind().skip_binder() { ty::ClauseKind::Trait(trait_pred) if self.tcx.is_fn_trait(trait_pred.def_id()) && other_idx != idx @@ -2040,7 +2057,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { true } _ => false, - }); + } + }); // If we found one, then it's very likely the cause of the error. if let Some((_, (_, other_pred_span))) = other_pred { err.span_note( @@ -2647,7 +2665,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Check for foreign traits being reachable. self.tcx.visible_parent_map(()).get(&def_id).is_some() }; - if let DefKind::Trait = tcx.def_kind(item_def_id) && !visible_item { + if let DefKind::Trait = tcx.def_kind(item_def_id) + && !visible_item + { // FIXME(estebank): extend this to search for all the types that do // implement this trait and list them. err.note(format!( @@ -2754,7 +2774,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { && let ty::ClauseKind::Trait(trait_pred) = clause && let ty::Dynamic(..) = trait_pred.self_ty().kind() { - let span = if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) + let span = if let Ok(snippet) = + self.tcx.sess.source_map().span_to_snippet(span) && snippet.starts_with("dyn ") { let pos = snippet.len() - snippet[3..].trim_start().len(); @@ -2845,8 +2866,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.note("all inline asm arguments must have a statically known size"); } ObligationCauseCode::SizedClosureCapture(closure_def_id) => { - err.note("all values captured by value by a closure must have a statically known size"); - let hir::ExprKind::Closure(closure) = self.tcx.hir().get_by_def_id(closure_def_id).expect_expr().kind else { + err.note( + "all values captured by value by a closure must have a statically known size", + ); + let hir::ExprKind::Closure(closure) = + self.tcx.hir().get_by_def_id(closure_def_id).expect_expr().kind + else { bug!("expected closure in SizedClosureCapture obligation"); }; if let hir::CaptureBy::Value = closure.capture_clause @@ -2860,7 +2885,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { None | Some(hir::GeneratorKind::Gen) => "yield", Some(hir::GeneratorKind::Async(..)) => "await", }; - err.note(format!("all values live across `{what}` must have a statically known size")); + err.note(format!( + "all values live across `{what}` must have a statically known size" + )); } ObligationCauseCode::ConstPatternStructural => { err.note("constants used for pattern-matching must derive `PartialEq` and `Eq`"); @@ -3385,15 +3412,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, ) { if let ObligationCauseCode::ImplDerivedObligation(_) = obligation.cause.code() - && self.tcx.is_diagnostic_item(sym::SliceIndex, trait_pred.skip_binder().trait_ref.def_id) + && self + .tcx + .is_diagnostic_item(sym::SliceIndex, trait_pred.skip_binder().trait_ref.def_id) && let ty::Slice(_) = trait_pred.skip_binder().trait_ref.args.type_at(1).kind() && let ty::Ref(_, inner_ty, _) = trait_pred.skip_binder().self_ty().kind() && let ty::Uint(ty::UintTy::Usize) = inner_ty.kind() { err.span_suggestion_verbose( obligation.cause.span.shrink_to_lo(), - "dereference this index", - '*', + "dereference this index", + '*', Applicability::MachineApplicable, ); } @@ -3415,7 +3444,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { { if let hir::Expr { kind: hir::ExprKind::Block(..), .. } = expr { let expr = expr.peel_blocks(); - let ty = typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx,)); + let ty = + typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)); let span = expr.span; if Some(span) != err.span.primary_span() { err.span_label( @@ -3437,7 +3467,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut type_diffs = vec![]; if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code && let Some(node_args) = typeck_results.node_args_opt(call_hir_id) - && let where_clauses = self.tcx.predicates_of(def_id).instantiate(self.tcx, node_args) + && let where_clauses = + self.tcx.predicates_of(def_id).instantiate(self.tcx, node_args) && let Some(where_pred) = where_clauses.predicates.get(*idx) { if let Some(where_pred) = where_pred.as_trait_clause() @@ -3447,32 +3478,34 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let failed_pred = self.instantiate_binder_with_fresh_vars( expr.span, LateBoundRegionConversionTime::FnCall, - failed_pred + failed_pred, ); - let zipped = - iter::zip(where_pred.trait_ref.args, failed_pred.trait_ref.args); + let zipped = iter::zip(where_pred.trait_ref.args, failed_pred.trait_ref.args); for (expected, actual) in zipped { self.probe(|_| { - match self - .at(&ObligationCause::misc(expr.span, body_id), param_env) - .eq(DefineOpaqueTypes::No, expected, actual) - { + match self.at(&ObligationCause::misc(expr.span, body_id), param_env).eq( + DefineOpaqueTypes::No, + expected, + actual, + ) { Ok(_) => (), // We ignore nested obligations here for now. Err(err) => type_diffs.push(err), } }) - }; + } } else if let Some(where_pred) = where_pred.as_projection_clause() && let Some(failed_pred) = failed_pred.to_opt_poly_projection_pred() && let Some(found) = failed_pred.skip_binder().term.ty() { - type_diffs = vec![ - Sorts(ty::error::ExpectedFound { - expected: Ty::new_alias(self.tcx,ty::Projection, where_pred.skip_binder().projection_ty), - found, - }), - ]; + type_diffs = vec![Sorts(ty::error::ExpectedFound { + expected: Ty::new_alias( + self.tcx, + ty::Projection, + where_pred.skip_binder().projection_ty, + ), + found, + })]; } } if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind @@ -3586,12 +3619,115 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { msg, sugg, Applicability::MaybeIncorrect, - SuggestionStyle::ShowAlways + SuggestionStyle::ShowAlways, ); } } } + fn look_for_iterator_item_mistakes( + &self, + assocs_in_this_method: &[Option<(Span, (DefId, Ty<'tcx>))>], + typeck_results: &TypeckResults<'tcx>, + type_diffs: &[TypeError<'tcx>], + param_env: ty::ParamEnv<'tcx>, + path_segment: &hir::PathSegment<'_>, + args: &[hir::Expr<'_>], + err: &mut Diagnostic, + ) { + let tcx = self.tcx; + // Special case for iterator chains, we look at potential failures of `Iterator::Item` + // not being `: Clone` and `Iterator::map` calls with spurious trailing `;`. + for entry in assocs_in_this_method { + let Some((_span, (def_id, ty))) = entry else { + continue; + }; + for diff in type_diffs { + let Sorts(expected_found) = diff else { + continue; + }; + if tcx.is_diagnostic_item(sym::IteratorItem, *def_id) + && path_segment.ident.name == sym::map + && self.can_eq(param_env, expected_found.found, *ty) + && let [arg] = args + && let hir::ExprKind::Closure(closure) = arg.kind + { + let body = tcx.hir().body(closure.body); + if let hir::ExprKind::Block(block, None) = body.value.kind + && let None = block.expr + && let [.., stmt] = block.stmts + && let hir::StmtKind::Semi(expr) = stmt.kind + // FIXME: actually check the expected vs found types, but right now + // the expected is a projection that we need to resolve. + // && let Some(tail_ty) = typeck_results.expr_ty_opt(expr) + && expected_found.found.is_unit() + { + err.span_suggestion_verbose( + expr.span.shrink_to_hi().with_hi(stmt.span.hi()), + "consider removing this semicolon", + String::new(), + Applicability::MachineApplicable, + ); + } + let expr = if let hir::ExprKind::Block(block, None) = body.value.kind + && let Some(expr) = block.expr + { + expr + } else { + body.value + }; + if let hir::ExprKind::MethodCall(path_segment, rcvr, [], span) = expr.kind + && path_segment.ident.name == sym::clone + && let Some(expr_ty) = typeck_results.expr_ty_opt(expr) + && let Some(rcvr_ty) = typeck_results.expr_ty_opt(rcvr) + && self.can_eq(param_env, expr_ty, rcvr_ty) + && let ty::Ref(_, ty, _) = expr_ty.kind() + { + err.span_label( + span, + format!( + "this method call is cloning the reference `{expr_ty}`, not \ + `{ty}` which doesn't implement `Clone`", + ), + ); + let ty::Param(..) = ty.kind() else { + continue; + }; + let hir = tcx.hir(); + let node = hir.get_by_def_id(hir.get_parent_item(expr.hir_id).def_id); + + let pred = ty::Binder::dummy(ty::TraitPredicate { + trait_ref: ty::TraitRef::from_lang_item( + tcx, + LangItem::Clone, + span, + [*ty], + ), + polarity: ty::ImplPolarity::Positive, + }); + let Some(generics) = node.generics() else { + continue; + }; + let Some(body_id) = node.body_id() else { + continue; + }; + suggest_restriction( + tcx, + hir.body_owner_def_id(body_id), + &generics, + &format!("type parameter `{ty}`"), + err, + node.fn_sig(), + None, + pred, + None, + ); + } + } + } + } + } + fn point_at_chain( &self, expr: &hir::Expr<'_>, @@ -3611,13 +3747,22 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut prev_ty = self.resolve_vars_if_possible( typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)), ); - while let hir::ExprKind::MethodCall(_path_segment, rcvr_expr, _args, span) = expr.kind { + while let hir::ExprKind::MethodCall(path_segment, rcvr_expr, args, span) = expr.kind { // Point at every method call in the chain with the resulting type. // vec![1, 2, 3].iter().map(mapper).sum<i32>() // ^^^^^^ ^^^^^^^^^^^ expr = rcvr_expr; let assocs_in_this_method = self.probe_assoc_types_at_expr(&type_diffs, span, prev_ty, expr.hir_id, param_env); + self.look_for_iterator_item_mistakes( + &assocs_in_this_method, + typeck_results, + &type_diffs, + param_env, + path_segment, + args, + err, + ); assocs.push(assocs_in_this_method); prev_ty = self.resolve_vars_if_possible( typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)), @@ -3638,9 +3783,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let hir::Node::Param(param) = parent { // ...and it is a an fn argument. let prev_ty = self.resolve_vars_if_possible( - typeck_results.node_type_opt(param.hir_id).unwrap_or(Ty::new_misc_error(tcx,)), + typeck_results + .node_type_opt(param.hir_id) + .unwrap_or(Ty::new_misc_error(tcx)), + ); + let assocs_in_this_method = self.probe_assoc_types_at_expr( + &type_diffs, + param.ty_span, + prev_ty, + param.hir_id, + param_env, ); - let assocs_in_this_method = self.probe_assoc_types_at_expr(&type_diffs, param.ty_span, prev_ty, param.hir_id, param_env); if assocs_in_this_method.iter().any(|a| a.is_some()) { assocs.push(assocs_in_this_method); print_root_expr = false; @@ -3651,7 +3804,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } // We want the type before deref coercions, otherwise we talk about `&[_]` // instead of `Vec<_>`. - if let Some(ty) = typeck_results.expr_ty_opt(expr) && print_root_expr { + if let Some(ty) = typeck_results.expr_ty_opt(expr) + && print_root_expr + { let ty = with_forced_trimmed_paths!(self.ty_to_string(ty)); // Point at the root expression // vec![1, 2, 3].iter().map(mapper).sum<i32>() @@ -3782,7 +3937,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // This corresponds to `<ExprTy as Iterator>::Item = _`. let projection = ty::Binder::dummy(ty::PredicateKind::Clause( ty::ClauseKind::Projection(ty::ProjectionPredicate { - projection_ty: self.tcx.mk_alias_ty(proj.def_id, args), + projection_ty: ty::AliasTy::new(self.tcx, proj.def_id, args), term: ty_var.into(), }), )); @@ -4104,7 +4259,9 @@ fn hint_missing_borrow<'tcx>( let mut span = arg.span.shrink_to_lo(); let mut left = found_refs.len() - expected_refs.len(); let mut ty = arg; - while let hir::TyKind::Ref(_, mut_ty) = &ty.kind && left > 0 { + while let hir::TyKind::Ref(_, mut_ty) = &ty.kind + && left > 0 + { span = span.with_hi(mut_ty.ty.span.lo()); ty = mut_ty.ty; left -= 1; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 8adfb27a3f4..640bd3fad7c 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -17,7 +17,7 @@ use crate::traits::{ use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::{ pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, - MultiSpan, Style, + MultiSpan, StashKey, Style, }; use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace, Res}; @@ -60,10 +60,7 @@ pub trait TypeErrCtxtExt<'tcx> { suggest_increasing_limit: bool, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> where - T: fmt::Display - + TypeFoldable<TyCtxt<'tcx>> - + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, - <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug; + T: fmt::Display + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>; fn report_overflow_error<T>( &self, @@ -73,10 +70,7 @@ pub trait TypeErrCtxtExt<'tcx> { mutate: impl FnOnce(&mut Diagnostic), ) -> ! where - T: fmt::Display - + TypeFoldable<TyCtxt<'tcx>> - + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, - <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug; + T: fmt::Display + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>; fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed; @@ -227,10 +221,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { mutate: impl FnOnce(&mut Diagnostic), ) -> ! where - T: fmt::Display - + TypeFoldable<TyCtxt<'tcx>> - + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, - <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug, + T: fmt::Display + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>, { let mut err = self.build_overflow_error(predicate, span, suggest_increasing_limit); mutate(&mut err); @@ -247,10 +238,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { suggest_increasing_limit: bool, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> where - T: fmt::Display - + TypeFoldable<TyCtxt<'tcx>> - + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, - <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug, + T: fmt::Display + TypeFoldable<TyCtxt<'tcx>> + Print<'tcx, FmtPrinter<'tcx, 'tcx>>, { let predicate = self.resolve_vars_if_possible(predicate.clone()); let mut pred_str = predicate.to_string(); @@ -2049,14 +2037,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // begin with in those cases. if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) { if let None = self.tainted_by_errors() { - self.emit_inference_failure_err( + let err = self.emit_inference_failure_err( obligation.cause.body_id, span, trait_ref.self_ty().skip_binder().into(), ErrorCode::E0282, false, - ) - .emit(); + ); + err.stash(span, StashKey::MaybeForgetReturn); } return; } @@ -2153,14 +2141,16 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } if let Some(ty::GenericArgKind::Type(_)) = subst.map(|subst| subst.unpack()) - && let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) + && let Some(body_id) = + self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) { let mut expr_finder = FindExprBySpan::new(span); expr_finder.visit_expr(&self.tcx.hir().body(body_id).value); if let Some(hir::Expr { - kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)), .. } - ) = expr_finder.result + kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)), + .. + }) = expr_finder.result && let [ .., trait_path_segment @ hir::PathSegment { @@ -2171,7 +2161,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ident: assoc_item_name, res: Res::Def(_, item_id), .. - } + }, ] = path.segments && data.trait_ref.def_id == *trait_id && self.tcx.trait_of_item(*item_id) == Some(*trait_id) @@ -2239,23 +2229,26 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { "/* self type */".to_string(), ) }; - let mut suggestions = vec![( - path.span.shrink_to_lo(), - format!("<{self_type} as "), - )]; + let mut suggestions = + vec![(path.span.shrink_to_lo(), format!("<{self_type} as "))]; if let Some(generic_arg) = trait_path_segment.args { - let between_span = trait_path_segment.ident.span.between(generic_arg.span_ext); + let between_span = + trait_path_segment.ident.span.between(generic_arg.span_ext); // get rid of :: between Trait and <type> // must be '::' between them, otherwise the parser won't accept the code - suggestions.push((between_span, "".to_string(),)); - suggestions.push((generic_arg.span_ext.shrink_to_hi(), ">".to_string())); + suggestions.push((between_span, "".to_string())); + suggestions + .push((generic_arg.span_ext.shrink_to_hi(), ">".to_string())); } else { - suggestions.push((trait_path_segment.ident.span.shrink_to_hi(), ">".to_string())); + suggestions.push(( + trait_path_segment.ident.span.shrink_to_hi(), + ">".to_string(), + )); } err.multipart_suggestion( message, suggestions, - Applicability::MaybeIncorrect + Applicability::MaybeIncorrect, ); } } @@ -2965,8 +2958,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); } else if !self.same_type_modulo_infer(given_ty, expected_ty) { // Print type mismatch - let (expected_args, given_args) = - self.cmp(given_ty, expected_ty); + let (expected_args, given_args) = self.cmp(given_ty, expected_ty); err.note_expected_found( &"a closure with arguments", expected_args, diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index da357dac415..55b5604b16b 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -6,7 +6,6 @@ use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::traits::ProjectionCacheKey; use rustc_infer::traits::{PolyTraitObligation, SelectionError, TraitEngine}; use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::GenericArgsRef; @@ -626,27 +625,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } ty::PredicateKind::Ambiguous => ProcessResult::Unchanged, - ty::PredicateKind::AliasRelate(..) - if matches!(self.selcx.infcx.defining_use_anchor, DefiningAnchor::Bubble) => - { - ProcessResult::Unchanged + ty::PredicateKind::AliasRelate(..) => { + bug!("AliasRelate is only used for new solver") } - ty::PredicateKind::AliasRelate(a, b, relate) => match relate { - ty::AliasRelationDirection::Equate => match self - .selcx - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(DefineOpaqueTypes::Yes, a, b) - { - Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())), - Err(_) => ProcessResult::Error(FulfillmentErrorCode::CodeSelectionError( - SelectionError::Unimplemented, - )), - }, - ty::AliasRelationDirection::Subtype => { - bug!("AliasRelate with subtyping is only used for new solver") - } - }, ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq( DefineOpaqueTypes::No, diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 5823b4508d9..2d05f934393 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -584,10 +584,9 @@ fn virtual_call_violation_for_method<'tcx>( // would already have reported an error at the definition of the // auto trait. if pred_trait_ref.args.len() != 1 { - tcx.sess.diagnostic().delay_span_bug( - span, - "auto traits cannot have generic parameters", - ); + tcx.sess + .diagnostic() + .delay_span_bug(span, "auto traits cannot have generic parameters"); } return false; } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 73c2ff3c536..b923926d28d 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1233,7 +1233,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( let projected_term = selcx.infcx.resolve_vars_if_possible(projected_term); - let result = if projected_term.has_projections() { + let mut result = if projected_term.has_projections() { let mut normalizer = AssocTypeNormalizer::new( selcx, param_env, @@ -1243,14 +1243,14 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( ); let normalized_ty = normalizer.fold(projected_term); - let mut deduped = SsoHashSet::with_capacity(projected_obligations.len()); - projected_obligations.retain(|obligation| deduped.insert(obligation.clone())); - Normalized { value: normalized_ty, obligations: projected_obligations } } else { Normalized { value: projected_term, obligations: projected_obligations } }; + let mut deduped = SsoHashSet::with_capacity(result.obligations.len()); + result.obligations.retain(|obligation| deduped.insert(obligation.clone())); + if use_cache { infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone()); } @@ -2072,7 +2072,7 @@ fn confirm_generator_candidate<'cx, 'tcx>( }; ty::ProjectionPredicate { - projection_ty: tcx.mk_alias_ty(obligation.predicate.def_id, trait_ref.args), + projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args), term: ty.into(), } }); @@ -2116,7 +2116,7 @@ fn confirm_future_candidate<'cx, 'tcx>( debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output); ty::ProjectionPredicate { - projection_ty: tcx.mk_alias_ty(obligation.predicate.def_id, trait_ref.args), + projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args), term: return_ty.into(), } }); @@ -2172,7 +2172,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>( }; let predicate = - ty::ProjectionPredicate { projection_ty: tcx.mk_alias_ty(item_def_id, args), term }; + ty::ProjectionPredicate { projection_ty: ty::AliasTy::new(tcx, item_def_id, args), term }; confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) .with_addl_obligations(obligations) @@ -2245,7 +2245,7 @@ fn confirm_callable_candidate<'cx, 'tcx>( flag, ) .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate { - projection_ty: tcx.mk_alias_ty(fn_once_output_def_id, trait_ref.args), + projection_ty: ty::AliasTy::new(tcx, fn_once_output_def_id, trait_ref.args), term: ret_type.into(), }); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index 9d7933e23a8..a5ccf62608e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -157,10 +157,18 @@ where } let mut region_constraints = QueryRegionConstraints::default(); - let (output, error_info, mut obligations, _) = - Q::fully_perform_into(self, infcx, &mut region_constraints).map_err(|_| { - infcx.tcx.sess.delay_span_bug(span, format!("error performing {self:?}")) - })?; + let (output, error_info, mut obligations) = + Q::fully_perform_into(self, infcx, &mut region_constraints) + .map_err(|_| { + infcx.tcx.sess.delay_span_bug(span, format!("error performing {self:?}")) + }) + .and_then(|(output, error_info, obligations, certainty)| match certainty { + Certainty::Proven => Ok((output, error_info, obligations)), + Certainty::Ambiguous => Err(infcx + .tcx + .sess + .delay_span_bug(span, format!("ambiguity performing {self:?}"))), + })?; // Typically, instantiating NLL query results does not // create obligations. However, in some cases there diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index bead8758ad6..a8001577bcd 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -492,7 +492,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // this trait and type. } ty::Param(..) - | ty::Alias(ty::Projection | ty::Inherent, ..) + | ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) | ty::Placeholder(..) | ty::Bound(..) => { // In these cases, we don't know what the actual @@ -536,20 +536,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); } - ty::Alias(_, _) - if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(..))) => - { - // We do not generate an auto impl candidate for `impl Trait`s which already - // reference our auto trait. - // - // For example during candidate assembly for `impl Send: Send`, we don't have - // to look at the constituent types for this opaque types to figure out that this - // trivially holds. - // - // Note that this is only sound as projection candidates of opaque types - // are always applicable for auto traits. + ty::Alias(ty::Opaque, _) => { + if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(..))) { + // We do not generate an auto impl candidate for `impl Trait`s which already + // reference our auto trait. + // + // For example during candidate assembly for `impl Send: Send`, we don't have + // to look at the constituent types for this opaque types to figure out that this + // trivially holds. + // + // Note that this is only sound as projection candidates of opaque types + // are always applicable for auto traits. + } else if self.infcx.intercrate { + // We do not emit auto trait candidates for opaque types in coherence. + // Doing so can result in weird dependency cycles. + candidates.ambiguous = true; + } else { + candidates.vec.push(AutoImplCandidate) + } } - ty::Alias(_, _) => candidates.vec.push(AutoImplCandidate), ty::Bool | ty::Char @@ -699,7 +704,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let ty = traits::normalize_projection_type( self, param_env, - tcx.mk_alias_ty(tcx.lang_items().deref_target()?, trait_ref.args), + ty::AliasTy::new(tcx, tcx.lang_items().deref_target()?, trait_ref.args), cause.clone(), 0, // We're *intentionally* throwing these away, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 8871de194a6..940ceca50d2 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -38,7 +38,6 @@ use rustc_infer::traits::TraitObligation; use rustc_middle::dep_graph::dep_kinds; use rustc_middle::dep_graph::DepNodeIndex; use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::_match::MatchAgainstFreshVars; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::fold::BottomUpFolder; @@ -860,7 +859,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { subobligations, ); if let Ok(eval_rslt) = res - && (eval_rslt == EvaluatedToOk || eval_rslt == EvaluatedToOkModuloRegions) + && (eval_rslt == EvaluatedToOk + || eval_rslt == EvaluatedToOkModuloRegions) && let Some(key) = ProjectionCacheKey::from_poly_projection_predicate( self, data, @@ -1004,27 +1004,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } } - ty::PredicateKind::AliasRelate(..) - if matches!(self.infcx.defining_use_anchor, DefiningAnchor::Bubble) => - { - Ok(EvaluatedToAmbig) + ty::PredicateKind::AliasRelate(..) => { + bug!("AliasRelate is only used for new solver") } - ty::PredicateKind::AliasRelate(a, b, relate) => match relate { - ty::AliasRelationDirection::Equate => match self - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(DefineOpaqueTypes::Yes, a, b) - { - Ok(inf_ok) => self.evaluate_predicates_recursively( - previous_stack, - inf_ok.into_obligations(), - ), - Err(_) => Ok(EvaluatedToErr), - }, - ty::AliasRelationDirection::Subtype => { - bug!("AliasRelate subtyping is only used for new solver") - } - }, ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig), ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { match self.infcx.at(&obligation.cause, obligation.param_env).eq( diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index a76272e9d09..4ef2027d7e8 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -326,7 +326,8 @@ pub fn check_args_compatible<'tcx>( if let Some(parent) = generics.parent && let parent_generics = tcx.generics_of(parent) - && !check_args_compatible_inner(tcx, parent_generics, parent_args) { + && !check_args_compatible_inner(tcx, parent_generics, parent_args) + { return false; } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 060df772613..e7e4ee983fb 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -254,7 +254,8 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( // projection coming from another associated type. See // `tests/ui/associated-types/point-at-type-on-obligation-failure.rs` and // `traits-assoc-type-in-supertrait-bad.rs`. - if let Some(ty::Alias(ty::Projection, projection_ty)) = proj.term.ty().map(|ty| ty.kind()) + if let Some(ty::Alias(ty::Projection, projection_ty)) = + proj.term.ty().map(|ty| ty.kind()) && let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.def_id) && let Some(impl_item_span) = items @@ -270,8 +271,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( // can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`. debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred); if let ty::Alias(ty::Projection, ty::AliasTy { def_id, .. }) = *pred.self_ty().kind() - && let Some(&impl_item_id) = - tcx.impl_item_implementor_ids(impl_def_id).get(&def_id) + && let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&def_id) && let Some(impl_item_span) = items .iter() .find(|item| item.id.owner_id.to_def_id() == impl_item_id) diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 780f7ea426f..3e140793b5a 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -192,7 +192,8 @@ fn associated_types_for_impl_traits_in_associated_fn( if let hir::TyKind::OpaqueDef(item_id, _, _) = ty.kind && self.rpits.insert(item_id.owner_id.def_id) { - let opaque_item = self.tcx.hir().expect_item(item_id.owner_id.def_id).expect_opaque_ty(); + let opaque_item = + self.tcx.hir().expect_item(item_id.owner_id.def_id).expect_opaque_ty(); for bound in opaque_item.bounds { intravisit::walk_param_bound(self, bound); } diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index ec2e0daaf88..0ca7d43f6d5 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -50,73 +50,76 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' let mut impl_spans = impl_spans(tcx, def_id); tcx.arena.alloc_from_iter(tys.into_iter().map(|ty| (ty, impl_spans.next().unwrap()))) } - DefKind::AssocTy if let Some(data) = tcx.opt_rpitit_info(def_id.to_def_id()) => match data { - ty::ImplTraitInTraitData::Trait { fn_def_id, .. } => { - // We need to remap all of the late-bound lifetimes in theassumed wf types - // of the fn (which are represented as ReFree) to the early-bound lifetimes - // of the RPITIT (which are represented by ReEarlyBound owned by the opaque). - // Luckily, this is very easy to do because we already have that mapping - // stored in the HIR of this RPITIT. - // - // Side-note: We don't really need to do this remapping for early-bound - // lifetimes because they're already "linked" by the bidirectional outlives - // predicates we insert in the `explicit_predicates_of` query for RPITITs. - let mut mapping = FxHashMap::default(); - let generics = tcx.generics_of(def_id); + DefKind::AssocTy if let Some(data) = tcx.opt_rpitit_info(def_id.to_def_id()) => { + match data { + ty::ImplTraitInTraitData::Trait { fn_def_id, .. } => { + // We need to remap all of the late-bound lifetimes in theassumed wf types + // of the fn (which are represented as ReFree) to the early-bound lifetimes + // of the RPITIT (which are represented by ReEarlyBound owned by the opaque). + // Luckily, this is very easy to do because we already have that mapping + // stored in the HIR of this RPITIT. + // + // Side-note: We don't really need to do this remapping for early-bound + // lifetimes because they're already "linked" by the bidirectional outlives + // predicates we insert in the `explicit_predicates_of` query for RPITITs. + let mut mapping = FxHashMap::default(); + let generics = tcx.generics_of(def_id); - // For each captured opaque lifetime, if it's late-bound (`ReFree` in this case, - // since it has been liberated), map it back to the early-bound lifetime of - // the GAT. Since RPITITs also have all of the fn's generics, we slice only - // the end of the list corresponding to the opaque's generics. - for param in &generics.params[tcx.generics_of(fn_def_id).params.len()..] { - let orig_lt = tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local()); - if matches!(*orig_lt, ty::ReFree(..)) { - mapping.insert( - orig_lt, - ty::Region::new_early_bound( - tcx, - ty::EarlyBoundRegion { - def_id: param.def_id, - index: param.index, - name: param.name, - }, - ), - ); + // For each captured opaque lifetime, if it's late-bound (`ReFree` in this case, + // since it has been liberated), map it back to the early-bound lifetime of + // the GAT. Since RPITITs also have all of the fn's generics, we slice only + // the end of the list corresponding to the opaque's generics. + for param in &generics.params[tcx.generics_of(fn_def_id).params.len()..] { + let orig_lt = + tcx.map_rpit_lifetime_to_fn_lifetime(param.def_id.expect_local()); + if matches!(*orig_lt, ty::ReFree(..)) { + mapping.insert( + orig_lt, + ty::Region::new_early_bound( + tcx, + ty::EarlyBoundRegion { + def_id: param.def_id, + index: param.index, + name: param.name, + }, + ), + ); + } } + // FIXME: This could use a real folder, I guess. + let remapped_wf_tys = tcx.fold_regions( + tcx.assumed_wf_types(fn_def_id.expect_local()).to_vec(), + |region, _| { + // If `region` is a `ReFree` that is captured by the + // opaque, remap it to its corresponding the early- + // bound region. + if let Some(remapped_region) = mapping.get(®ion) { + *remapped_region + } else { + region + } + }, + ); + tcx.arena.alloc_from_iter(remapped_wf_tys) + } + // Assumed wf types for RPITITs in an impl just inherit (and instantiate) + // the assumed wf types of the trait's RPITIT GAT. + ty::ImplTraitInTraitData::Impl { .. } => { + let impl_def_id = tcx.local_parent(def_id); + let rpitit_def_id = tcx.associated_item(def_id).trait_item_def_id.unwrap(); + let args = ty::GenericArgs::identity_for_item(tcx, def_id).rebase_onto( + tcx, + impl_def_id.to_def_id(), + tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity().args, + ); + tcx.arena.alloc_from_iter( + ty::EarlyBinder::bind(tcx.assumed_wf_types_for_rpitit(rpitit_def_id)) + .iter_instantiated_copied(tcx, args) + .chain(tcx.assumed_wf_types(impl_def_id).into_iter().copied()), + ) } - // FIXME: This could use a real folder, I guess. - let remapped_wf_tys = tcx.fold_regions( - tcx.assumed_wf_types(fn_def_id.expect_local()).to_vec(), - |region, _| { - // If `region` is a `ReFree` that is captured by the - // opaque, remap it to its corresponding the early- - // bound region. - if let Some(remapped_region) = mapping.get(®ion) { - *remapped_region - } else { - region - } - }, - ); - tcx.arena.alloc_from_iter(remapped_wf_tys) - } - // Assumed wf types for RPITITs in an impl just inherit (and instantiate) - // the assumed wf types of the trait's RPITIT GAT. - ty::ImplTraitInTraitData::Impl { .. } => { - let impl_def_id = tcx.local_parent(def_id); - let rpitit_def_id = tcx.associated_item(def_id).trait_item_def_id.unwrap(); - let args = ty::GenericArgs::identity_for_item(tcx, def_id).rebase_onto( - tcx, - impl_def_id.to_def_id(), - tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity().args, - ); - tcx.arena.alloc_from_iter( - ty::EarlyBinder::bind(tcx.assumed_wf_types_for_rpitit(rpitit_def_id)) - .iter_instantiated_copied(tcx, args) - .chain(tcx.assumed_wf_types(impl_def_id).into_iter().copied()), - ) } - }, + } DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.local_parent(def_id)), DefKind::OpaqueTy => match tcx.def_kind(tcx.local_parent(def_id)) { DefKind::TyAlias => ty::List::empty(), diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 91f1c21310e..2fbf87800bb 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -188,10 +188,7 @@ fn resolve_associated_item<'tcx>( && trait_item_id != leaf_def.item.def_id && let Some(leaf_def_item) = leaf_def.item.def_id.as_local() { - tcx.compare_impl_const(( - leaf_def_item, - trait_item_id, - ))?; + tcx.compare_impl_const((leaf_def_item, trait_item_id))?; } Some(ty::Instance::new(leaf_def.item.def_id, args)) diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 8132742d1df..cc6c8478785 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -170,29 +170,27 @@ fn layout_of_uncached<'tcx>( // fall back to structurally deducing metadata. && !pointee.references_error() { - let pointee_metadata = Ty::new_projection(tcx,metadata_def_id, [pointee]); - let metadata_ty = match tcx.try_normalize_erasing_regions( - param_env, - pointee_metadata, - ) { - Ok(metadata_ty) => metadata_ty, - Err(mut err) => { - // Usually `<Ty as Pointee>::Metadata` can't be normalized because - // its struct tail cannot be normalized either, so try to get a - // more descriptive layout error here, which will lead to less confusing - // diagnostics. - match tcx.try_normalize_erasing_regions( - param_env, - tcx.struct_tail_without_normalization(pointee), - ) { - Ok(_) => {}, - Err(better_err) => { - err = better_err; + let pointee_metadata = Ty::new_projection(tcx, metadata_def_id, [pointee]); + let metadata_ty = + match tcx.try_normalize_erasing_regions(param_env, pointee_metadata) { + Ok(metadata_ty) => metadata_ty, + Err(mut err) => { + // Usually `<Ty as Pointee>::Metadata` can't be normalized because + // its struct tail cannot be normalized either, so try to get a + // more descriptive layout error here, which will lead to less confusing + // diagnostics. + match tcx.try_normalize_erasing_regions( + param_env, + tcx.struct_tail_without_normalization(pointee), + ) { + Ok(_) => {} + Err(better_err) => { + err = better_err; + } } + return Err(error(cx, LayoutError::NormalizationFailure(pointee, err))); } - return Err(error(cx, LayoutError::NormalizationFailure(pointee, err))); - }, - }; + }; let metadata_layout = cx.layout_of(metadata_ty)?; // If the metadata is a 1-zst, then the pointer is thin. diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 147b600f7ba..1a9de150041 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -5,6 +5,9 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] +#![cfg_attr(not(bootstrap), allow(internal_features))] #![feature(assert_matches)] #![feature(iterator_try_collect)] #![feature(let_chains)] diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index c22c67bd907..e1ec159921e 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -184,9 +184,10 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> { if let ty::Alias(ty::Projection, unshifted_alias_ty) = *ty.kind() - && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. } - | ty::ImplTraitInTraitData::Impl { fn_def_id, .. }) - = self.tcx.opt_rpitit_info(unshifted_alias_ty.def_id) + && let Some( + ty::ImplTraitInTraitData::Trait { fn_def_id, .. } + | ty::ImplTraitInTraitData::Impl { fn_def_id, .. }, + ) = self.tcx.opt_rpitit_info(unshifted_alias_ty.def_id) && fn_def_id == self.fn_def_id && self.seen.insert(unshifted_alias_ty.def_id) { @@ -202,7 +203,11 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { "we shouldn't walk non-predicate binders with `impl Trait`...", ); } - ty::Region::new_late_bound(self.tcx, index.shifted_out_to_binder(self.depth), bv) + ty::Region::new_late_bound( + self.tcx, + index.shifted_out_to_binder(self.depth), + bv, + ) } else { re } @@ -211,12 +216,21 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { // If we're lowering to associated item, install the opaque type which is just // the `type_of` of the trait's associated item. If we're using the old lowering // strategy, then just reinterpret the associated type like an opaque :^) - let default_ty = self.tcx.type_of(shifted_alias_ty.def_id).instantiate(self.tcx, shifted_alias_ty.args); - - self.predicates.push(ty::Binder::bind_with_vars( - ty::ProjectionPredicate { projection_ty: shifted_alias_ty, term: default_ty.into() }, - self.bound_vars, - ).to_predicate(self.tcx)); + let default_ty = self + .tcx + .type_of(shifted_alias_ty.def_id) + .instantiate(self.tcx, shifted_alias_ty.args); + + self.predicates.push( + ty::Binder::bind_with_vars( + ty::ProjectionPredicate { + projection_ty: shifted_alias_ty, + term: default_ty.into(), + }, + self.bound_vars, + ) + .to_predicate(self.tcx), + ); // We walk the *un-shifted* alias ty, because we're tracking the de bruijn // binder depth, and if we were to walk `shifted_alias_ty` instead, we'd diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 5df068de1f8..9f8d9f02ec2 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -1,7 +1,9 @@ #![feature(associated_type_defaults)] #![feature(fmt_helpers_for_derive)] +#![feature(get_mut_unchecked)] #![feature(min_specialization)] #![feature(never_type)] +#![feature(new_uninit)] #![feature(rustc_attrs)] #![feature(unwrap_infallible)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_type_ir/src/structural_impls.rs b/compiler/rustc_type_ir/src/structural_impls.rs index f36f4ec8697..08af96ea15f 100644 --- a/compiler/rustc_type_ir/src/structural_impls.rs +++ b/compiler/rustc_type_ir/src/structural_impls.rs @@ -5,12 +5,12 @@ use crate::fold::{FallibleTypeFolder, TypeFoldable}; use crate::visit::{TypeVisitable, TypeVisitor}; use crate::{ConstKind, FloatTy, InferTy, IntTy, Interner, UintTy, UniverseIndex}; -use rustc_data_structures::functor::IdFunctor; use rustc_data_structures::sync::Lrc; use rustc_index::{Idx, IndexVec}; use core::fmt; use std::marker::PhantomData; +use std::mem; use std::ops::ControlFlow; /////////////////////////////////////////////////////////////////////////// @@ -108,8 +108,39 @@ impl<I: Interner, T: TypeVisitable<I>, E: TypeVisitable<I>> TypeVisitable<I> for } impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Lrc<T> { - fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { - self.try_map_id(|value| value.try_fold_with(folder)) + fn try_fold_with<F: FallibleTypeFolder<I>>(mut self, folder: &mut F) -> Result<Self, F::Error> { + // We merely want to replace the contained `T`, if at all possible, + // so that we don't needlessly allocate a new `Lrc` or indeed clone + // the contained type. + unsafe { + // First step is to ensure that we have a unique reference to + // the contained type, which `Lrc::make_mut` will accomplish (by + // allocating a new `Lrc` and cloning the `T` only if required). + // This is done *before* casting to `Lrc<ManuallyDrop<T>>` so that + // panicking during `make_mut` does not leak the `T`. + Lrc::make_mut(&mut self); + + // Casting to `Lrc<ManuallyDrop<T>>` is safe because `ManuallyDrop` + // is `repr(transparent)`. + let ptr = Lrc::into_raw(self).cast::<mem::ManuallyDrop<T>>(); + let mut unique = Lrc::from_raw(ptr); + + // Call to `Lrc::make_mut` above guarantees that `unique` is the + // sole reference to the contained value, so we can avoid doing + // a checked `get_mut` here. + let slot = Lrc::get_mut_unchecked(&mut unique); + + // Semantically move the contained type out from `unique`, fold + // it, then move the folded value back into `unique`. Should + // folding fail, `ManuallyDrop` ensures that the "moved-out" + // value is not re-dropped. + let owned = mem::ManuallyDrop::take(slot); + let folded = owned.try_fold_with(folder)?; + *slot = mem::ManuallyDrop::new(folded); + + // Cast back to `Lrc<T>`. + Ok(Lrc::from_raw(Lrc::into_raw(unique).cast())) + } } } @@ -120,8 +151,9 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Lrc<T> { } impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Box<T> { - fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { - self.try_map_id(|value| value.try_fold_with(folder)) + fn try_fold_with<F: FallibleTypeFolder<I>>(mut self, folder: &mut F) -> Result<Self, F::Error> { + *self = (*self).try_fold_with(folder)?; + Ok(self) } } @@ -133,7 +165,7 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<T> { impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Vec<T> { fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { - self.try_map_id(|t| t.try_fold_with(folder)) + self.into_iter().map(|t| t.try_fold_with(folder)).collect() } } @@ -153,9 +185,15 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for &[T] { } } +impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<[T]> { + fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> { + self.iter().try_for_each(|t| t.visit_with(visitor)) + } +} + impl<I: Interner, T: TypeFoldable<I>, Ix: Idx> TypeFoldable<I> for IndexVec<Ix, T> { fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> { - self.try_map_id(|x| x.try_fold_with(folder)) + self.raw.try_fold_with(folder).map(IndexVec::from_raw) } } diff --git a/compiler/stable_mir/src/error.rs b/compiler/stable_mir/src/error.rs new file mode 100644 index 00000000000..12ac8f1ca65 --- /dev/null +++ b/compiler/stable_mir/src/error.rs @@ -0,0 +1,69 @@ +//! When things go wrong, we need some error handling. +//! There are a few different types of errors in StableMIR: +//! +//! - [CompilerError]: This represents errors that can be raised when invoking the compiler. +//! - [Error]: Generic error that represents the reason why a request that could not be fulfilled. + +use std::fmt::{Debug, Display, Formatter}; +use std::{error, fmt}; + +/// An error type used to represent an error that has already been reported by the compiler. +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum CompilerError<T> { + /// Internal compiler error (I.e.: Compiler crashed). + ICE, + /// Compilation failed. + CompilationFailed, + /// Compilation was interrupted. + Interrupted(T), + /// Compilation skipped. This happens when users invoke rustc to retrieve information such as + /// --version. + Skipped, +} + +/// A generic error to represent an API request that cannot be fulfilled. +#[derive(Debug)] +pub struct Error(String); + +impl Error { + pub(crate) fn new(msg: String) -> Self { + Self(msg) + } +} + +impl Display for Error { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(&self.0, f) + } +} + +impl<T> Display for CompilerError<T> +where + T: Display, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + CompilerError::ICE => write!(f, "Internal Compiler Error"), + CompilerError::CompilationFailed => write!(f, "Compilation Failed"), + CompilerError::Interrupted(reason) => write!(f, "Compilation Interrupted: {reason}"), + CompilerError::Skipped => write!(f, "Compilation Skipped"), + } + } +} + +impl<T> Debug for CompilerError<T> +where + T: Debug, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + CompilerError::ICE => write!(f, "Internal Compiler Error"), + CompilerError::CompilationFailed => write!(f, "Compilation Failed"), + CompilerError::Interrupted(reason) => write!(f, "Compilation Interrupted: {reason:?}"), + CompilerError::Skipped => write!(f, "Compilation Skipped"), + } + } +} + +impl error::Error for Error {} +impl<T> error::Error for CompilerError<T> where T: Display + Debug {} diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index 79f598b6faa..59af3f64ad3 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -17,22 +17,29 @@ //! The goal is to eventually be published on //! [crates.io](https://crates.io). +use crate::mir::mono::InstanceDef; +use crate::mir::Body; use std::cell::Cell; use std::fmt; use std::fmt::Debug; use self::ty::{ - GenericPredicates, Generics, ImplDef, ImplTrait, Span, TraitDecl, TraitDef, Ty, TyKind, + GenericPredicates, Generics, ImplDef, ImplTrait, IndexedVal, LineInfo, Span, TraitDecl, + TraitDef, Ty, TyKind, }; #[macro_use] extern crate scoped_tls; +pub mod error; pub mod fold; pub mod mir; pub mod ty; pub mod visitor; +pub use error::*; +use mir::mono::Instance; + /// Use String for now but we should replace it. pub type Symbol = String; @@ -41,7 +48,7 @@ pub type CrateNum = usize; /// A unique identification number for each item accessible for the current compilation unit. #[derive(Clone, Copy, PartialEq, Eq)] -pub struct DefId(pub usize); +pub struct DefId(usize); impl Debug for DefId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -52,9 +59,28 @@ impl Debug for DefId { } } +impl IndexedVal for DefId { + fn to_val(index: usize) -> Self { + DefId(index) + } + + fn to_index(&self) -> usize { + self.0 + } +} + /// A unique identification number for each provenance #[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct AllocId(pub usize); +pub struct AllocId(usize); + +impl IndexedVal for AllocId { + fn to_val(index: usize) -> Self { + AllocId(index) + } + fn to_index(&self) -> usize { + self.0 + } +} /// A list of crate items. pub type CrateItems = Vec<CrateItem>; @@ -65,20 +91,6 @@ pub type TraitDecls = Vec<TraitDef>; /// A list of impl trait decls. pub type ImplTraitDecls = Vec<ImplDef>; -/// An error type used to represent an error that has already been reported by the compiler. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum CompilerError<T> { - /// Internal compiler error (I.e.: Compiler crashed). - ICE, - /// Compilation failed. - CompilationFailed, - /// Compilation was interrupted. - Interrupted(T), - /// Compilation skipped. This happens when users invoke rustc to retrieve information such as - /// --version. - Skipped, -} - /// Holds information about a crate. #[derive(Clone, PartialEq, Eq, Debug)] pub struct Crate { @@ -88,11 +100,12 @@ pub struct Crate { } pub type DefKind = Opaque; +pub type Filename = Opaque; /// Holds information about an item in the crate. /// For now, it only stores the item DefId. Use functions inside `rustc_internal` module to /// use this item. -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct CrateItem(pub DefId); impl CrateItem { @@ -111,6 +124,10 @@ impl CrateItem { pub fn kind(&self) -> DefKind { with(|cx| cx.def_kind(self.0)) } + + pub fn requires_monomorphization(&self) -> bool { + with(|cx| cx.requires_monomorphization(self.0)) + } } /// Return the function where execution starts if the current @@ -176,13 +193,19 @@ pub trait Context { /// Find a crate with the given name. fn find_crates(&self, name: &str) -> Vec<Crate>; - /// Prints the name of given `DefId` + /// Returns the name of given `DefId` fn name_of_def_id(&self, def_id: DefId) -> String; - /// Prints a human readable form of `Span` - fn print_span(&self, span: Span) -> String; + /// Returns printable, human readable form of `Span` + fn span_to_string(&self, span: Span) -> String; + + /// Return filename from given `Span`, for diagnostic purposes + fn get_filename(&self, span: &Span) -> Filename; + + /// Return lines corresponding to this `Span` + fn get_lines(&self, span: &Span) -> LineInfo; - /// Prints the kind of given `DefId` + /// Returns the `kind` of given `DefId` fn def_kind(&mut self, def_id: DefId) -> DefKind; /// `Span` of an item @@ -193,6 +216,23 @@ pub trait Context { /// Create a new `Ty` from scratch without information from rustc. fn mk_ty(&mut self, kind: TyKind) -> Ty; + + /// Get the body of an Instance. + /// FIXME: Monomorphize the body. + fn instance_body(&mut self, instance: InstanceDef) -> Body; + + /// Get the instance type with generic substitutions applied and lifetimes erased. + fn instance_ty(&mut self, instance: InstanceDef) -> Ty; + + /// Get the instance. + fn instance_def_id(&mut self, instance: InstanceDef) -> DefId; + + /// Convert a non-generic crate item into an instance. + /// This function will panic if the item is generic. + fn mono_instance(&mut self, item: CrateItem) -> Instance; + + /// Item requires monomorphization. + fn requires_monomorphization(&self, def_id: DefId) -> bool; } // A thread local variable that stores a pointer to the tables mapping between TyCtxt diff --git a/compiler/stable_mir/src/mir.rs b/compiler/stable_mir/src/mir.rs index a9dbc3463f8..3138bb1ec83 100644 --- a/compiler/stable_mir/src/mir.rs +++ b/compiler/stable_mir/src/mir.rs @@ -1,3 +1,4 @@ mod body; +pub mod mono; pub use body::*; diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs new file mode 100644 index 00000000000..d8e8ccb0454 --- /dev/null +++ b/compiler/stable_mir/src/mir/mono.rs @@ -0,0 +1,89 @@ +use crate::mir::Body; +use crate::ty::{IndexedVal, Ty}; +use crate::{with, CrateItem, DefId, Error, Opaque}; +use std::fmt::Debug; + +#[derive(Clone, Debug)] +pub enum MonoItem { + Fn(Instance), + Static(StaticDef), + GlobalAsm(Opaque), +} + +#[derive(Copy, Clone, Debug)] +pub struct Instance { + /// The type of instance. + pub kind: InstanceKind, + /// An ID used to get the instance definition from the compiler. + /// Do not use this field directly. + pub def: InstanceDef, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum InstanceKind { + /// A user defined item. + Item, + /// A compiler intrinsic function. + Intrinsic, + /// A virtual function definition stored in a VTable. + Virtual, + /// A compiler generated shim. + Shim, +} + +impl Instance { + /// Get the body of an Instance. The body will be eagerly monomorphized. + pub fn body(&self) -> Body { + with(|context| context.instance_body(self.def)) + } + + /// Get the instance type with generic substitutions applied and lifetimes erased. + pub fn ty(&self) -> Ty { + with(|context| context.instance_ty(self.def)) + } +} + +/// Try to convert a crate item into an instance. +/// The item cannot be generic in order to be converted into an instance. +impl TryFrom<CrateItem> for Instance { + type Error = crate::Error; + + fn try_from(item: CrateItem) -> Result<Self, Self::Error> { + with(|context| { + if !context.requires_monomorphization(item.0) { + Ok(context.mono_instance(item)) + } else { + Err(Error::new("Item requires monomorphization".to_string())) + } + }) + } +} + +/// Try to convert an instance into a crate item. +/// Only user defined instances can be converted. +impl TryFrom<Instance> for CrateItem { + type Error = crate::Error; + + fn try_from(value: Instance) -> Result<Self, Self::Error> { + if value.kind == InstanceKind::Item { + Ok(CrateItem(with(|context| context.instance_def_id(value.def)))) + } else { + Err(Error::new(format!("Item kind `{:?}` cannot be converted", value.kind))) + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct InstanceDef(usize); + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct StaticDef(pub DefId); + +impl IndexedVal for InstanceDef { + fn to_val(index: usize) -> Self { + InstanceDef(index) + } + fn to_index(&self) -> usize { + self.0 + } +} diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 6029e3c11ad..003045a4696 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -3,7 +3,7 @@ use super::{ mir::{Body, Mutability}, with, AllocId, DefId, Symbol, }; -use crate::Opaque; +use crate::{Filename, Opaque}; use std::fmt::{self, Debug, Formatter}; #[derive(Copy, Clone)] @@ -75,17 +75,48 @@ pub struct Placeholder<T> { } #[derive(Clone, Copy, PartialEq, Eq)] -pub struct Span(pub usize); +pub struct Span(usize); impl Debug for Span { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("Span") .field("id", &self.0) - .field("repr", &with(|cx| cx.print_span(*self))) + .field("repr", &with(|cx| cx.span_to_string(*self))) .finish() } } +impl Span { + /// Return filename for diagnostic purposes + pub fn get_filename(&self) -> Filename { + with(|c| c.get_filename(self)) + } + + /// Return lines that corespond to this `Span` + pub fn get_lines(&self) -> LineInfo { + with(|c| c.get_lines(&self)) + } +} + +#[derive(Clone, Copy, Debug)] +/// Information you get from `Span` in a struct form. +/// Line and col start from 1. +pub struct LineInfo { + pub start_line: usize, + pub start_col: usize, + pub end_line: usize, + pub end_col: usize, +} + +impl IndexedVal for Span { + fn to_val(index: usize) -> Self { + Span(index) + } + fn to_index(&self) -> usize { + self.0 + } +} + #[derive(Clone, Debug)] pub enum TyKind { RigidTy(RigidTy), @@ -565,3 +596,9 @@ pub enum ImplPolarity { Negative, Reservation, } + +pub trait IndexedVal { + fn to_val(index: usize) -> Self; + + fn to_index(&self) -> usize; +} diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 5481b327d69..4bdd9639557 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -669,7 +669,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> { /// map.insert(1, "a"); /// ``` #[unstable(feature = "btreemap_alloc", issue = "32838")] - pub fn new_in(alloc: A) -> BTreeMap<K, V, A> { + pub const fn new_in(alloc: A) -> BTreeMap<K, V, A> { BTreeMap { root: None, length: 0, alloc: ManuallyDrop::new(alloc), _marker: PhantomData } } } diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 9da230915b8..0e03551286e 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -358,7 +358,7 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> { /// let mut set: BTreeSet<i32> = BTreeSet::new_in(Global); /// ``` #[unstable(feature = "btreemap_alloc", issue = "32838")] - pub fn new_in(alloc: A) -> BTreeSet<T, A> { + pub const fn new_in(alloc: A) -> BTreeSet<T, A> { BTreeSet { map: BTreeMap::new_in(alloc) } } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index cd3648214a4..d47f9de941c 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -78,6 +78,8 @@ not(no_sync), target_has_atomic = "ptr" ))] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![no_std] #![needs_allocator] // Lints: diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 01b03de6acb..625b67a79ad 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -530,6 +530,7 @@ fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { // ensure that the code generation related to these panics is minimal as there's // only one location which panics rather than a bunch throughout the module. #[cfg(not(no_global_oom_handling))] +#[inline(never)] fn capacity_overflow() -> ! { panic!("capacity overflow"); } diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 73cb746c41d..dd7876bed76 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1304,7 +1304,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> { /// assert_eq!(unsafe { &*x_ptr }, "hello"); /// ``` #[stable(feature = "rc_raw", since = "1.17.0")] - #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] + #[rustc_never_returns_null_ptr] pub fn into_raw(this: Self) -> *const T { let ptr = Self::as_ptr(&this); mem::forget(this); @@ -1328,7 +1328,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> { /// assert_eq!(unsafe { &*x_ptr }, "hello"); /// ``` #[stable(feature = "weak_into_raw", since = "1.45.0")] - #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] + #[rustc_never_returns_null_ptr] pub fn as_ptr(this: &Self) -> *const T { let ptr: *mut RcBox<T> = NonNull::as_ptr(this.ptr); @@ -2409,7 +2409,7 @@ impl<T> From<T> for Rc<T> { } #[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_array", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "shared_from_array", since = "1.74.0")] impl<T, const N: usize> From<[T; N]> for Rc<[T]> { /// Converts a [`[T; N]`](prim@array) into an `Rc<[T]>`. /// diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index e42bed7d264..4d6968157de 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -714,6 +714,156 @@ impl String { .collect() } + /// Decode a UTF-16LE–encoded vector `v` into a `String`, returning [`Err`] + /// if `v` contains any invalid data. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(str_from_utf16_endian)] + /// // 𝄞music + /// let v = &[0x34, 0xD8, 0x1E, 0xDD, 0x6d, 0x00, 0x75, 0x00, + /// 0x73, 0x00, 0x69, 0x00, 0x63, 0x00]; + /// assert_eq!(String::from("𝄞music"), + /// String::from_utf16le(v).unwrap()); + /// + /// // 𝄞mu<invalid>ic + /// let v = &[0x34, 0xD8, 0x1E, 0xDD, 0x6d, 0x00, 0x75, 0x00, + /// 0x00, 0xD8, 0x69, 0x00, 0x63, 0x00]; + /// assert!(String::from_utf16le(v).is_err()); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "str_from_utf16_endian", issue = "116258")] + pub fn from_utf16le(v: &[u8]) -> Result<String, FromUtf16Error> { + if v.len() % 2 != 0 { + return Err(FromUtf16Error(())); + } + match (cfg!(target_endian = "little"), unsafe { v.align_to::<u16>() }) { + (true, ([], v, [])) => Self::from_utf16(v), + _ => char::decode_utf16(v.array_chunks::<2>().copied().map(u16::from_le_bytes)) + .collect::<Result<_, _>>() + .map_err(|_| FromUtf16Error(())), + } + } + + /// Decode a UTF-16LE–encoded slice `v` into a `String`, replacing + /// invalid data with [the replacement character (`U+FFFD`)][U+FFFD]. + /// + /// Unlike [`from_utf8_lossy`] which returns a [`Cow<'a, str>`], + /// `from_utf16le_lossy` returns a `String` since the UTF-16 to UTF-8 + /// conversion requires a memory allocation. + /// + /// [`from_utf8_lossy`]: String::from_utf8_lossy + /// [`Cow<'a, str>`]: crate::borrow::Cow "borrow::Cow" + /// [U+FFFD]: core::char::REPLACEMENT_CHARACTER + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(str_from_utf16_endian)] + /// // 𝄞mus<invalid>ic<invalid> + /// let v = &[0x34, 0xD8, 0x1E, 0xDD, 0x6d, 0x00, 0x75, 0x00, + /// 0x73, 0x00, 0x1E, 0xDD, 0x69, 0x00, 0x63, 0x00, + /// 0x34, 0xD8]; + /// + /// assert_eq!(String::from("𝄞mus\u{FFFD}ic\u{FFFD}"), + /// String::from_utf16le_lossy(v)); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "str_from_utf16_endian", issue = "116258")] + pub fn from_utf16le_lossy(v: &[u8]) -> String { + match (cfg!(target_endian = "little"), unsafe { v.align_to::<u16>() }) { + (true, ([], v, [])) => Self::from_utf16_lossy(v), + (true, ([], v, [_remainder])) => Self::from_utf16_lossy(v) + "\u{FFFD}", + _ => { + let mut iter = v.array_chunks::<2>(); + let string = char::decode_utf16(iter.by_ref().copied().map(u16::from_le_bytes)) + .map(|r| r.unwrap_or(char::REPLACEMENT_CHARACTER)) + .collect(); + if iter.remainder().is_empty() { string } else { string + "\u{FFFD}" } + } + } + } + + /// Decode a UTF-16BE–encoded vector `v` into a `String`, returning [`Err`] + /// if `v` contains any invalid data. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(str_from_utf16_endian)] + /// // 𝄞music + /// let v = &[0xD8, 0x34, 0xDD, 0x1E, 0x00, 0x6d, 0x00, 0x75, + /// 0x00, 0x73, 0x00, 0x69, 0x00, 0x63]; + /// assert_eq!(String::from("𝄞music"), + /// String::from_utf16be(v).unwrap()); + /// + /// // 𝄞mu<invalid>ic + /// let v = &[0xD8, 0x34, 0xDD, 0x1E, 0x00, 0x6d, 0x00, 0x75, + /// 0xD8, 0x00, 0x00, 0x69, 0x00, 0x63]; + /// assert!(String::from_utf16be(v).is_err()); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "str_from_utf16_endian", issue = "116258")] + pub fn from_utf16be(v: &[u8]) -> Result<String, FromUtf16Error> { + if v.len() % 2 != 0 { + return Err(FromUtf16Error(())); + } + match (cfg!(target_endian = "big"), unsafe { v.align_to::<u16>() }) { + (true, ([], v, [])) => Self::from_utf16(v), + _ => char::decode_utf16(v.array_chunks::<2>().copied().map(u16::from_be_bytes)) + .collect::<Result<_, _>>() + .map_err(|_| FromUtf16Error(())), + } + } + + /// Decode a UTF-16BE–encoded slice `v` into a `String`, replacing + /// invalid data with [the replacement character (`U+FFFD`)][U+FFFD]. + /// + /// Unlike [`from_utf8_lossy`] which returns a [`Cow<'a, str>`], + /// `from_utf16le_lossy` returns a `String` since the UTF-16 to UTF-8 + /// conversion requires a memory allocation. + /// + /// [`from_utf8_lossy`]: String::from_utf8_lossy + /// [`Cow<'a, str>`]: crate::borrow::Cow "borrow::Cow" + /// [U+FFFD]: core::char::REPLACEMENT_CHARACTER + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(str_from_utf16_endian)] + /// // 𝄞mus<invalid>ic<invalid> + /// let v = &[0xD8, 0x34, 0xDD, 0x1E, 0x00, 0x6d, 0x00, 0x75, + /// 0x00, 0x73, 0xDD, 0x1E, 0x00, 0x69, 0x00, 0x63, + /// 0xD8, 0x34]; + /// + /// assert_eq!(String::from("𝄞mus\u{FFFD}ic\u{FFFD}"), + /// String::from_utf16be_lossy(v)); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "str_from_utf16_endian", issue = "116258")] + pub fn from_utf16be_lossy(v: &[u8]) -> String { + match (cfg!(target_endian = "big"), unsafe { v.align_to::<u16>() }) { + (true, ([], v, [])) => Self::from_utf16_lossy(v), + (true, ([], v, [_remainder])) => Self::from_utf16_lossy(v) + "\u{FFFD}", + _ => { + let mut iter = v.array_chunks::<2>(); + let string = char::decode_utf16(iter.by_ref().copied().map(u16::from_be_bytes)) + .map(|r| r.unwrap_or(char::REPLACEMENT_CHARACTER)) + .collect(); + if iter.remainder().is_empty() { string } else { string + "\u{FFFD}" } + } + } + } + /// Decomposes a `String` into its raw components. /// /// Returns the raw pointer to the underlying data, the length of diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 0c6f3ef9b73..351e6c1a4b3 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1455,7 +1455,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> { /// ``` #[must_use = "losing the pointer will leak memory"] #[stable(feature = "rc_raw", since = "1.17.0")] - #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] + #[rustc_never_returns_null_ptr] pub fn into_raw(this: Self) -> *const T { let ptr = Self::as_ptr(&this); mem::forget(this); @@ -1480,7 +1480,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> { /// ``` #[must_use] #[stable(feature = "rc_as_ptr", since = "1.45.0")] - #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] + #[rustc_never_returns_null_ptr] pub fn as_ptr(this: &Self) -> *const T { let ptr: *mut ArcInner<T> = NonNull::as_ptr(this.ptr); @@ -3271,7 +3271,7 @@ impl<T> From<T> for Arc<T> { } #[cfg(not(no_global_oom_handling))] -#[stable(feature = "shared_from_array", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "shared_from_array", since = "1.74.0")] impl<T, const N: usize> From<[T; N]> for Arc<[T]> { /// Converts a [`[T; N]`](prim@array) into an `Arc<[T]>`. /// diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 6f0cd5316a0..3b12c1bee0b 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1258,7 +1258,7 @@ impl<T, A: Allocator> Vec<T, A> { /// [`as_mut_ptr`]: Vec::as_mut_ptr /// [`as_ptr`]: Vec::as_ptr #[stable(feature = "vec_as_ptr", since = "1.37.0")] - #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] + #[rustc_never_returns_null_ptr] #[inline] pub fn as_ptr(&self) -> *const T { // We shadow the slice method of the same name to avoid going through @@ -1318,7 +1318,7 @@ impl<T, A: Allocator> Vec<T, A> { /// [`as_mut_ptr`]: Vec::as_mut_ptr /// [`as_ptr`]: Vec::as_ptr #[stable(feature = "vec_as_ptr", since = "1.37.0")] - #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] + #[rustc_never_returns_null_ptr] #[inline] pub fn as_mut_ptr(&mut self) -> *mut T { // We shadow the slice method of the same name to avoid going through @@ -1956,6 +1956,7 @@ impl<T, A: Allocator> Vec<T, A> { } else { unsafe { self.len -= 1; + core::intrinsics::assume(self.len < self.capacity()); Some(ptr::read(self.as_ptr().add(self.len()))) } } @@ -3155,7 +3156,7 @@ impl<T: Clone> From<&mut [T]> for Vec<T> { } #[cfg(not(no_global_oom_handling))] -#[stable(feature = "vec_from_array_ref", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "vec_from_array_ref", since = "1.74.0")] impl<T: Clone, const N: usize> From<&[T; N]> for Vec<T> { /// Allocate a `Vec<T>` and fill it by cloning `s`'s items. /// @@ -3170,7 +3171,7 @@ impl<T: Clone, const N: usize> From<&[T; N]> for Vec<T> { } #[cfg(not(no_global_oom_handling))] -#[stable(feature = "vec_from_array_ref", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "vec_from_array_ref", since = "1.74.0")] impl<T: Clone, const N: usize> From<&mut [T; N]> for Vec<T> { /// Allocate a `Vec<T>` and fill it by cloning `s`'s items. /// diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 59730303734..65946e09ff9 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -130,6 +130,8 @@ impl Layout { } /// The minimum byte alignment for a memory block of this layout. + /// + /// The returned alignment is guaranteed to be a power of two. #[stable(feature = "alloc_layout", since = "1.28.0")] #[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")] #[must_use = "this returns the minimum alignment, \ diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index 8815cb21fc4..321357a15bf 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -4,7 +4,7 @@ use crate::num::NonZeroUsize; use crate::{ fmt, intrinsics::transmute_unchecked, - iter::{self, ExactSizeIterator, FusedIterator, TrustedLen}, + iter::{self, ExactSizeIterator, FusedIterator, TrustedLen, TrustedRandomAccessNoCoerce}, mem::MaybeUninit, ops::{IndexRange, Range}, ptr, @@ -294,6 +294,12 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> { NonZeroUsize::new(remaining).map_or(Ok(()), Err) } + + #[inline] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + // SAFETY: The caller must provide an idx that is in bound of the remainder. + unsafe { self.data.as_ptr().add(self.alive.start()).add(idx).cast::<T>().read() } + } } #[stable(feature = "array_value_iter_impls", since = "1.40.0")] @@ -375,6 +381,25 @@ impl<T, const N: usize> FusedIterator for IntoIter<T, N> {} #[stable(feature = "array_value_iter_impls", since = "1.40.0")] unsafe impl<T, const N: usize> TrustedLen for IntoIter<T, N> {} +#[doc(hidden)] +#[unstable(issue = "none", feature = "std_internals")] +#[rustc_unsafe_specialization_marker] +pub trait NonDrop {} + +// T: Copy as approximation for !Drop since get_unchecked does not advance self.alive +// and thus we can't implement drop-handling +#[unstable(issue = "none", feature = "std_internals")] +impl<T: Copy> NonDrop for T {} + +#[doc(hidden)] +#[unstable(issue = "none", feature = "std_internals")] +unsafe impl<T, const N: usize> TrustedRandomAccessNoCoerce for IntoIter<T, N> +where + T: NonDrop, +{ + const MAY_HAVE_SIDE_EFFECT: bool = false; +} + #[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl<T: Clone, const N: usize> Clone for IntoIter<T, N> { fn clone(&self) -> Self { diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index db07ef7e3c9..f3d8b54d4e9 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -556,7 +556,7 @@ impl<T: ?Sized> Cell<T> { #[inline] #[stable(feature = "cell_as_ptr", since = "1.12.0")] #[rustc_const_stable(feature = "const_cell_as_ptr", since = "1.32.0")] - #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] + #[rustc_never_returns_null_ptr] pub const fn as_ptr(&self) -> *mut T { self.value.get() } @@ -1112,7 +1112,7 @@ impl<T: ?Sized> RefCell<T> { /// ``` #[inline] #[stable(feature = "cell_as_ptr", since = "1.12.0")] - #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] + #[rustc_never_returns_null_ptr] pub fn as_ptr(&self) -> *mut T { self.value.get() } @@ -2109,7 +2109,7 @@ impl<T: ?Sized> UnsafeCell<T> { #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_unsafecell_get", since = "1.32.0")] - #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] + #[rustc_never_returns_null_ptr] pub const fn get(&self) -> *mut T { // We can just cast the pointer from `UnsafeCell<T>` to `T` because of // #[repr(transparent)]. This exploits std's special status, there is @@ -2253,7 +2253,7 @@ impl<T: ?Sized> SyncUnsafeCell<T> { /// when casting to `&mut T`, and ensure that there are no mutations /// or mutable aliases going on when casting to `&T` #[inline] - #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] + #[rustc_never_returns_null_ptr] pub const fn get(&self) -> *mut T { self.value.get() } diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs index 2e8534f651a..3877a0c48cb 100644 --- a/library/core/src/cell/once.rs +++ b/library/core/src/cell/once.rs @@ -87,10 +87,40 @@ impl<T> OnceCell<T> { #[inline] #[stable(feature = "once_cell", since = "1.70.0")] pub fn set(&self, value: T) -> Result<(), T> { - // SAFETY: Safe because we cannot have overlapping mutable borrows - let slot = unsafe { &*self.inner.get() }; - if slot.is_some() { - return Err(value); + match self.try_insert(value) { + Ok(_) => Ok(()), + Err((_, value)) => Err(value), + } + } + + /// Sets the contents of the cell to `value` if the cell was empty, then + /// returns a reference to it. + /// + /// # Errors + /// + /// This method returns `Ok(&value)` if the cell was empty and + /// `Err(¤t_value, value)` if it was full. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell_try_insert)] + /// + /// use std::cell::OnceCell; + /// + /// let cell = OnceCell::new(); + /// assert!(cell.get().is_none()); + /// + /// assert_eq!(cell.try_insert(92), Ok(&92)); + /// assert_eq!(cell.try_insert(62), Err((&92, 62))); + /// + /// assert!(cell.get().is_some()); + /// ``` + #[inline] + #[unstable(feature = "once_cell_try_insert", issue = "116693")] + pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> { + if let Some(old) = self.get() { + return Err((old, value)); } // SAFETY: This is the only place where we set the slot, no races @@ -98,8 +128,7 @@ impl<T> OnceCell<T> { // checked that slot is currently `None`, so this write // maintains the `inner`'s invariant. let slot = unsafe { &mut *self.inner.get() }; - *slot = Some(value); - Ok(()) + Ok(slot.insert(value)) } /// Gets the contents of the cell, initializing it with `f` @@ -183,10 +212,9 @@ impl<T> OnceCell<T> { let val = outlined_call(f)?; // Note that *some* forms of reentrant initialization might lead to // UB (see `reentrant_init` test). I believe that just removing this - // `assert`, while keeping `set/get` would be sound, but it seems + // `panic`, while keeping `try_insert` would be sound, but it seems // better to panic, rather than to silently use an old value. - assert!(self.set(val).is_ok(), "reentrant init"); - Ok(self.get().unwrap()) + if let Ok(val) = self.try_insert(val) { Ok(val) } else { panic!("reentrant init") } } /// Consumes the cell, returning the wrapped value. diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs index b6b36886604..453de9754be 100644 --- a/library/core/src/char/convert.rs +++ b/library/core/src/char/convert.rs @@ -115,7 +115,7 @@ impl TryFrom<char> for u8 { /// failing if the code point is greater than U+FFFF. /// /// This corresponds to the UCS-2 encoding, as specified in ISO/IEC 10646:2003. -#[stable(feature = "u16_from_char", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "u16_from_char", since = "1.74.0")] impl TryFrom<char> for u16 { type Error = TryFromCharError; diff --git a/library/core/src/char/decode.rs b/library/core/src/char/decode.rs index dbfe251f2bb..d76f983d87c 100644 --- a/library/core/src/char/decode.rs +++ b/library/core/src/char/decode.rs @@ -2,6 +2,7 @@ use crate::error::Error; use crate::fmt; +use crate::iter::FusedIterator; /// An iterator that decodes UTF-16 encoded code points from an iterator of `u16`s. /// @@ -105,6 +106,9 @@ impl<I: Iterator<Item = u16>> Iterator for DecodeUtf16<I> { } } +#[stable(feature = "decode_utf16_fused_iterator", since = "CURRENT_RUSTC_VERSION")] +impl<I: Iterator<Item = u16> + FusedIterator> FusedIterator for DecodeUtf16<I> {} + impl DecodeUtf16Error { /// Returns the unpaired surrogate which caused this error. #[must_use] diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index ca4e6be71ef..227746b62c8 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -311,8 +311,7 @@ pub trait Eq: PartialEq<Self> { // // This should never be implemented by hand. #[doc(hidden)] - #[cfg_attr(bootstrap, no_coverage)] // rust-lang/rust#84605 - #[cfg_attr(not(bootstrap), coverage(off))] // + #[coverage(off)] #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn assert_receiver_is_total_eq(&self) {} @@ -322,8 +321,7 @@ pub trait Eq: PartialEq<Self> { #[rustc_builtin_macro] #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow_internal_unstable(core_intrinsics, derive_eq, structural_match)] -#[cfg_attr(bootstrap, allow_internal_unstable(no_coverage))] -#[cfg_attr(not(bootstrap), allow_internal_unstable(coverage_attribute))] +#[allow_internal_unstable(coverage_attribute)] pub macro Eq($item:item) { /* compiler built-in */ } diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index fc8d19d1a58..89125b7955e 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -573,7 +573,7 @@ pub trait Into<T>: Sized { #[rustc_diagnostic_item = "From"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(on( - all(_Self = "&str", any(T = "alloc::string::String", T = "std::string::String")), + all(_Self = "&str", T = "alloc::string::String"), note = "to coerce a `{T}` into a `{Self}`, use `&*` as a prefix", ))] pub trait From<T>: Sized { @@ -618,12 +618,11 @@ pub trait TryInto<T>: Sized { /// For example, there is no way to convert an [`i64`] into an [`i32`] /// using the [`From`] trait, because an [`i64`] may contain a value /// that an [`i32`] cannot represent and so the conversion would lose data. -/// This might be handled by truncating the [`i64`] to an [`i32`] (essentially -/// giving the [`i64`]'s value modulo [`i32::MAX`]) or by simply returning -/// [`i32::MAX`], or by some other method. The [`From`] trait is intended -/// for perfect conversions, so the `TryFrom` trait informs the -/// programmer when a type conversion could go bad and lets them -/// decide how to handle it. +/// This might be handled by truncating the [`i64`] to an [`i32`] or by +/// simply returning [`i32::MAX`], or by some other method. The [`From`] +/// trait is intended for perfect conversions, so the `TryFrom` trait +/// informs the programmer when a type conversion could go bad and lets +/// them decide how to handle it. /// /// # Generic Implementations /// diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 93a6716d7ab..e7ec1fb73cd 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -487,7 +487,7 @@ impl CStr { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0")] - #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] + #[rustc_never_returns_null_ptr] pub const fn as_ptr(&self) -> *const c_char { self.inner.as_ptr() } diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index cab195dad9b..b26a17ec30e 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -12,8 +12,7 @@ //! //! Typical usage will look like this: //! -#![cfg_attr(bootstrap, doc = "```rust,ignore")] -#![cfg_attr(not(bootstrap), doc = "```rust")] +//! ```rust //! #![feature(core_intrinsics, custom_mir)] //! #![allow(internal_features)] //! @@ -63,8 +62,7 @@ //! //! # Examples //! -#![cfg_attr(bootstrap, doc = "```rust,ignore")] -#![cfg_attr(not(bootstrap), doc = "```rust")] +//! ```rust //! #![feature(core_intrinsics, custom_mir)] //! #![allow(internal_features)] //! @@ -106,7 +104,6 @@ //! } //! //! #[custom_mir(dialect = "runtime", phase = "optimized")] -#![cfg_attr(bootstrap, doc = "#[cfg(any())]")] // disable the following function in doctests when `bootstrap` is set //! fn push_and_pop<T>(v: &mut Vec<T>, value: T) { //! mir!( //! let _unused; @@ -319,8 +316,7 @@ define!( /// /// # Examples /// - #[cfg_attr(bootstrap, doc = "```rust,ignore")] - #[cfg_attr(not(bootstrap), doc = "```rust")] + /// ```rust /// #![allow(internal_features)] /// #![feature(custom_mir, core_intrinsics)] /// diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index b6b0c90cb7d..77ccf508502 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -95,6 +95,14 @@ where } #[inline] + fn fold<Acc, F>(self, init: Acc, f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + ZipImpl::fold(self, init, f) + } + + #[inline] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item where Self: TrustedRandomAccessNoCoerce, @@ -129,6 +137,9 @@ trait ZipImpl<A, B> { where A: DoubleEndedIterator + ExactSizeIterator, B: DoubleEndedIterator + ExactSizeIterator; + fn fold<Acc, F>(self, init: Acc, f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc; // This has the same safety requirements as `Iterator::__iterator_get_unchecked` unsafe fn get_unchecked(&mut self, idx: usize) -> <Self as Iterator>::Item where @@ -228,6 +239,14 @@ where { unreachable!("Always specialized"); } + + #[inline] + default fn fold<Acc, F>(self, init: Acc, f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + SpecFold::spec_fold(self, init, f) + } } #[doc(hidden)] @@ -251,6 +270,24 @@ where // `Iterator::__iterator_get_unchecked`. unsafe { (self.a.__iterator_get_unchecked(idx), self.b.__iterator_get_unchecked(idx)) } } + + #[inline] + fn fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + let mut accum = init; + let len = ZipImpl::size_hint(&self).0; + for i in 0..len { + // SAFETY: since Self: TrustedRandomAccessNoCoerce we can trust the size-hint to + // calculate the length and then use that to do unchecked iteration. + // fold consumes the iterator so we don't need to fixup any state. + unsafe { + accum = f(accum, self.get_unchecked(i)); + } + } + accum + } } #[doc(hidden)] @@ -590,3 +627,56 @@ unsafe impl<I: Iterator + TrustedRandomAccessNoCoerce> SpecTrustedRandomAccess f unsafe { self.__iterator_get_unchecked(index) } } } + +trait SpecFold: Iterator { + fn spec_fold<B, F>(self, init: B, f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B; +} + +impl<A: Iterator, B: Iterator> SpecFold for Zip<A, B> { + // Adapted from default impl from the Iterator trait + #[inline] + default fn spec_fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + let mut accum = init; + while let Some(x) = ZipImpl::next(&mut self) { + accum = f(accum, x); + } + accum + } +} + +impl<A: TrustedLen, B: TrustedLen> SpecFold for Zip<A, B> { + #[inline] + fn spec_fold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc + where + F: FnMut(Acc, Self::Item) -> Acc, + { + let mut accum = init; + loop { + let (upper, more) = if let Some(upper) = ZipImpl::size_hint(&self).1 { + (upper, false) + } else { + // Per TrustedLen contract a None upper bound means more than usize::MAX items + (usize::MAX, true) + }; + + for _ in 0..upper { + let pair = + // SAFETY: TrustedLen guarantees that at least `upper` many items are available + // therefore we know they can't be None + unsafe { (self.a.next().unwrap_unchecked(), self.b.next().unwrap_unchecked()) }; + accum = f(accum, pair); + } + + if !more { + break; + } + } + accum + } +} diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index ac1fc26a1ef..c7ace58afa8 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -27,13 +27,13 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {} #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( on( - any(_Self = "core::ops::RangeTo<Idx>", _Self = "std::ops::RangeTo<Idx>"), + _Self = "core::ops::range::RangeTo<Idx>", label = "if you meant to iterate until a value, add a starting value", note = "`..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a \ bounded `Range`: `0..end`" ), on( - any(_Self = "core::ops::RangeToInclusive<Idx>", _Self = "std::ops::RangeToInclusive<Idx>"), + _Self = "core::ops::range::RangeToInclusive<Idx>", label = "if you meant to iterate until a value (including it), add a starting value", note = "`..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant \ to have a bounded `RangeInclusive`: `0..=end`" @@ -44,7 +44,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {} ), on(_Self = "&[]", label = "`{Self}` is not an iterator; try calling `.iter()`"), on( - any(_Self = "alloc::vec::Vec<T, A>", _Self = "std::vec::Vec<T, A>"), + _Self = "alloc::vec::Vec<T, A>", label = "`{Self}` is not an iterator; try calling `.into_iter()` or `.iter()`" ), on( @@ -52,7 +52,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {} label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`" ), on( - any(_Self = "alloc::string::String", _Self = "std::string::String"), + _Self = "alloc::string::String", label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`" ), on( diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 7fa7e83a744..03243e31348 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -68,6 +68,7 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] +#![cfg_attr(not(bootstrap), doc(rust_logo))] #![doc(cfg_hide( not(test), any(not(feature = "miri-test-libstd"), test, doctest), @@ -110,8 +111,6 @@ // // Library features: // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(no_coverage))] // rust-lang/rust#84605 -#![cfg_attr(not(bootstrap), feature(coverage_attribute))] // rust-lang/rust#84605 #![feature(char_indices_offset)] #![feature(const_align_of_val)] #![feature(const_align_of_val_raw)] @@ -173,6 +172,7 @@ #![feature(const_unsafecell_get_mut)] #![feature(const_waker)] #![feature(core_panic)] +#![feature(coverage_attribute)] #![feature(duration_consts_float)] #![feature(internal_impls_macro)] #![feature(ip)] @@ -196,7 +196,6 @@ // // Language features: // tidy-alphabetical-start -#![cfg_attr(not(bootstrap), feature(effects))] #![feature(abi_unadjusted)] #![feature(adt_const_params)] #![feature(allow_internal_unsafe)] @@ -413,13 +412,13 @@ pub mod primitive; dead_code, unused_imports, unsafe_op_in_unsafe_fn, - ambiguous_glob_reexports + ambiguous_glob_reexports, + deprecated_in_future )] #[allow(rustdoc::bare_urls)] // FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is // merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet. #[allow(clashing_extern_declarations)] -#[cfg_attr(bootstrap, allow(deprecated_in_future))] #[unstable(feature = "stdsimd", issue = "48556")] mod core_arch; diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 5ed82e26a0a..f1594501d40 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -573,59 +573,59 @@ impl<T: ?Sized> Copy for &T {} #[lang = "sync"] #[rustc_on_unimplemented( on( - any(_Self = "core::cell:OnceCell<T>", _Self = "std::cell::OnceCell<T>"), + _Self = "core::cell::once::OnceCell<T>", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::OnceLock` instead" ), on( - any(_Self = "core::cell::Cell<u8>", _Self = "std::cell::Cell<u8>"), + _Self = "core::cell::Cell<u8>", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU8` instead", ), on( - any(_Self = "core::cell::Cell<u16>", _Self = "std::cell::Cell<u16>"), + _Self = "core::cell::Cell<u16>", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU16` instead", ), on( - any(_Self = "core::cell::Cell<u32>", _Self = "std::cell::Cell<u32>"), + _Self = "core::cell::Cell<u32>", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU32` instead", ), on( - any(_Self = "core::cell::Cell<u64>", _Self = "std::cell::Cell<u64>"), + _Self = "core::cell::Cell<u64>", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicU64` instead", ), on( - any(_Self = "core::cell::Cell<usize>", _Self = "std::cell::Cell<usize>"), + _Self = "core::cell::Cell<usize>", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicUsize` instead", ), on( - any(_Self = "core::cell::Cell<i8>", _Self = "std::cell::Cell<i8>"), + _Self = "core::cell::Cell<i8>", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI8` instead", ), on( - any(_Self = "core::cell::Cell<i16>", _Self = "std::cell::Cell<i16>"), + _Self = "core::cell::Cell<i16>", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI16` instead", ), on( - any(_Self = "core::cell::Cell<i32>", _Self = "std::cell::Cell<i32>"), + _Self = "core::cell::Cell<i32>", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead", ), on( - any(_Self = "core::cell::Cell<i64>", _Self = "std::cell::Cell<i64>"), + _Self = "core::cell::Cell<i64>", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI64` instead", ), on( - any(_Self = "core::cell::Cell<isize>", _Self = "std::cell::Cell<isize>"), + _Self = "core::cell::Cell<isize>", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicIsize` instead", ), on( - any(_Self = "core::cell::Cell<bool>", _Self = "std::cell::Cell<bool>"), + _Self = "core::cell::Cell<bool>", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicBool` instead", ), on( - any(_Self = "core::cell::Cell<T>", _Self = "std::cell::Cell<T>"), + _Self = "core::cell::Cell<T>", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock`", ), on( - any(_Self = "core::cell::RefCell<T>", _Self = "std::cell::RefCell<T>"), + _Self = "core::cell::RefCell<T>", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead", ), message = "`{Self}` cannot be shared between threads safely", diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index d09a24b4b1d..6274a916f3e 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -686,7 +686,10 @@ impl<T> MaybeUninit<T> { /// // they both get dropped! /// ``` #[stable(feature = "maybe_uninit_extra", since = "1.60.0")] - #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init_read", issue = "63567")] + #[rustc_const_stable( + feature = "const_maybe_uninit_assume_init_read", + since = "CURRENT_RUSTC_VERSION" + )] #[inline(always)] #[track_caller] pub const unsafe fn assume_init_read(&self) -> T { diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index d1b1eb7624b..a79a204e2c6 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1051,7 +1051,7 @@ pub const fn copy<T: Copy>(x: &T) -> T { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_stable(feature = "const_transmute_copy", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_transmute_copy", since = "1.74.0")] pub const unsafe fn transmute_copy<Src, Dst>(src: &Src) -> Dst { assert!( size_of::<Src>() >= size_of::<Dst>(), diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 6a36dfec098..b7eca9b168a 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -1,6 +1,8 @@ use crate::cmp::Ordering; use crate::fmt::{self, Write}; +use crate::iter; use crate::mem::transmute; +use crate::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not}; use super::display_buffer::DisplayBuffer; @@ -410,9 +412,12 @@ impl IpAddr { /// # Examples /// /// ``` - /// #![feature(ip)] /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// + /// let localhost_v4 = Ipv4Addr::new(127, 0, 0, 1); + /// + /// assert_eq!(IpAddr::V4(localhost_v4).to_canonical(), localhost_v4); + /// assert_eq!(IpAddr::V6(localhost_v4.to_ipv6_mapped()).to_canonical(), localhost_v4); /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).to_canonical().is_loopback(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).is_loopback(), false); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).to_canonical().is_loopback(), true); @@ -420,11 +425,11 @@ impl IpAddr { #[inline] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[rustc_const_unstable(feature = "const_ip", issue = "76205")] - #[unstable(feature = "ip", issue = "27709")] + #[stable(feature = "ip_to_canonical", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "ip_to_canonical", since = "CURRENT_RUSTC_VERSION")] pub const fn to_canonical(&self) -> IpAddr { match self { - &v4 @ IpAddr::V4(_) => v4, + IpAddr::V4(_) => *self, IpAddr::V6(v6) => v6.to_canonical(), } } @@ -1748,11 +1753,11 @@ impl Ipv6Addr { /// Some(Ipv4Addr::new(192, 10, 2, 255))); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[stable(feature = "ipv6_to_ipv4_mapped", since = "1.63.0")] + #[inline] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[stable(feature = "ipv6_to_ipv4_mapped", since = "1.63.0")] + #[rustc_const_stable(feature = "const_ipv6_to_ipv4_mapped", since = "CURRENT_RUSTC_VERSION")] pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> { match self.octets() { [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => { @@ -1817,11 +1822,11 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).to_canonical().is_loopback(), true); /// ``` - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[unstable(feature = "ip", issue = "27709")] + #[inline] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[inline] + #[stable(feature = "ip_to_canonical", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "ip_to_canonical", since = "CURRENT_RUSTC_VERSION")] pub const fn to_canonical(&self) -> IpAddr { if let Some(mapped) = self.to_ipv4_mapped() { return IpAddr::V4(mapped); @@ -2122,3 +2127,132 @@ impl From<[u16; 8]> for IpAddr { IpAddr::V6(Ipv6Addr::from(segments)) } } + +#[stable(feature = "ip_bitops", since = "CURRENT_RUSTC_VERSION")] +impl Not for Ipv4Addr { + type Output = Ipv4Addr; + + #[inline] + fn not(mut self) -> Ipv4Addr { + for octet in &mut self.octets { + *octet = !*octet; + } + self + } +} + +#[stable(feature = "ip_bitops", since = "CURRENT_RUSTC_VERSION")] +impl Not for &'_ Ipv4Addr { + type Output = Ipv4Addr; + + #[inline] + fn not(self) -> Ipv4Addr { + !*self + } +} + +#[stable(feature = "ip_bitops", since = "CURRENT_RUSTC_VERSION")] +impl Not for Ipv6Addr { + type Output = Ipv6Addr; + + #[inline] + fn not(mut self) -> Ipv6Addr { + for octet in &mut self.octets { + *octet = !*octet; + } + self + } +} + +#[stable(feature = "ip_bitops", since = "CURRENT_RUSTC_VERSION")] +impl Not for &'_ Ipv6Addr { + type Output = Ipv6Addr; + + #[inline] + fn not(self) -> Ipv6Addr { + !*self + } +} + +macro_rules! bitop_impls { + ($( + $(#[$attr:meta])* + impl ($BitOp:ident, $BitOpAssign:ident) for $ty:ty = ($bitop:ident, $bitop_assign:ident); + )*) => { + $( + $(#[$attr])* + impl $BitOpAssign for $ty { + fn $bitop_assign(&mut self, rhs: $ty) { + for (lhs, rhs) in iter::zip(&mut self.octets, rhs.octets) { + lhs.$bitop_assign(rhs); + } + } + } + + $(#[$attr])* + impl $BitOpAssign<&'_ $ty> for $ty { + fn $bitop_assign(&mut self, rhs: &'_ $ty) { + self.$bitop_assign(*rhs); + } + } + + $(#[$attr])* + impl $BitOp for $ty { + type Output = $ty; + + #[inline] + fn $bitop(mut self, rhs: $ty) -> $ty { + self.$bitop_assign(rhs); + self + } + } + + $(#[$attr])* + impl $BitOp<&'_ $ty> for $ty { + type Output = $ty; + + #[inline] + fn $bitop(mut self, rhs: &'_ $ty) -> $ty { + self.$bitop_assign(*rhs); + self + } + } + + $(#[$attr])* + impl $BitOp<$ty> for &'_ $ty { + type Output = $ty; + + #[inline] + fn $bitop(self, rhs: $ty) -> $ty { + let mut lhs = *self; + lhs.$bitop_assign(rhs); + lhs + } + } + + $(#[$attr])* + impl $BitOp<&'_ $ty> for &'_ $ty { + type Output = $ty; + + #[inline] + fn $bitop(self, rhs: &'_ $ty) -> $ty { + let mut lhs = *self; + lhs.$bitop_assign(*rhs); + lhs + } + } + )* + }; +} + +bitop_impls! { + #[stable(feature = "ip_bitops", since = "CURRENT_RUSTC_VERSION")] + impl (BitAnd, BitAndAssign) for Ipv4Addr = (bitand, bitand_assign); + #[stable(feature = "ip_bitops", since = "CURRENT_RUSTC_VERSION")] + impl (BitOr, BitOrAssign) for Ipv4Addr = (bitor, bitor_assign); + + #[stable(feature = "ip_bitops", since = "CURRENT_RUSTC_VERSION")] + impl (BitAnd, BitAndAssign) for Ipv6Addr = (bitand, bitand_assign); + #[stable(feature = "ip_bitops", since = "CURRENT_RUSTC_VERSION")] + impl (BitOr, BitOrAssign) for Ipv6Addr = (bitor, bitor_assign); +} diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 4232319fecb..8b127132c1c 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -47,7 +47,7 @@ mod nonzero; mod saturating; mod wrapping; -#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "saturating_int_impl", since = "1.74.0")] pub use saturating::Saturating; #[stable(feature = "rust1", since = "1.0.0")] pub use wrapping::Wrapping; diff --git a/library/core/src/num/saturating.rs b/library/core/src/num/saturating.rs index 5757e7498ad..d040539ebe5 100644 --- a/library/core/src/num/saturating.rs +++ b/library/core/src/num/saturating.rs @@ -31,50 +31,48 @@ use crate::ops::{Sub, SubAssign}; /// /// assert_eq!(u32::MAX, (max + one).0); /// ``` -#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "saturating_int_impl", since = "1.74.0")] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)] #[repr(transparent)] #[rustc_diagnostic_item = "Saturating"] -pub struct Saturating<T>( - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] pub T, -); +pub struct Saturating<T>(#[stable(feature = "saturating_int_impl", since = "1.74.0")] pub T); -#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "saturating_int_impl", since = "1.74.0")] impl<T: fmt::Debug> fmt::Debug for Saturating<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "saturating_int_impl", since = "1.74.0")] impl<T: fmt::Display> fmt::Display for Saturating<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "saturating_int_impl", since = "1.74.0")] impl<T: fmt::Binary> fmt::Binary for Saturating<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "saturating_int_impl", since = "1.74.0")] impl<T: fmt::Octal> fmt::Octal for Saturating<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "saturating_int_impl", since = "1.74.0")] impl<T: fmt::LowerHex> fmt::LowerHex for Saturating<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "saturating_int_impl", since = "1.74.0")] impl<T: fmt::UpperHex> fmt::UpperHex for Saturating<T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) @@ -210,7 +208,7 @@ impl<T: fmt::UpperHex> fmt::UpperHex for Saturating<T> { // FIXME(30524): impl Op<T> for Saturating<T>, impl OpAssign<T> for Saturating<T> macro_rules! saturating_impl { ($($t:ty)*) => ($( - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl Add for Saturating<$t> { type Output = Saturating<$t>; @@ -220,9 +218,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl Add, add for Saturating<$t>, Saturating<$t>, - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] } + #[stable(feature = "saturating_int_impl", since = "1.74.0")] } - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl AddAssign for Saturating<$t> { #[inline] fn add_assign(&mut self, other: Saturating<$t>) { @@ -231,7 +229,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl AddAssign, add_assign for Saturating<$t>, Saturating<$t> } - #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")] impl AddAssign<$t> for Saturating<$t> { #[inline] fn add_assign(&mut self, other: $t) { @@ -240,7 +238,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl AddAssign, add_assign for Saturating<$t>, $t } - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl Sub for Saturating<$t> { type Output = Saturating<$t>; @@ -250,9 +248,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl Sub, sub for Saturating<$t>, Saturating<$t>, - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] } + #[stable(feature = "saturating_int_impl", since = "1.74.0")] } - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl SubAssign for Saturating<$t> { #[inline] fn sub_assign(&mut self, other: Saturating<$t>) { @@ -261,7 +259,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl SubAssign, sub_assign for Saturating<$t>, Saturating<$t> } - #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")] impl SubAssign<$t> for Saturating<$t> { #[inline] fn sub_assign(&mut self, other: $t) { @@ -270,7 +268,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl SubAssign, sub_assign for Saturating<$t>, $t } - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl Mul for Saturating<$t> { type Output = Saturating<$t>; @@ -280,9 +278,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl Mul, mul for Saturating<$t>, Saturating<$t>, - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] } + #[stable(feature = "saturating_int_impl", since = "1.74.0")] } - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl MulAssign for Saturating<$t> { #[inline] fn mul_assign(&mut self, other: Saturating<$t>) { @@ -291,7 +289,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl MulAssign, mul_assign for Saturating<$t>, Saturating<$t> } - #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")] impl MulAssign<$t> for Saturating<$t> { #[inline] fn mul_assign(&mut self, other: $t) { @@ -317,7 +315,7 @@ macro_rules! saturating_impl { /// #[doc = concat!("let _ = Saturating(0", stringify!($t), ") / Saturating(0);")] /// ``` - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl Div for Saturating<$t> { type Output = Saturating<$t>; @@ -327,10 +325,10 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl Div, div for Saturating<$t>, Saturating<$t>, - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] } + #[stable(feature = "saturating_int_impl", since = "1.74.0")] } - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl DivAssign for Saturating<$t> { #[inline] fn div_assign(&mut self, other: Saturating<$t>) { @@ -339,7 +337,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl DivAssign, div_assign for Saturating<$t>, Saturating<$t> } - #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")] impl DivAssign<$t> for Saturating<$t> { #[inline] fn div_assign(&mut self, other: $t) { @@ -348,7 +346,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl DivAssign, div_assign for Saturating<$t>, $t } - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl Rem for Saturating<$t> { type Output = Saturating<$t>; @@ -358,9 +356,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl Rem, rem for Saturating<$t>, Saturating<$t>, - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] } + #[stable(feature = "saturating_int_impl", since = "1.74.0")] } - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl RemAssign for Saturating<$t> { #[inline] fn rem_assign(&mut self, other: Saturating<$t>) { @@ -369,7 +367,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl RemAssign, rem_assign for Saturating<$t>, Saturating<$t> } - #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")] impl RemAssign<$t> for Saturating<$t> { #[inline] fn rem_assign(&mut self, other: $t) { @@ -378,7 +376,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl RemAssign, rem_assign for Saturating<$t>, $t } - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl Not for Saturating<$t> { type Output = Saturating<$t>; @@ -388,9 +386,9 @@ macro_rules! saturating_impl { } } forward_ref_unop! { impl Not, not for Saturating<$t>, - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] } + #[stable(feature = "saturating_int_impl", since = "1.74.0")] } - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl BitXor for Saturating<$t> { type Output = Saturating<$t>; @@ -400,9 +398,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl BitXor, bitxor for Saturating<$t>, Saturating<$t>, - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] } + #[stable(feature = "saturating_int_impl", since = "1.74.0")] } - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl BitXorAssign for Saturating<$t> { #[inline] fn bitxor_assign(&mut self, other: Saturating<$t>) { @@ -411,7 +409,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Saturating<$t>, Saturating<$t> } - #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")] impl BitXorAssign<$t> for Saturating<$t> { #[inline] fn bitxor_assign(&mut self, other: $t) { @@ -420,7 +418,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Saturating<$t>, $t } - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl BitOr for Saturating<$t> { type Output = Saturating<$t>; @@ -430,9 +428,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl BitOr, bitor for Saturating<$t>, Saturating<$t>, - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] } + #[stable(feature = "saturating_int_impl", since = "1.74.0")] } - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl BitOrAssign for Saturating<$t> { #[inline] fn bitor_assign(&mut self, other: Saturating<$t>) { @@ -441,7 +439,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Saturating<$t>, Saturating<$t> } - #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")] impl BitOrAssign<$t> for Saturating<$t> { #[inline] fn bitor_assign(&mut self, other: $t) { @@ -450,7 +448,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Saturating<$t>, $t } - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl BitAnd for Saturating<$t> { type Output = Saturating<$t>; @@ -460,9 +458,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl BitAnd, bitand for Saturating<$t>, Saturating<$t>, - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] } + #[stable(feature = "saturating_int_impl", since = "1.74.0")] } - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl BitAndAssign for Saturating<$t> { #[inline] fn bitand_assign(&mut self, other: Saturating<$t>) { @@ -471,7 +469,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Saturating<$t>, Saturating<$t> } - #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_assign_impl", since = "1.74.0")] impl BitAndAssign<$t> for Saturating<$t> { #[inline] fn bitand_assign(&mut self, other: $t) { @@ -499,7 +497,7 @@ macro_rules! saturating_int_impl { /// #[doc = concat!("assert_eq!(<Saturating<", stringify!($t), ">>::MIN, Saturating(", stringify!($t), "::MIN));")] /// ``` - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const MIN: Self = Self(<$t>::MIN); /// Returns the largest value that can be represented by this integer type. @@ -513,7 +511,7 @@ macro_rules! saturating_int_impl { /// #[doc = concat!("assert_eq!(<Saturating<", stringify!($t), ">>::MAX, Saturating(", stringify!($t), "::MAX));")] /// ``` - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const MAX: Self = Self(<$t>::MAX); /// Returns the size of this integer type in bits. @@ -527,7 +525,7 @@ macro_rules! saturating_int_impl { /// #[doc = concat!("assert_eq!(<Saturating<", stringify!($t), ">>::BITS, ", stringify!($t), "::BITS);")] /// ``` - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const BITS: u32 = <$t>::BITS; /// Returns the number of ones in the binary representation of `self`. @@ -548,8 +546,8 @@ macro_rules! saturating_int_impl { #[doc(alias = "popcnt")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn count_ones(self) -> u32 { self.0.count_ones() } @@ -568,8 +566,8 @@ macro_rules! saturating_int_impl { #[inline] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn count_zeros(self) -> u32 { self.0.count_zeros() } @@ -590,8 +588,8 @@ macro_rules! saturating_int_impl { #[inline] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn trailing_zeros(self) -> u32 { self.0.trailing_zeros() } @@ -618,8 +616,8 @@ macro_rules! saturating_int_impl { #[inline] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn rotate_left(self, n: u32) -> Self { Saturating(self.0.rotate_left(n)) } @@ -646,8 +644,8 @@ macro_rules! saturating_int_impl { #[inline] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn rotate_right(self, n: u32) -> Self { Saturating(self.0.rotate_right(n)) } @@ -672,8 +670,8 @@ macro_rules! saturating_int_impl { #[inline] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn swap_bytes(self) -> Self { Saturating(self.0.swap_bytes()) } @@ -699,8 +697,8 @@ macro_rules! saturating_int_impl { /// assert_eq!(m, Saturating(-22016)); /// ``` #[inline] - #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn reverse_bits(self) -> Self { @@ -729,8 +727,8 @@ macro_rules! saturating_int_impl { /// ``` #[inline] #[must_use] - #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn from_be(x: Self) -> Self { Saturating(<$t>::from_be(x.0)) } @@ -757,8 +755,8 @@ macro_rules! saturating_int_impl { /// ``` #[inline] #[must_use] - #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn from_le(x: Self) -> Self { Saturating(<$t>::from_le(x.0)) } @@ -784,8 +782,8 @@ macro_rules! saturating_int_impl { /// } /// ``` #[inline] - #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn to_be(self) -> Self { @@ -813,8 +811,8 @@ macro_rules! saturating_int_impl { /// } /// ``` #[inline] - #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn to_le(self) -> Self { @@ -842,8 +840,8 @@ macro_rules! saturating_int_impl { /// assert_eq!(Saturating(3i8).pow(6), Saturating(127)); /// ``` #[inline] - #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn pow(self, exp: u32) -> Self { @@ -872,8 +870,8 @@ macro_rules! saturating_int_impl_signed { /// assert_eq!(n.leading_zeros(), 3); /// ``` #[inline] - #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn leading_zeros(self) -> u32 { @@ -897,8 +895,8 @@ macro_rules! saturating_int_impl_signed { #[doc = concat!("assert_eq!(Saturating(", stringify!($t), "::MIN).abs(), Saturating(", stringify!($t), "::MAX));")] /// ``` #[inline] - #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn abs(self) -> Saturating<$t> { @@ -923,8 +921,8 @@ macro_rules! saturating_int_impl_signed { #[doc = concat!("assert_eq!(Saturating(-10", stringify!($t), ").signum(), Saturating(-1));")] /// ``` #[inline] - #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn signum(self) -> Saturating<$t> { @@ -946,8 +944,8 @@ macro_rules! saturating_int_impl_signed { /// ``` #[must_use] #[inline] - #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn is_positive(self) -> bool { self.0.is_positive() } @@ -967,14 +965,14 @@ macro_rules! saturating_int_impl_signed { /// ``` #[must_use] #[inline] - #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn is_negative(self) -> bool { self.0.is_negative() } } - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] impl Neg for Saturating<$t> { type Output = Self; #[inline] @@ -983,7 +981,7 @@ macro_rules! saturating_int_impl_signed { } } forward_ref_unop! { impl Neg, neg for Saturating<$t>, - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] } + #[stable(feature = "saturating_int_impl", since = "1.74.0")] } )*) } @@ -1006,8 +1004,8 @@ macro_rules! saturating_int_impl_unsigned { /// assert_eq!(n.leading_zeros(), 2); /// ``` #[inline] - #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn leading_zeros(self) -> u32 { @@ -1028,8 +1026,8 @@ macro_rules! saturating_int_impl_unsigned { /// ``` #[must_use] #[inline] - #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] - #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "1.74.0")] + #[stable(feature = "saturating_int_impl", since = "1.74.0")] pub const fn is_power_of_two(self) -> bool { self.0.is_power_of_two() } diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs index f4649be54d5..6ceee463729 100644 --- a/library/core/src/ops/index.rs +++ b/library/core/src/ops/index.rs @@ -153,7 +153,7 @@ see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#ind see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>" ), on( - any(_Self = "alloc::string::String", _Self = "std::string::String"), + _Self = "alloc::string::String", note = "you can use `.chars().nth()` or `.bytes().nth()` see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>" ), diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index 17625daccbc..3f8c8efd416 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -226,14 +226,8 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - any( - _Self = "core::result::Result<T, E>", - _Self = "std::result::Result<T, E>", - ), - any( - R = "core::option::Option<core::convert::Infallible>", - R = "std::option::Option<std::convert::Infallible>", - ) + _Self = "core::result::Result<T, E>", + R = "core::option::Option<core::convert::Infallible>", ), message = "the `?` operator can only be used on `Result`s, not `Option`s, \ in {ItemContext} that returns `Result`", @@ -243,10 +237,7 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - any( - _Self = "core::result::Result<T, E>", - _Self = "std::result::Result<T, E>", - ) + _Self = "core::result::Result<T, E>", ), // There's a special error message in the trait selection code for // `From` in `?`, so this is not shown for result-in-result errors, @@ -259,14 +250,8 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - any( - _Self = "core::option::Option<T>", - _Self = "std::option::Option<T>", - ), - any( - R = "core::result::Result<T, E>", - R = "std::result::Result<T, E>", - ) + _Self = "core::option::Option<T>", + R = "core::result::Result<T, E>", ), message = "the `?` operator can only be used on `Option`s, not `Result`s, \ in {ItemContext} that returns `Option`", @@ -276,10 +261,7 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - any( - _Self = "core::option::Option<T>", - _Self = "std::option::Option<T>", - ) + _Self = "core::option::Option<T>", ), // `Option`-in-`Option` always works, as there's only one possible // residual, so this can also be phrased strongly. @@ -291,14 +273,8 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - any( - _Self = "core::ops::ControlFlow<B, C>", - _Self = "std::ops::ControlFlow<B, C>", - ), - any( - R = "core::ops::ControlFlow<B, C>", - R = "std::ops::ControlFlow<B, C>", - ) + _Self = "core::ops::control_flow::ControlFlow<B, C>", + R = "core::ops::control_flow::ControlFlow<B, C>", ), message = "the `?` operator in {ItemContext} that returns `ControlFlow<B, _>` \ can only be used on other `ControlFlow<B, _>`s (with the same Break type)", @@ -309,10 +285,7 @@ pub trait Try: FromResidual { on( all( from_desugaring = "QuestionMark", - any( - _Self = "core::ops::ControlFlow<B, C>", - _Self = "std::ops::ControlFlow<B, C>", - ) + _Self = "core::ops::control_flow::ControlFlow<B, C>", // `R` is not a `ControlFlow`, as that case was matched previously ), message = "the `?` operator can only be used on `ControlFlow`s \ diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 1a32cf92ffb..39a5e8d9fe2 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -229,7 +229,6 @@ fn panic_cannot_unwind() -> ! { /// pass to `panic_nounwind`. /// This function is called directly by the codegen backend, and must not have /// any extra arguments (including those synthesized by track_caller). -#[cfg(not(bootstrap))] #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[lang = "panic_in_cleanup"] // needed by codegen for panic in nounwind function diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 9af8f1228f0..a3e4f0fb90a 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -842,7 +842,7 @@ impl<T: ?Sized> *const T { where T: Sized, { - match intrinsics::ptr_guaranteed_cmp(self as _, other as _) { + match intrinsics::ptr_guaranteed_cmp(self, other) { 2 => None, other => Some(other == 1), } diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 5039ff53d03..84b179df8c1 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -699,7 +699,7 @@ where #[inline(always)] #[must_use] #[unstable(feature = "ptr_from_ref", issue = "106116")] -#[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] +#[rustc_never_returns_null_ptr] #[rustc_diagnostic_item = "ptr_from_ref"] pub const fn from_ref<T: ?Sized>(r: &T) -> *const T { r @@ -712,7 +712,7 @@ pub const fn from_ref<T: ?Sized>(r: &T) -> *const T { #[inline(always)] #[must_use] #[unstable(feature = "ptr_from_ref", issue = "106116")] -#[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] +#[rustc_never_returns_null_ptr] pub const fn from_mut<T: ?Sized>(r: &mut T) -> *mut T { r } diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 5f5a10bbdf3..ae673b7799f 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -339,7 +339,7 @@ impl<T: ?Sized> NonNull<T> { /// ``` #[stable(feature = "nonnull", since = "1.25.0")] #[rustc_const_stable(feature = "const_nonnull_as_ptr", since = "1.32.0")] - #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] + #[rustc_never_returns_null_ptr] #[must_use] #[inline(always)] pub const fn as_ptr(self) -> *mut T { @@ -599,7 +599,7 @@ impl<T> NonNull<[T]> { #[must_use] #[unstable(feature = "slice_ptr_get", issue = "74265")] #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")] - #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] + #[rustc_never_returns_null_ptr] pub const fn as_mut_ptr(self) -> *mut T { self.as_non_null_ptr().as_ptr() } diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 5dc53caba0d..4cfccd2e3ce 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -10,7 +10,7 @@ use crate::ops; impl [u8] { /// Checks if all bytes in this slice are within the ASCII range. #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[rustc_const_stable(feature = "const_slice_is_ascii", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_slice_is_ascii", since = "1.74.0")] #[must_use] #[inline] pub const fn is_ascii(&self) -> bool { diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index d313e8e012f..1da3a87e117 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -152,10 +152,7 @@ mod private_slice_index { #[rustc_on_unimplemented( on(T = "str", label = "string indices are ranges of `usize`",), on( - all( - any(T = "str", T = "&str", T = "alloc::string::String", T = "std::string::String"), - _Self = "{integer}" - ), + all(any(T = "str", T = "&str", T = "alloc::string::String"), _Self = "{integer}"), note = "you can use `.chars().nth()` or `.bytes().nth()`\n\ for more information, see chapter 8 in The Book: \ <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>" diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index a19fcf93c4d..45080eda2ce 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -730,7 +730,7 @@ impl<T> [T] { /// [`as_mut_ptr`]: slice::as_mut_ptr #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0")] - #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] + #[rustc_never_returns_null_ptr] #[inline(always)] #[must_use] pub const fn as_ptr(&self) -> *const T { @@ -761,7 +761,7 @@ impl<T> [T] { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")] #[rustc_allow_const_fn_unstable(const_mut_refs)] - #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] + #[rustc_never_returns_null_ptr] #[inline(always)] #[must_use] pub const fn as_mut_ptr(&mut self) -> *mut T { @@ -2482,6 +2482,62 @@ impl<T> [T] { RSplitNMut::new(self.rsplit_mut(pred), n) } + /// Splits the slice on the first element that matches the specified + /// predicate. + /// + /// If any matching elements are resent in the slice, returns the prefix + /// before the match and suffix after. The matching element itself is not + /// included. If no elements match, returns `None`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_split_once)] + /// let s = [1, 2, 3, 2, 4]; + /// assert_eq!(s.split_once(|&x| x == 2), Some(( + /// &[1][..], + /// &[3, 2, 4][..] + /// ))); + /// assert_eq!(s.split_once(|&x| x == 0), None); + /// ``` + #[unstable(feature = "slice_split_once", reason = "newly added", issue = "112811")] + #[inline] + pub fn split_once<F>(&self, pred: F) -> Option<(&[T], &[T])> + where + F: FnMut(&T) -> bool, + { + let index = self.iter().position(pred)?; + Some((&self[..index], &self[index + 1..])) + } + + /// Splits the slice on the last element that matches the specified + /// predicate. + /// + /// If any matching elements are resent in the slice, returns the prefix + /// before the match and suffix after. The matching element itself is not + /// included. If no elements match, returns `None`. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_split_once)] + /// let s = [1, 2, 3, 2, 4]; + /// assert_eq!(s.rsplit_once(|&x| x == 2), Some(( + /// &[1, 2, 3][..], + /// &[4][..] + /// ))); + /// assert_eq!(s.rsplit_once(|&x| x == 0), None); + /// ``` + #[unstable(feature = "slice_split_once", reason = "newly added", issue = "112811")] + #[inline] + pub fn rsplit_once<F>(&self, pred: F) -> Option<(&[T], &[T])> + where + F: FnMut(&T) -> bool, + { + let index = self.iter().rposition(pred)?; + Some((&self[..index], &self[index + 1..])) + } + /// Returns `true` if the slice contains an element with the given value. /// /// This operation is *O*(*n*). diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 899d572f0e3..6aba9b64509 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -386,7 +386,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rustc_str_as_ptr", since = "1.32.0")] - #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] + #[rustc_never_returns_null_ptr] #[must_use] #[inline(always)] pub const fn as_ptr(&self) -> *const u8 { @@ -402,7 +402,7 @@ impl str { /// It is your responsibility to make sure that the string slice only gets /// modified in a way that it remains valid UTF-8. #[stable(feature = "str_as_mut_ptr", since = "1.36.0")] - #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] + #[rustc_never_returns_null_ptr] #[must_use] #[inline(always)] pub fn as_mut_ptr(&mut self) -> *mut u8 { @@ -2324,7 +2324,7 @@ impl str { /// assert!(!non_ascii.is_ascii()); /// ``` #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[rustc_const_stable(feature = "const_slice_is_ascii", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_slice_is_ascii", since = "1.74.0")] #[must_use] #[inline] pub const fn is_ascii(&self) -> bool { diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index cf1fbe2d389..073488817c4 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -79,6 +79,40 @@ //! //! [lock-free]: https://en.wikipedia.org/wiki/Non-blocking_algorithm //! +//! # Atomic accesses to read-only memory +//! +//! In general, *all* atomic accesses on read-only memory are Undefined Behavior. For instance, attempting +//! to do a `compare_exchange` that will definitely fail (making it conceptually a read-only +//! operation) can still cause a page fault if the underlying memory page is mapped read-only. Since +//! atomic `load`s might be implemented using compare-exchange operations, even a `load` can fault +//! on read-only memory. +//! +//! For the purpose of this section, "read-only memory" is defined as memory that is read-only in +//! the underlying target, i.e., the pages are mapped with a read-only flag and any attempt to write +//! will cause a page fault. In particular, an `&u128` reference that points to memory that is +//! read-write mapped is *not* considered to point to "read-only memory". In Rust, almost all memory +//! is read-write; the only exceptions are memory created by `const` items or `static` items without +//! interior mutability, and memory that was specifically marked as read-only by the operating +//! system via platform-specific APIs. +//! +//! As an exception from the general rule stated above, "sufficiently small" atomic loads with +//! `Ordering::Relaxed` are implemented in a way that works on read-only memory, and are hence not +//! Undefined Behavior. The exact size limit for what makes a load "sufficiently small" varies +//! depending on the target: +//! +//! | `target_arch` | Size limit | +//! |---------------|---------| +//! | `x86`, `arm`, `mips`, `mips32r6, `powerpc`, `riscv32`, `sparc`, `hexagon` | 4 bytes | +//! | `x86_64`, `aarch64`, `loongarch64`, `mips64`, `mips64r6`, `powerpc64`, `riscv64`, `sparc64`, `s390x` | 8 bytes | +//! +//! Atomics loads that are larger than this limit as well as atomic loads with ordering other +//! than `Relaxed`, as well as *all* atomic loads on targets not listed in the table, might still be +//! read-only under certain conditions, but that is not a stable guarantee and should not be relied +//! upon. +//! +//! If you need to do an acquire load on read-only memory, you can do a relaxed load followed by an +//! acquire fence instead. +//! //! # Examples //! //! A simple spinlock: @@ -319,7 +353,7 @@ impl AtomicBool { /// # Examples /// /// ``` - /// #![feature(atomic_from_ptr, pointer_is_aligned)] + /// #![feature(pointer_is_aligned)] /// use std::sync::atomic::{self, AtomicBool}; /// use std::mem::align_of; /// @@ -346,13 +380,21 @@ impl AtomicBool { /// /// # Safety /// - /// * `ptr` must be aligned to `align_of::<AtomicBool>()` (note that on some platforms this can be bigger than `align_of::<bool>()`). + /// * `ptr` must be aligned to `align_of::<AtomicBool>()` (note that on some platforms this can + /// be bigger than `align_of::<bool>()`). /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`. - /// * The value behind `ptr` must not be accessed through non-atomic operations for the whole lifetime `'a`. + /// * Non-atomic accesses to the value behind `ptr` must have a happens-before relationship + /// with atomic accesses via the returned value (or vice-versa). + /// * In other words, time periods where the value is accessed atomically may not overlap + /// with periods where the value is accessed non-atomically. + /// * This requirement is trivially satisfied if `ptr` is never used non-atomically for the + /// duration of lifetime `'a`. Most use cases should be able to follow this guideline. + /// * This requirement is also trivially satisfied if all accesses (atomic or not) are done + /// from the same thread. /// /// [valid]: crate::ptr#safety - #[unstable(feature = "atomic_from_ptr", issue = "108652")] - #[rustc_const_unstable(feature = "atomic_from_ptr", issue = "108652")] + #[stable(feature = "atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")] pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a AtomicBool { // SAFETY: guaranteed by the caller unsafe { &*ptr.cast() } @@ -1018,7 +1060,7 @@ impl AtomicBool { #[inline] #[stable(feature = "atomic_as_ptr", since = "1.70.0")] #[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")] - #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] + #[rustc_never_returns_null_ptr] pub const fn as_ptr(&self) -> *mut bool { self.v.get().cast() } @@ -1113,7 +1155,7 @@ impl<T> AtomicPtr<T> { /// # Examples /// /// ``` - /// #![feature(atomic_from_ptr, pointer_is_aligned)] + /// #![feature(pointer_is_aligned)] /// use std::sync::atomic::{self, AtomicPtr}; /// use std::mem::align_of; /// @@ -1140,13 +1182,23 @@ impl<T> AtomicPtr<T> { /// /// # Safety /// - /// * `ptr` must be aligned to `align_of::<AtomicPtr<T>>()` (note that on some platforms this can be bigger than `align_of::<*mut T>()`). + /// * `ptr` must be aligned to `align_of::<AtomicPtr<T>>()` (note that on some platforms this + /// can be bigger than `align_of::<*mut T>()`). /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`. - /// * The value behind `ptr` must not be accessed through non-atomic operations for the whole lifetime `'a`. + /// * Non-atomic accesses to the value behind `ptr` must have a happens-before relationship + /// with atomic accesses via the returned value (or vice-versa). + /// * In other words, time periods where the value is accessed atomically may not overlap + /// with periods where the value is accessed non-atomically. + /// * This requirement is trivially satisfied if `ptr` is never used non-atomically for the + /// duration of lifetime `'a`. Most use cases should be able to follow this guideline. + /// * This requirement is also trivially satisfied if all accesses (atomic or not) are done + /// from the same thread. + /// * This method should not be used to create overlapping or mixed-size atomic accesses, as + /// these are not supported by the memory model. /// /// [valid]: crate::ptr#safety - #[unstable(feature = "atomic_from_ptr", issue = "108652")] - #[rustc_const_unstable(feature = "atomic_from_ptr", issue = "108652")] + #[stable(feature = "atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")] pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr<T> { // SAFETY: guaranteed by the caller unsafe { &*ptr.cast() } @@ -1954,7 +2006,7 @@ impl<T> AtomicPtr<T> { #[inline] #[stable(feature = "atomic_as_ptr", since = "1.70.0")] #[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")] - #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] + #[rustc_never_returns_null_ptr] pub const fn as_ptr(&self) -> *mut *mut T { self.p.get() } @@ -2083,7 +2135,7 @@ macro_rules! atomic_int { /// # Examples /// /// ``` - /// #![feature(atomic_from_ptr, pointer_is_aligned)] + /// #![feature(pointer_is_aligned)] #[doc = concat!($extra_feature, "use std::sync::atomic::{self, ", stringify!($atomic_type), "};")] /// use std::mem::align_of; /// @@ -2111,14 +2163,25 @@ macro_rules! atomic_int { /// /// # Safety /// - /// * `ptr` must be aligned to `align_of::<AtomicBool>()` (note that on some platforms this can be bigger than `align_of::<bool>()`). - #[doc = concat!(" * `ptr` must be aligned to `align_of::<", stringify!($atomic_type), ">()` (note that on some platforms this can be bigger than `align_of::<", stringify!($int_type), ">()`).")] + #[doc = concat!(" * `ptr` must be aligned to \ + `align_of::<", stringify!($atomic_type), ">()` (note that on some platforms this \ + can be bigger than `align_of::<", stringify!($int_type), ">()`).")] /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`. - /// * The value behind `ptr` must not be accessed through non-atomic operations for the whole lifetime `'a`. + /// * Non-atomic accesses to the value behind `ptr` must have a happens-before + /// relationship with atomic accesses via the returned value (or vice-versa). + /// * In other words, time periods where the value is accessed atomically may not + /// overlap with periods where the value is accessed non-atomically. + /// * This requirement is trivially satisfied if `ptr` is never used non-atomically + /// for the duration of lifetime `'a`. Most use cases should be able to follow + /// this guideline. + /// * This requirement is also trivially satisfied if all accesses (atomic or not) are + /// done from the same thread. + /// * This method should not be used to create overlapping or mixed-size atomic + /// accesses, as these are not supported by the memory model. /// /// [valid]: crate::ptr#safety - #[unstable(feature = "atomic_from_ptr", issue = "108652")] - #[rustc_const_unstable(feature = "atomic_from_ptr", issue = "108652")] + #[stable(feature = "atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")] pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a $atomic_type { // SAFETY: guaranteed by the caller unsafe { &*ptr.cast() } @@ -2893,7 +2956,7 @@ macro_rules! atomic_int { #[inline] #[stable(feature = "atomic_as_ptr", since = "1.70.0")] #[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")] - #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] + #[rustc_never_returns_null_ptr] pub const fn as_ptr(&self) -> *mut $int_type { self.v.get() } diff --git a/library/core/tests/iter/adapters/zip.rs b/library/core/tests/iter/adapters/zip.rs index 585cfbb90e4..c3508be8598 100644 --- a/library/core/tests/iter/adapters/zip.rs +++ b/library/core/tests/iter/adapters/zip.rs @@ -184,7 +184,11 @@ fn test_zip_nested_sideffectful() { let it = xs.iter_mut().map(|x| *x = 1).enumerate().zip(&ys); it.count(); } - assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); + let length_aware = &xs == &[1, 1, 1, 1, 0, 0]; + let probe_first = &xs == &[1, 1, 1, 1, 1, 0]; + + // either implementation is valid according to zip documentation + assert!(length_aware || probe_first); } #[test] diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index e4003a208bc..79601c8c19d 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -15,7 +15,6 @@ #![feature(const_hash)] #![feature(const_heap)] #![feature(const_maybe_uninit_as_mut_ptr)] -#![feature(const_maybe_uninit_assume_init_read)] #![feature(const_nonnull_new)] #![feature(const_pointer_byte_offsets)] #![feature(const_pointer_is_aligned)] @@ -49,6 +48,7 @@ #![feature(sort_internals)] #![feature(slice_take)] #![feature(slice_from_ptr_range)] +#![feature(slice_split_once)] #![feature(split_as_slice)] #![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_write_slice)] diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 865e702b5c2..666452ead3f 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -2476,6 +2476,26 @@ fn slice_rsplit_array_mut_out_of_bounds() { let _ = v.rsplit_array_mut::<7>(); } +#[test] +fn slice_split_once() { + let v = &[1, 2, 3, 2, 4][..]; + + assert_eq!(v.split_once(|&x| x == 2), Some((&[1][..], &[3, 2, 4][..]))); + assert_eq!(v.split_once(|&x| x == 1), Some((&[][..], &[2, 3, 2, 4][..]))); + assert_eq!(v.split_once(|&x| x == 4), Some((&[1, 2, 3, 2][..], &[][..]))); + assert_eq!(v.split_once(|&x| x == 0), None); +} + +#[test] +fn slice_rsplit_once() { + let v = &[1, 2, 3, 2, 4][..]; + + assert_eq!(v.rsplit_once(|&x| x == 2), Some((&[1, 2, 3][..], &[4][..]))); + assert_eq!(v.rsplit_once(|&x| x == 1), Some((&[][..], &[2, 3, 2, 4][..]))); + assert_eq!(v.rsplit_once(|&x| x == 4), Some((&[1, 2, 3, 2][..], &[][..]))); + assert_eq!(v.rsplit_once(|&x| x == 0), None); +} + macro_rules! take_tests { (slice: &[], $($tts:tt)*) => { take_tests!(ty: &[()], slice: &[], $($tts)*); diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 0a70c488aec..991fdb1256d 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -17,6 +17,8 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] // This library is copied into rust-analyzer to allow loading rustc compiled proc macros. // Please avoid unstable features where possible to minimize the amount of changes necessary // to make it compile with rust-analyzer on stable. diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index feb6274d029..3b57f864e20 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -17,7 +17,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -libc = { version = "0.2.148", default-features = false, features = ['rustc-dep-of-std'], public = true } +libc = { version = "0.2.149", default-features = false, features = ['rustc-dep-of-std'], public = true } compiler_builtins = { version = "0.1.100" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } @@ -36,10 +36,6 @@ object = { version = "0.32.0", default-features = false, optional = true, featur rand = { version = "0.8.5", default-features = false, features = ["alloc"] } rand_xorshift = "0.3.0" -[build-dependencies] -# Dependency of the `backtrace` crate's build script -cc = "1.0.67" - [target.'cfg(any(all(target_family = "wasm", target_os = "unknown"), target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies] dlmalloc = { version = "0.2.4", features = ['rustc-dep-of-std'] } diff --git a/library/std/build.rs b/library/std/build.rs index 49354d5a58c..046ac488b1f 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -1,11 +1,5 @@ use std::env; -// backtrace-rs requires a feature check on Android targets, so -// we need to run its build.rs as well. -#[allow(unused_extern_crates)] -#[path = "../backtrace/build.rs"] -mod backtrace_build_rs; - fn main() { println!("cargo:rerun-if-changed=build.rs"); let target = env::var("TARGET").expect("TARGET was not set"); @@ -65,6 +59,4 @@ fn main() { } println!("cargo:rustc-env=STD_ENV_ARCH={}", env::var("CARGO_CFG_TARGET_ARCH").unwrap()); println!("cargo:rustc-cfg=backtrace_in_libstd"); - - backtrace_build_rs::main(); } diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 93b9bf0cc20..fa9d48771b6 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -179,7 +179,7 @@ impl OsString { /// /// [conversions]: super#conversions #[inline] - #[stable(feature = "os_str_bytes", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "os_str_bytes", since = "1.74.0")] pub unsafe fn from_encoded_bytes_unchecked(bytes: Vec<u8>) -> Self { OsString { inner: Buf::from_encoded_bytes_unchecked(bytes) } } @@ -217,7 +217,7 @@ impl OsString { /// /// [`std::ffi`]: crate::ffi #[inline] - #[stable(feature = "os_str_bytes", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "os_str_bytes", since = "1.74.0")] pub fn into_encoded_bytes(self) -> Vec<u8> { self.inner.into_encoded_bytes() } @@ -768,7 +768,7 @@ impl OsStr { /// /// [conversions]: super#conversions #[inline] - #[stable(feature = "os_str_bytes", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "os_str_bytes", since = "1.74.0")] pub unsafe fn from_encoded_bytes_unchecked(bytes: &[u8]) -> &Self { Self::from_inner(Slice::from_encoded_bytes_unchecked(bytes)) } @@ -958,7 +958,7 @@ impl OsStr { /// /// [`std::ffi`]: crate::ffi #[inline] - #[stable(feature = "os_str_bytes", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "os_str_bytes", since = "1.74.0")] pub fn as_encoded_bytes(&self) -> &[u8] { self.inner.as_encoded_bytes() } diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index d74f0f00e46..f0c4be2327c 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1707,3 +1707,38 @@ fn test_file_times() { assert_eq!(metadata.created().unwrap(), created); } } + +#[test] +#[cfg(windows)] +fn windows_unix_socket_exists() { + use crate::sys::{c, net}; + use crate::{mem, ptr}; + + let tmp = tmpdir(); + let socket_path = tmp.join("socket"); + + // std doesn't current support Unix sockets on Windows so manually create one here. + net::init(); + unsafe { + let socket = c::WSASocketW( + c::AF_UNIX as i32, + c::SOCK_STREAM, + 0, + ptr::null_mut(), + 0, + c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT, + ); + assert_ne!(socket, c::INVALID_SOCKET); + let mut addr = c::SOCKADDR_UN { sun_family: c::AF_UNIX, sun_path: mem::zeroed() }; + let bytes = socket_path.as_os_str().as_encoded_bytes(); + addr.sun_path[..bytes.len()].copy_from_slice(bytes); + let len = mem::size_of_val(&addr) as i32; + let result = c::bind(socket, ptr::addr_of!(addr).cast::<c::SOCKADDR>(), len); + c::closesocket(socket); + assert_eq!(result, 0); + } + // Make sure all ways of testing a file exist work for a Unix socket. + assert_eq!(socket_path.exists(), true); + assert_eq!(socket_path.try_exists().unwrap(), true); + assert_eq!(socket_path.metadata().is_ok(), true); +} diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 5966416e32a..b63091deac2 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -536,7 +536,7 @@ impl Error { /// // errors can also be created from other errors /// let custom_error2 = Error::other(custom_error); /// ``` - #[stable(feature = "io_error_other", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "io_error_other", since = "1.74.0")] pub fn other<E>(error: E) -> Error where E: Into<Box<dyn error::Error + Send + Sync>>, diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index a7428776d8f..f438325560f 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -475,6 +475,24 @@ impl<A: Allocator> Read for VecDeque<u8, A> { } } +/// BufRead is implemented for `VecDeque<u8>` by reading bytes from the front of the `VecDeque`. +#[stable(feature = "vecdeque_buf_read", since = "CURRENT_RUSTC_VERSION")] +impl<A: Allocator> BufRead for VecDeque<u8, A> { + /// Returns the contents of the "front" slice as returned by + /// [`as_slices`][`VecDeque::as_slices`]. If the contained byte slices of the `VecDeque` are + /// discontiguous, multiple calls to `fill_buf` will be needed to read the entire content. + #[inline] + fn fill_buf(&mut self) -> io::Result<&[u8]> { + let (front, _) = self.as_slices(); + Ok(front) + } + + #[inline] + fn consume(&mut self, amt: usize) { + self.drain(..amt); + } +} + /// Write is implemented for `VecDeque<u8>` by appending to the `VecDeque`, growing it as needed. #[stable(feature = "vecdeque_read_write", since = "1.63.0")] impl<A: Allocator> Write for VecDeque<u8, A> { diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index c93bf020252..c0a72948112 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -513,8 +513,7 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [ match this.read(buf) { Ok(0) => break, Ok(n) => { - let tmp = buf; - buf = &mut tmp[n..]; + buf = &mut buf[n..]; } Err(ref e) if e.is_interrupted() => {} Err(e) => return Err(e), @@ -2778,6 +2777,7 @@ pub struct Bytes<R> { impl<R: Read> Iterator for Bytes<R> { type Item = Result<u8>; + #[inline] fn next(&mut self) -> Option<Result<u8>> { let mut byte = 0; loop { @@ -2790,6 +2790,7 @@ impl<R: Read> Iterator for Bytes<R> { } } + #[inline] fn size_hint(&self) -> (usize, Option<usize>) { SizeHint::size_hint(&self.inner) } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 02f4d5bc7ae..aaf20875129 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -227,6 +227,7 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] +#![cfg_attr(not(bootstrap), doc(rust_logo))] #![doc(cfg_hide( not(test), not(any(test, bootstrap)), diff --git a/library/std/src/num.rs b/library/std/src/num.rs index 9e021b23fec..3cd5fa458e0 100644 --- a/library/std/src/num.rs +++ b/library/std/src/num.rs @@ -12,7 +12,7 @@ mod tests; #[cfg(test)] mod benches; -#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "saturating_int_impl", since = "1.74.0")] pub use core::num::Saturating; #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::Wrapping; diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 81106d6c62c..24f2bdcf421 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -97,14 +97,14 @@ impl BorrowedFd<'_> { // We want to atomically duplicate this file descriptor and set the // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This // is a POSIX flag that was added to Linux in 2.6.24. - #[cfg(not(target_os = "espidf"))] + #[cfg(not(any(target_os = "espidf", target_os = "vita")))] let cmd = libc::F_DUPFD_CLOEXEC; // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics // will never be supported, as this is a bare metal framework with // no capabilities for multi-process execution. While F_DUPFD is also // not supported yet, it might be (currently it returns ENOSYS). - #[cfg(target_os = "espidf")] + #[cfg(any(target_os = "espidf", target_os = "vita"))] let cmd = libc::F_DUPFD; // Avoid using file descriptors below 3 as they are used for stdio @@ -119,7 +119,7 @@ impl BorrowedFd<'_> { pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> { Err(crate::io::const_io_error!( crate::io::ErrorKind::Unsupported, - "operation not supported on WASI yet", + "operation not supported on this platform", )) } } diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 5d9f7430ca2..ac551030492 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -438,7 +438,7 @@ impl From<crate::process::ChildStdin> for OwnedFd { /// /// The provided file descriptor must point to a pipe /// with the `CLOEXEC` flag set. -#[stable(feature = "child_stream_from_fd", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "child_stream_from_fd", since = "1.74.0")] impl From<OwnedFd> for process::ChildStdin { #[inline] fn from(fd: OwnedFd) -> process::ChildStdin { @@ -468,7 +468,7 @@ impl From<crate::process::ChildStdout> for OwnedFd { /// /// The provided file descriptor must point to a pipe /// with the `CLOEXEC` flag set. -#[stable(feature = "child_stream_from_fd", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "child_stream_from_fd", since = "1.74.0")] impl From<OwnedFd> for process::ChildStdout { #[inline] fn from(fd: OwnedFd) -> process::ChildStdout { @@ -498,7 +498,7 @@ impl From<crate::process::ChildStderr> for OwnedFd { /// /// The provided file descriptor must point to a pipe /// with the `CLOEXEC` flag set. -#[stable(feature = "child_stream_from_fd", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "child_stream_from_fd", since = "1.74.0")] impl From<OwnedFd> for process::ChildStderr { #[inline] fn from(fd: OwnedFd) -> process::ChildStderr { diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index 94173825c4a..d00e79476f3 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -110,7 +110,7 @@ impl IntoRawHandle for process::ChildStderr { /// /// The provided handle must be asynchronous, as reading and /// writing from and to it is implemented using asynchronous APIs. -#[stable(feature = "child_stream_from_fd", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "child_stream_from_fd", since = "1.74.0")] impl From<OwnedHandle> for process::ChildStdin { fn from(handle: OwnedHandle) -> process::ChildStdin { let handle = sys::handle::Handle::from_inner(handle); @@ -123,7 +123,7 @@ impl From<OwnedHandle> for process::ChildStdin { /// /// The provided handle must be asynchronous, as reading and /// writing from and to it is implemented using asynchronous APIs. -#[stable(feature = "child_stream_from_fd", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "child_stream_from_fd", since = "1.74.0")] impl From<OwnedHandle> for process::ChildStdout { fn from(handle: OwnedHandle) -> process::ChildStdout { let handle = sys::handle::Handle::from_inner(handle); @@ -136,7 +136,7 @@ impl From<OwnedHandle> for process::ChildStdout { /// /// The provided handle must be asynchronous, as reading and /// writing from and to it is implemented using asynchronous APIs. -#[stable(feature = "child_stream_from_fd", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "child_stream_from_fd", since = "1.74.0")] impl From<OwnedHandle> for process::ChildStderr { fn from(handle: OwnedHandle) -> process::ChildStderr { let handle = sys::handle::Handle::from_inner(handle); diff --git a/library/std/src/process.rs b/library/std/src/process.rs index e148635f581..ad29eeb6a0b 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1500,7 +1500,7 @@ impl From<fs::File> for Stdio { } } -#[stable(feature = "stdio_from_stdio", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "stdio_from_stdio", since = "1.74.0")] impl From<io::Stdout> for Stdio { /// Redirect command stdout/stderr to our stdout /// @@ -1531,7 +1531,7 @@ impl From<io::Stdout> for Stdio { } } -#[stable(feature = "stdio_from_stdio", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "stdio_from_stdio", since = "1.74.0")] impl From<io::Stderr> for Stdio { /// Redirect command stdout/stderr to our stderr /// @@ -1594,7 +1594,7 @@ impl From<io::Stderr> for Stdio { pub struct ExitStatus(imp::ExitStatus); /// The default value is one which indicates successful completion. -#[stable(feature = "process-exitcode-default", since = "1.73.0")] +#[stable(feature = "process_exitstatus_default", since = "1.73.0")] impl Default for ExitStatus { fn default() -> Self { // Ideally this would be done by ExitCode::default().into() but that is complicated. @@ -1960,6 +1960,14 @@ impl ExitCode { } } +/// The default value is [`ExitCode::SUCCESS`] +#[stable(feature = "process_exitcode_default", since = "CURRENT_RUSTC_VERSION")] +impl Default for ExitCode { + fn default() -> Self { + ExitCode::SUCCESS + } +} + #[stable(feature = "process_exitcode", since = "1.61.0")] impl From<u8> for ExitCode { /// Construct an `ExitCode` from an arbitrary u8 value. diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index f1eeb75be7c..5c83f72f3c1 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -155,6 +155,7 @@ fn lang_start_internal( } #[cfg(not(test))] +#[inline(never)] #[lang = "start"] fn lang_start<T: crate::process::Termination + 'static>( main: fn() -> T, diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index e2b7b893cb5..f4963090795 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -126,11 +126,48 @@ impl<T> OnceLock<T> { #[inline] #[stable(feature = "once_cell", since = "1.70.0")] pub fn set(&self, value: T) -> Result<(), T> { + match self.try_insert(value) { + Ok(_) => Ok(()), + Err((_, value)) => Err(value), + } + } + + /// Sets the contents of this cell to `value` if the cell was empty, then + /// returns a reference to it. + /// + /// May block if another thread is currently attempting to initialize the cell. The cell is + /// guaranteed to contain a value when set returns, though not necessarily the one provided. + /// + /// Returns `Ok(&value)` if the cell was empty and `Err(¤t_value, value)` if it was full. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell_try_insert)] + /// + /// use std::sync::OnceLock; + /// + /// static CELL: OnceLock<i32> = OnceLock::new(); + /// + /// fn main() { + /// assert!(CELL.get().is_none()); + /// + /// std::thread::spawn(|| { + /// assert_eq!(CELL.try_insert(92), Ok(&92)); + /// }).join().unwrap(); + /// + /// assert_eq!(CELL.try_insert(62), Err((&92, 62))); + /// assert_eq!(CELL.get(), Some(&92)); + /// } + /// ``` + #[inline] + #[unstable(feature = "once_cell_try_insert", issue = "116693")] + pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> { let mut value = Some(value); - self.get_or_init(|| value.take().unwrap()); + let res = self.get_or_init(|| value.take().unwrap()); match value { - None => Ok(()), - Some(value) => Err(value), + None => Ok(res), + Some(value) => Err((res, value)), } } diff --git a/library/std/src/sys/hermit/thread_local_dtor.rs b/library/std/src/sys/hermit/thread_local_dtor.rs index 613266b9530..98adaf4bff1 100644 --- a/library/std/src/sys/hermit/thread_local_dtor.rs +++ b/library/std/src/sys/hermit/thread_local_dtor.rs @@ -5,23 +5,25 @@ // The this solution works like the implementation of macOS and // doesn't additional OS support -use crate::mem; +use crate::cell::RefCell; #[thread_local] -static mut DTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new(); +static DTORS: RefCell<Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>> = RefCell::new(Vec::new()); pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { - let list = &mut DTORS; - list.push((t, dtor)); + match DTORS.try_borrow_mut() { + Ok(mut dtors) => dtors.push((t, dtor)), + Err(_) => rtabort!("global allocator may not use TLS"), + } } // every thread call this function to run through all possible destructors pub unsafe fn run_dtors() { - let mut list = mem::take(&mut DTORS); + let mut list = DTORS.take(); while !list.is_empty() { for (ptr, dtor) in list { dtor(ptr); } - list = mem::take(&mut DTORS); + list = DTORS.take(); } } diff --git a/library/std/src/sys/solid/thread_local_dtor.rs b/library/std/src/sys/solid/thread_local_dtor.rs index bad14bb37f7..26918a4fcb0 100644 --- a/library/std/src/sys/solid/thread_local_dtor.rs +++ b/library/std/src/sys/solid/thread_local_dtor.rs @@ -4,14 +4,13 @@ // Simplify dtor registration by using a list of destructors. use super::{abi, itron::task}; -use crate::cell::Cell; -use crate::mem; +use crate::cell::{Cell, RefCell}; #[thread_local] static REGISTERED: Cell<bool> = Cell::new(false); #[thread_local] -static mut DTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new(); +static DTORS: RefCell<Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>> = RefCell::new(Vec::new()); pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { if !REGISTERED.get() { @@ -22,18 +21,20 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { REGISTERED.set(true); } - let list = unsafe { &mut DTORS }; - list.push((t, dtor)); + match DTORS.try_borrow_mut() { + Ok(mut dtors) => dtors.push((t, dtor)), + Err(_) => rtabort!("global allocator may not use TLS"), + } } pub unsafe fn run_dtors() { - let mut list = mem::take(unsafe { &mut DTORS }); + let mut list = DTORS.take(); while !list.is_empty() { for (ptr, dtor) in list { unsafe { dtor(ptr) }; } - list = mem::take(unsafe { &mut DTORS }); + list = DTORS.take(); } } diff --git a/library/std/src/sys/uefi/args.rs b/library/std/src/sys/uefi/args.rs new file mode 100644 index 00000000000..4ff7be748e9 --- /dev/null +++ b/library/std/src/sys/uefi/args.rs @@ -0,0 +1,158 @@ +use r_efi::protocols::loaded_image; + +use crate::env::current_exe; +use crate::ffi::OsString; +use crate::fmt; +use crate::iter::Iterator; +use crate::mem::size_of; +use crate::sys::uefi::helpers; +use crate::vec; + +pub struct Args { + parsed_args_list: vec::IntoIter<OsString>, +} + +pub fn args() -> Args { + let lazy_current_exe = || Vec::from([current_exe().map(Into::into).unwrap_or_default()]); + + // Each loaded image has an image handle that supports `EFI_LOADED_IMAGE_PROTOCOL`. Thus, this + // will never fail. + let protocol = + helpers::image_handle_protocol::<loaded_image::Protocol>(loaded_image::PROTOCOL_GUID) + .unwrap(); + + let lp_size = unsafe { (*protocol.as_ptr()).load_options_size } as usize; + // Break if we are sure that it cannot be UTF-16 + if lp_size < size_of::<u16>() || lp_size % size_of::<u16>() != 0 { + return Args { parsed_args_list: lazy_current_exe().into_iter() }; + } + let lp_size = lp_size / size_of::<u16>(); + + let lp_cmd_line = unsafe { (*protocol.as_ptr()).load_options as *const u16 }; + if !lp_cmd_line.is_aligned() { + return Args { parsed_args_list: lazy_current_exe().into_iter() }; + } + let lp_cmd_line = unsafe { crate::slice::from_raw_parts(lp_cmd_line, lp_size) }; + + Args { + parsed_args_list: parse_lp_cmd_line(lp_cmd_line) + .unwrap_or_else(lazy_current_exe) + .into_iter(), + } +} + +impl fmt::Debug for Args { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.parsed_args_list.as_slice().fmt(f) + } +} + +impl Iterator for Args { + type Item = OsString; + + fn next(&mut self) -> Option<OsString> { + self.parsed_args_list.next() + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.parsed_args_list.size_hint() + } +} + +impl ExactSizeIterator for Args { + fn len(&self) -> usize { + self.parsed_args_list.len() + } +} + +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option<OsString> { + self.parsed_args_list.next_back() + } +} + +/// Implements the UEFI command-line argument parsing algorithm. +/// +/// This implementation is based on what is defined in Section 3.4 of +/// [UEFI Shell Specification](https://uefi.org/sites/default/files/resources/UEFI_Shell_Spec_2_0.pdf) +/// +/// Return None in the following cases: +/// - Invalid UTF-16 (unpaired surrogate) +/// - Empty/improper arguments +fn parse_lp_cmd_line(code_units: &[u16]) -> Option<Vec<OsString>> { + const QUOTE: char = '"'; + const SPACE: char = ' '; + const CARET: char = '^'; + const NULL: char = '\0'; + + let mut ret_val = Vec::new(); + let mut code_units_iter = char::decode_utf16(code_units.iter().cloned()).peekable(); + + // The executable name at the beginning is special. + let mut in_quotes = false; + let mut cur = String::new(); + while let Some(w) = code_units_iter.next() { + let w = w.ok()?; + match w { + // break on NULL + NULL => break, + // A quote mark always toggles `in_quotes` no matter what because + // there are no escape characters when parsing the executable name. + QUOTE => in_quotes = !in_quotes, + // If not `in_quotes` then whitespace ends argv[0]. + SPACE if !in_quotes => break, + // In all other cases the code unit is taken literally. + _ => cur.push(w), + } + } + + // If exe name is missing, the cli args are invalid + if cur.is_empty() { + return None; + } + + ret_val.push(OsString::from(cur)); + // Skip whitespace. + while code_units_iter.next_if_eq(&Ok(SPACE)).is_some() {} + + // Parse the arguments according to these rules: + // * All code units are taken literally except space, quote and caret. + // * When not `in_quotes`, space separate arguments. Consecutive spaces are + // treated as a single separator. + // * A space `in_quotes` is taken literally. + // * A quote toggles `in_quotes` mode unless it's escaped. An escaped quote is taken literally. + // * A quote can be escaped if preceded by caret. + // * A caret can be escaped if preceded by caret. + let mut cur = String::new(); + let mut in_quotes = false; + while let Some(w) = code_units_iter.next() { + let w = w.ok()?; + match w { + // break on NULL + NULL => break, + // If not `in_quotes`, a space or tab ends the argument. + SPACE if !in_quotes => { + ret_val.push(OsString::from(&cur[..])); + cur.truncate(0); + + // Skip whitespace. + while code_units_iter.next_if_eq(&Ok(SPACE)).is_some() {} + } + // Caret can escape quotes or carets + CARET if in_quotes => { + if let Some(x) = code_units_iter.next() { + cur.push(x.ok()?); + } + } + // If quote then flip `in_quotes` + QUOTE => in_quotes = !in_quotes, + // Everything else is always taken literally. + _ => cur.push(w), + } + } + // Push the final argument, if any. + if !cur.is_empty() || in_quotes { + ret_val.push(OsString::from(cur)); + } + Some(ret_val) +} diff --git a/library/std/src/sys/uefi/helpers.rs b/library/std/src/sys/uefi/helpers.rs index 126661bfc96..9837cc89f2d 100644 --- a/library/std/src/sys/uefi/helpers.rs +++ b/library/std/src/sys/uefi/helpers.rs @@ -139,3 +139,10 @@ pub(crate) unsafe fn close_event(evt: NonNull<crate::ffi::c_void>) -> io::Result if r.is_error() { Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } } + +/// Get the Protocol for current system handle. +/// Note: Some protocols need to be manually freed. It is the callers responsibility to do so. +pub(crate) fn image_handle_protocol<T>(protocol_guid: Guid) -> Option<NonNull<T>> { + let system_handle = uefi::env::try_image_handle()?; + open_protocol(system_handle, protocol_guid).ok() +} diff --git a/library/std/src/sys/uefi/mod.rs b/library/std/src/sys/uefi/mod.rs index 097396ae993..4edc00e3ea0 100644 --- a/library/std/src/sys/uefi/mod.rs +++ b/library/std/src/sys/uefi/mod.rs @@ -13,7 +13,6 @@ //! [`OsString`]: crate::ffi::OsString pub mod alloc; -#[path = "../unsupported/args.rs"] pub mod args; #[path = "../unix/cmath.rs"] pub mod cmath; diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index f450d708dae..7e2016c410e 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -103,7 +103,7 @@ impl Socket { } } - #[cfg(not(any(target_os = "vxworks", target_os = "vita")))] + #[cfg(not(target_os = "vxworks"))] pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> { unsafe { let mut fds = [0, 0]; @@ -135,7 +135,7 @@ impl Socket { } } - #[cfg(any(target_os = "vxworks", target_os = "vita"))] + #[cfg(target_os = "vxworks")] pub fn new_pair(_fam: c_int, _ty: c_int) -> io::Result<(Socket, Socket)> { unimplemented!() } diff --git a/library/std/src/sys/unix/process/mod.rs b/library/std/src/sys/unix/process/mod.rs index 0cf163d9fb8..947ef4c8aef 100644 --- a/library/std/src/sys/unix/process/mod.rs +++ b/library/std/src/sys/unix/process/mod.rs @@ -6,6 +6,9 @@ pub use crate::sys_common::process::CommandEnvs; #[cfg_attr(any(target_os = "espidf", target_os = "horizon"), allow(unused))] mod process_common; +#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] +mod process_unsupported; + cfg_if::cfg_if! { if #[cfg(target_os = "fuchsia")] { #[path = "process_fuchsia.rs"] @@ -15,8 +18,9 @@ cfg_if::cfg_if! { #[path = "process_vxworks.rs"] mod process_inner; } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] { - #[path = "process_unsupported.rs"] - mod process_inner; + mod process_inner { + pub use super::process_unsupported::*; + } } else { #[path = "process_unix.rs"] mod process_inner; diff --git a/library/std/src/sys/unix/process/process_common/tests.rs b/library/std/src/sys/unix/process/process_common/tests.rs index 03631e4e33b..4e41efc9096 100644 --- a/library/std/src/sys/unix/process/process_common/tests.rs +++ b/library/std/src/sys/unix/process/process_common/tests.rs @@ -159,3 +159,36 @@ fn test_program_kind() { ); } } + +// Test that Rust std handles wait status values (`ExitStatus`) the way that Unix does, +// at least for the values which represent a Unix exit status (`ExitCode`). +// Should work on every #[cfg(unix)] platform. However: +#[cfg(not(any( + // Fuchsia is not Unix and has totally broken std::os::unix. + // https://github.com/rust-lang/rust/issues/58590#issuecomment-836535609 + target_os = "fuchsia", +)))] +#[test] +fn unix_exit_statuses() { + use crate::num::NonZeroI32; + use crate::os::unix::process::ExitStatusExt; + use crate::process::*; + + for exit_code in 0..=0xff { + // FIXME impl From<ExitCode> for ExitStatus and then test that here too; + // the two ExitStatus values should be the same + let raw_wait_status = exit_code << 8; + let exit_status = ExitStatus::from_raw(raw_wait_status); + + assert_eq!(exit_status.code(), Some(exit_code)); + + if let Ok(nz) = NonZeroI32::try_from(exit_code) { + assert!(!exit_status.success()); + let es_error = exit_status.exit_ok().unwrap_err(); + assert_eq!(es_error.code().unwrap(), i32::from(nz)); + } else { + assert!(exit_status.success()); + assert_eq!(exit_status.exit_ok(), Ok(())); + } + } +} diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 564f8c48290..72aca4e6659 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -1074,3 +1074,8 @@ impl crate::os::linux::process::ChildExt for crate::process::Child { #[cfg(test)] #[path = "process_unix/tests.rs"] mod tests; + +// See [`process_unsupported_wait_status::compare_with_linux`]; +#[cfg(all(test, target_os = "linux"))] +#[path = "process_unsupported/wait_status.rs"] +mod process_unsupported_wait_status; diff --git a/library/std/src/sys/unix/process/process_unsupported.rs b/library/std/src/sys/unix/process/process_unsupported.rs index 8e0b971af73..2fbb3192265 100644 --- a/library/std/src/sys/unix/process/process_unsupported.rs +++ b/library/std/src/sys/unix/process/process_unsupported.rs @@ -55,68 +55,20 @@ impl Process { } } -#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)] -pub struct ExitStatus(c_int); - -impl ExitStatus { - #[cfg_attr(target_os = "horizon", allow(unused))] - pub fn success(&self) -> bool { - self.code() == Some(0) - } - - pub fn exit_ok(&self) -> Result<(), ExitStatusError> { - Err(ExitStatusError(1.try_into().unwrap())) - } - - pub fn code(&self) -> Option<i32> { - None - } - - pub fn signal(&self) -> Option<i32> { - None - } - - pub fn core_dumped(&self) -> bool { - false - } - - pub fn stopped_signal(&self) -> Option<i32> { - None - } - - pub fn continued(&self) -> bool { - false - } - - pub fn into_raw(&self) -> c_int { - 0 - } -} - -/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying. -impl From<c_int> for ExitStatus { - fn from(a: c_int) -> ExitStatus { - ExitStatus(a as i32) - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "exit code: {}", self.0) - } -} +mod wait_status; +pub use wait_status::ExitStatus; #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub struct ExitStatusError(NonZero_c_int); impl Into<ExitStatus> for ExitStatusError { fn into(self) -> ExitStatus { - ExitStatus(self.0.into()) + ExitStatus::from(c_int::from(self.0)) } } impl ExitStatusError { pub fn code(self) -> Option<NonZeroI32> { - ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap()) + ExitStatus::from(c_int::from(self.0)).code().map(|st| st.try_into().unwrap()) } } diff --git a/library/std/src/sys/unix/process/process_unsupported/wait_status.rs b/library/std/src/sys/unix/process/process_unsupported/wait_status.rs new file mode 100644 index 00000000000..72b7ae18cff --- /dev/null +++ b/library/std/src/sys/unix/process/process_unsupported/wait_status.rs @@ -0,0 +1,84 @@ +//! Emulated wait status for non-Unix #[cfg(unix) platforms +//! +//! Separate module to facilitate testing against a real Unix implementation. +use core::ffi::NonZero_c_int; + +use crate::ffi::c_int; +use crate::fmt; + +use super::ExitStatusError; + +/// Emulated wait status for use by `process_unsupported.rs` +/// +/// Uses the "traditional unix" encoding. For use on platfors which are `#[cfg(unix)]` +/// but do not actually support subprocesses at all. +/// +/// These platforms aren't Unix, but are simply pretending to be for porting convenience. +/// So, we provide a faithful pretence here. +#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)] +pub struct ExitStatus { + wait_status: c_int, +} + +/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it +impl From<c_int> for ExitStatus { + fn from(wait_status: c_int) -> ExitStatus { + ExitStatus { wait_status } + } +} + +impl fmt::Display for ExitStatus { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "emulated wait status: {}", self.wait_status) + } +} + +impl ExitStatus { + pub fn code(&self) -> Option<i32> { + // Linux and FreeBSD both agree that values linux 0x80 + // count as "WIFEXITED" even though this is quite mad. + // Likewise the macros disregard all the high bits, so are happy to declare + // out-of-range values to be WIFEXITED, WIFSTOPPED, etc. + let w = self.wait_status; + if (w & 0x7f) == 0 { Some((w & 0xff00) >> 8) } else { None } + } + + #[allow(unused)] + pub fn exit_ok(&self) -> Result<(), ExitStatusError> { + // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is + // true on all actual versions of Unix, is widely assumed, and is specified in SuS + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html. If it is not + // true for a platform pretending to be Unix, the tests (our doctests, and also + // process_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too. + match NonZero_c_int::try_from(self.wait_status) { + /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)), + /* was zero, couldn't convert */ Err(_) => Ok(()), + } + } + + pub fn signal(&self) -> Option<i32> { + let signal = self.wait_status & 0x007f; + if signal > 0 && signal < 0x7f { Some(signal) } else { None } + } + + pub fn core_dumped(&self) -> bool { + self.signal().is_some() && (self.wait_status & 0x80) != 0 + } + + pub fn stopped_signal(&self) -> Option<i32> { + let w = self.wait_status; + if (w & 0xff) == 0x7f { Some((w & 0xff00) >> 8) } else { None } + } + + pub fn continued(&self) -> bool { + self.wait_status == 0xffff + } + + pub fn into_raw(&self) -> c_int { + self.wait_status + } +} + +#[cfg(test)] +#[path = "wait_status/tests.rs"] // needed because of strange layout of process_unsupported +mod tests; diff --git a/library/std/src/sys/unix/process/process_unsupported/wait_status/tests.rs b/library/std/src/sys/unix/process/process_unsupported/wait_status/tests.rs new file mode 100644 index 00000000000..5132eab10a1 --- /dev/null +++ b/library/std/src/sys/unix/process/process_unsupported/wait_status/tests.rs @@ -0,0 +1,36 @@ +// Note that tests in this file are run on Linux as well as on platforms using process_unsupported + +// Test that our emulation exactly matches Linux +// +// This test runs *on Linux* but it tests +// the implementation used on non-Unix `#[cfg(unix)]` platforms. +// +// I.e. we're using Linux as a proxy for "trad unix". +#[cfg(target_os = "linux")] +#[test] +fn compare_with_linux() { + use super::ExitStatus as Emulated; + use crate::os::unix::process::ExitStatusExt as _; + use crate::process::ExitStatus as Real; + + // Check that we handle out-of-range values similarly, too. + for wstatus in -0xf_ffff..0xf_ffff { + let emulated = Emulated::from(wstatus); + let real = Real::from_raw(wstatus); + + macro_rules! compare { { $method:ident } => { + assert_eq!( + emulated.$method(), + real.$method(), + "{wstatus:#x}.{}()", + stringify!($method), + ); + } } + compare!(code); + compare!(signal); + compare!(core_dumped); + compare!(stopped_signal); + compare!(continued); + compare!(into_raw); + } +} diff --git a/library/std/src/sys/unix/thread_local_dtor.rs b/library/std/src/sys/unix/thread_local_dtor.rs index a0117e1d165..06399e8a274 100644 --- a/library/std/src/sys/unix/thread_local_dtor.rs +++ b/library/std/src/sys/unix/thread_local_dtor.rs @@ -69,15 +69,14 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { // _tlv_atexit. #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos", target_os = "tvos"))] pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { - use crate::cell::Cell; - use crate::mem; + use crate::cell::{Cell, RefCell}; use crate::ptr; #[thread_local] static REGISTERED: Cell<bool> = Cell::new(false); #[thread_local] - static mut DTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new(); + static DTORS: RefCell<Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>> = RefCell::new(Vec::new()); if !REGISTERED.get() { _tlv_atexit(run_dtors, ptr::null_mut()); @@ -88,16 +87,18 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { fn _tlv_atexit(dtor: unsafe extern "C" fn(*mut u8), arg: *mut u8); } - let list = &mut DTORS; - list.push((t, dtor)); + match DTORS.try_borrow_mut() { + Ok(mut dtors) => dtors.push((t, dtor)), + Err(_) => rtabort!("global allocator may not use TLS"), + } unsafe extern "C" fn run_dtors(_: *mut u8) { - let mut list = mem::take(&mut DTORS); + let mut list = DTORS.take(); while !list.is_empty() { for (ptr, dtor) in list { dtor(ptr); } - list = mem::take(&mut DTORS); + list = DTORS.take(); } } } diff --git a/library/std/src/sys/windows/c/windows_sys.lst b/library/std/src/sys/windows/c/windows_sys.lst index 0aca37e2d45..dad4a4223b2 100644 --- a/library/std/src/sys/windows/c/windows_sys.lst +++ b/library/std/src/sys/windows/c/windows_sys.lst @@ -1964,6 +1964,7 @@ Windows.Win32.Networking.WinSock.ADDRESS_FAMILY Windows.Win32.Networking.WinSock.ADDRINFOA Windows.Win32.Networking.WinSock.AF_INET Windows.Win32.Networking.WinSock.AF_INET6 +Windows.Win32.Networking.WinSock.AF_UNIX Windows.Win32.Networking.WinSock.AF_UNSPEC Windows.Win32.Networking.WinSock.bind Windows.Win32.Networking.WinSock.closesocket @@ -2058,6 +2059,7 @@ Windows.Win32.Networking.WinSock.SOCK_RDM Windows.Win32.Networking.WinSock.SOCK_SEQPACKET Windows.Win32.Networking.WinSock.SOCK_STREAM Windows.Win32.Networking.WinSock.SOCKADDR +Windows.Win32.Networking.WinSock.SOCKADDR_UN Windows.Win32.Networking.WinSock.SOCKET Windows.Win32.Networking.WinSock.SOCKET_ERROR Windows.Win32.Networking.WinSock.SOL_SOCKET diff --git a/library/std/src/sys/windows/c/windows_sys.rs b/library/std/src/sys/windows/c/windows_sys.rs index 851d15915c7..20b44966a39 100644 --- a/library/std/src/sys/windows/c/windows_sys.rs +++ b/library/std/src/sys/windows/c/windows_sys.rs @@ -847,6 +847,7 @@ impl ::core::clone::Clone for ADDRINFOA { } pub const AF_INET: ADDRESS_FAMILY = 2u16; pub const AF_INET6: ADDRESS_FAMILY = 23u16; +pub const AF_UNIX: u16 = 1u16; pub const AF_UNSPEC: ADDRESS_FAMILY = 0u16; pub const ALL_PROCESSOR_GROUPS: u32 = 65535u32; #[repr(C)] @@ -3813,6 +3814,17 @@ impl ::core::clone::Clone for SOCKADDR { *self } } +#[repr(C)] +pub struct SOCKADDR_UN { + pub sun_family: ADDRESS_FAMILY, + pub sun_path: [u8; 108], +} +impl ::core::marker::Copy for SOCKADDR_UN {} +impl ::core::clone::Clone for SOCKADDR_UN { + fn clone(&self) -> Self { + *self + } +} pub type SOCKET = usize; pub const SOCKET_ERROR: i32 = -1i32; pub const SOCK_DGRAM: WINSOCK_SOCKET_TYPE = 2i32; diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 0113196b824..6ded683aade 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -1515,6 +1515,13 @@ pub fn try_exists(path: &Path) -> io::Result<bool> { // as the file existing. _ if e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as i32) => Ok(true), + // `ERROR_CANT_ACCESS_FILE` means that a file exists but that the + // reparse point could not be handled by `CreateFile`. + // This can happen for special files such as: + // * Unix domain sockets which you need to `connect` to + // * App exec links which require using `CreateProcess` + _ if e.raw_os_error() == Some(c::ERROR_CANT_ACCESS_FILE as i32) => Ok(true), + // Other errors such as `ERROR_ACCESS_DENIED` may indicate that the // file exists. However, these types of errors are usually more // permanent so we report them here. diff --git a/library/std/src/sys/windows/thread_local_key.rs b/library/std/src/sys/windows/thread_local_key.rs index 036d96596e9..5eee4a9667b 100644 --- a/library/std/src/sys/windows/thread_local_key.rs +++ b/library/std/src/sys/windows/thread_local_key.rs @@ -16,14 +16,19 @@ static HAS_DTORS: AtomicBool = AtomicBool::new(false); // Using a per-thread list avoids the problems in synchronizing global state. #[thread_local] #[cfg(target_thread_local)] -static mut DESTRUCTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new(); +static DESTRUCTORS: crate::cell::RefCell<Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>> = + crate::cell::RefCell::new(Vec::new()); // Ensure this can never be inlined because otherwise this may break in dylibs. // See #44391. #[inline(never)] #[cfg(target_thread_local)] pub unsafe fn register_keyless_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { - DESTRUCTORS.push((t, dtor)); + match DESTRUCTORS.try_borrow_mut() { + Ok(mut dtors) => dtors.push((t, dtor)), + Err(_) => rtabort!("global allocator may not use TLS"), + } + HAS_DTORS.store(true, Relaxed); } @@ -37,11 +42,17 @@ unsafe fn run_keyless_dtors() { // the case that this loop always terminates because we provide the // guarantee that a TLS key cannot be set after it is flagged for // destruction. - while let Some((ptr, dtor)) = DESTRUCTORS.pop() { + loop { + // Use a let-else binding to ensure the `RefCell` guard is dropped + // immediately. Otherwise, a panic would occur if a TLS destructor + // tries to access the list. + let Some((ptr, dtor)) = DESTRUCTORS.borrow_mut().pop() else { + break; + }; (dtor)(ptr); } // We're done so free the memory. - DESTRUCTORS = Vec::new(); + DESTRUCTORS.replace(Vec::new()); } type Key = c::DWORD; diff --git a/library/std/src/sys_common/thread_local_dtor.rs b/library/std/src/sys_common/thread_local_dtor.rs index 844946eda03..98382fc6acc 100644 --- a/library/std/src/sys_common/thread_local_dtor.rs +++ b/library/std/src/sys_common/thread_local_dtor.rs @@ -13,6 +13,7 @@ #![unstable(feature = "thread_local_internals", issue = "none")] #![allow(dead_code)] +use crate::cell::RefCell; use crate::ptr; use crate::sys_common::thread_local_key::StaticKey; @@ -28,17 +29,23 @@ pub unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern "C" fn(*mut // flagged for destruction. static DTORS: StaticKey = StaticKey::new(Some(run_dtors)); - type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>; + // FIXME(joboet): integrate RefCell into pointer to avoid infinite recursion + // when the global allocator tries to register a destructor and just panic + // instead. + type List = RefCell<Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>>; if DTORS.get().is_null() { - let v: Box<List> = Box::new(Vec::new()); + let v: Box<List> = Box::new(RefCell::new(Vec::new())); DTORS.set(Box::into_raw(v) as *mut u8); } - let list: &mut List = &mut *(DTORS.get() as *mut List); - list.push((t, dtor)); + let list = &*(DTORS.get() as *const List); + match list.try_borrow_mut() { + Ok(mut dtors) => dtors.push((t, dtor)), + Err(_) => rtabort!("global allocator may not use TLS"), + } unsafe extern "C" fn run_dtors(mut ptr: *mut u8) { while !ptr.is_null() { - let list: Box<List> = Box::from_raw(ptr as *mut List); + let list = Box::from_raw(ptr as *mut List).into_inner(); for (ptr, dtor) in list.into_iter() { dtor(ptr); } diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 09994e47f0a..def94acd457 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -29,9 +29,9 @@ use crate::fmt; /// within a thread, and values that implement [`Drop`] get destructed when a /// thread exits. Some caveats apply, which are explained below. /// -/// A `LocalKey`'s initializer cannot recursively depend on itself, and using -/// a `LocalKey` in this way will cause the initializer to infinitely recurse -/// on the first call to `with`. +/// A `LocalKey`'s initializer cannot recursively depend on itself. Using a +/// `LocalKey` in this way may cause panics, aborts or infinite recursion on +/// the first call to `with`. /// /// # Examples /// diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 413f0fba342..bddf75dffbb 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -16,6 +16,8 @@ #![unstable(feature = "test", issue = "50297")] #![doc(test(attr(deny(warnings))))] +#![cfg_attr(not(bootstrap), doc(rust_logo))] +#![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![feature(internal_output_capture)] #![feature(staged_api)] #![feature(process_exitcode_internals)] diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index f5220e361b3..96a0eb75582 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -126,9 +126,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.2.2" +version = "4.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36774babb166352bb4f7b9cb16f781ffa3439d2a8f12cd31bea85a38c888fea3" +checksum = "e3ae8ba90b9d8b007efe66e55e48fb936272f5ca00349b5b0e89877520d35ea7" dependencies = [ "clap", ] diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 9bf26948af3..e236421b7f5 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -5,38 +5,47 @@ edition = "2021" build = "build.rs" default-run = "bootstrap" +[features] +build-metrics = ["sysinfo"] + [lib] -path = "lib.rs" +path = "src/lib.rs" doctest = false [[bin]] name = "bootstrap" -path = "bin/main.rs" +path = "src/bin/main.rs" test = false [[bin]] name = "rustc" -path = "bin/rustc.rs" +path = "src/bin/rustc.rs" test = false [[bin]] name = "rustdoc" -path = "bin/rustdoc.rs" +path = "src/bin/rustdoc.rs" test = false [[bin]] name = "sccache-plus-cl" -path = "bin/sccache-plus-cl.rs" +path = "src/bin/sccache-plus-cl.rs" test = false [dependencies] build_helper = { path = "../tools/build_helper" } +cc = "1.0.69" +clap = { version = "4.2.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] } +clap_complete = "4.4.3" cmake = "0.1.38" filetime = "0.2" -cc = "1.0.69" -libc = "0.2" hex = "0.4" +ignore = "0.4.10" +libc = "0.2" object = { version = "0.32.0", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] } +once_cell = "1.7.2" +opener = "0.5" +semver = "1.0.17" serde = "1.0.137" # Directly use serde_derive rather than through the derive feature of serde to allow building both # in parallel and to allow serde_json and toml to start building as soon as serde has been built. @@ -46,17 +55,11 @@ sha2 = "0.10" tar = "0.4" termcolor = "1.2.0" toml = "0.5" -ignore = "0.4.10" -opener = "0.5" -once_cell = "1.7.2" -xz2 = "0.1" walkdir = "2" +xz2 = "0.1" # Dependencies needed by the build-metrics feature sysinfo = { version = "0.26.0", optional = true } -clap = { version = "4.2.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] } -clap_complete = "4.2.2" -semver = "1.0.17" # Solaris doesn't support flock() and thus fd-lock is not option now [target.'cfg(not(target_os = "solaris"))'.dependencies] @@ -80,9 +83,6 @@ features = [ [dev-dependencies] pretty_assertions = "1.4" -[features] -build-metrics = ["sysinfo"] - # We care a lot about bootstrap's compile times, so don't include debuginfo for # dependencies, only bootstrap itself. [profile.dev] diff --git a/src/bootstrap/job.rs b/src/bootstrap/job.rs deleted file mode 100644 index b0a97b540ec..00000000000 --- a/src/bootstrap/job.rs +++ /dev/null @@ -1,143 +0,0 @@ -//! Job management on Windows for bootstrapping -//! -//! Most of the time when you're running a build system (e.g., make) you expect -//! Ctrl-C or abnormal termination to actually terminate the entire tree of -//! process in play, not just the one at the top. This currently works "by -//! default" on Unix platforms because Ctrl-C actually sends a signal to the -//! *process group* rather than the parent process, so everything will get torn -//! down. On Windows, however, this does not happen and Ctrl-C just kills the -//! parent process. -//! -//! To achieve the same semantics on Windows we use Job Objects to ensure that -//! all processes die at the same time. Job objects have a mode of operation -//! where when all handles to the object are closed it causes all child -//! processes associated with the object to be terminated immediately. -//! Conveniently whenever a process in the job object spawns a new process the -//! child will be associated with the job object as well. This means if we add -//! ourselves to the job object we create then everything will get torn down! -//! -//! Unfortunately most of the time the build system is actually called from a -//! python wrapper (which manages things like building the build system) so this -//! all doesn't quite cut it so far. To go the last mile we duplicate the job -//! object handle into our parent process (a python process probably) and then -//! close our own handle. This means that the only handle to the job object -//! resides in the parent python process, so when python dies the whole build -//! system dies (as one would probably expect!). -//! -//! Note that this module has a #[cfg(windows)] above it as none of this logic -//! is required on Unix. - -use crate::Build; -use std::env; -use std::ffi::c_void; -use std::io; -use std::mem; - -use windows::{ - core::PCWSTR, - Win32::Foundation::{CloseHandle, DuplicateHandle, DUPLICATE_SAME_ACCESS, HANDLE}, - Win32::System::Diagnostics::Debug::{SetErrorMode, SEM_NOGPFAULTERRORBOX, THREAD_ERROR_MODE}, - Win32::System::JobObjects::{ - AssignProcessToJobObject, CreateJobObjectW, JobObjectExtendedLimitInformation, - SetInformationJobObject, JOBOBJECT_EXTENDED_LIMIT_INFORMATION, - JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS, - }, - Win32::System::Threading::{ - GetCurrentProcess, OpenProcess, BELOW_NORMAL_PRIORITY_CLASS, PROCESS_DUP_HANDLE, - }, -}; - -pub unsafe fn setup(build: &mut Build) { - // Enable the Windows Error Reporting dialog which msys disables, - // so we can JIT debug rustc - let mode = SetErrorMode(THREAD_ERROR_MODE::default()); - let mode = THREAD_ERROR_MODE(mode); - SetErrorMode(mode & !SEM_NOGPFAULTERRORBOX); - - // Create a new job object for us to use - let job = CreateJobObjectW(None, PCWSTR::null()).unwrap(); - - // Indicate that when all handles to the job object are gone that all - // process in the object should be killed. Note that this includes our - // entire process tree by default because we've added ourselves and our - // children will reside in the job by default. - let mut info = JOBOBJECT_EXTENDED_LIMIT_INFORMATION::default(); - info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; - if build.config.low_priority { - info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS; - info.BasicLimitInformation.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS.0; - } - let r = SetInformationJobObject( - job, - JobObjectExtendedLimitInformation, - &info as *const _ as *const c_void, - mem::size_of_val(&info) as u32, - ) - .ok(); - assert!(r.is_ok(), "{}", io::Error::last_os_error()); - - // Assign our process to this job object. Note that if this fails, one very - // likely reason is that we are ourselves already in a job object! This can - // happen on the build bots that we've got for Windows, or if just anyone - // else is instrumenting the build. In this case we just bail out - // immediately and assume that they take care of it. - // - // Also note that nested jobs (why this might fail) are supported in recent - // versions of Windows, but the version of Windows that our bots are running - // at least don't support nested job objects. - let r = AssignProcessToJobObject(job, GetCurrentProcess()).ok(); - if r.is_err() { - CloseHandle(job); - return; - } - - // If we've got a parent process (e.g., the python script that called us) - // then move ownership of this job object up to them. That way if the python - // script is killed (e.g., via ctrl-c) then we'll all be torn down. - // - // If we don't have a parent (e.g., this was run directly) then we - // intentionally leak the job object handle. When our process exits - // (normally or abnormally) it will close the handle implicitly, causing all - // processes in the job to be cleaned up. - let pid = match env::var("BOOTSTRAP_PARENT_ID") { - Ok(s) => s, - Err(..) => return, - }; - - let parent = match OpenProcess(PROCESS_DUP_HANDLE, false, pid.parse().unwrap()).ok() { - Some(parent) => parent, - _ => { - // If we get a null parent pointer here, it is possible that either - // we have an invalid pid or the parent process has been closed. - // Since the first case rarely happens - // (only when wrongly setting the environmental variable), - // it might be better to improve the experience of the second case - // when users have interrupted the parent process and we haven't finish - // duplicating the handle yet. We just need close the job object if that occurs. - CloseHandle(job); - return; - } - }; - - let mut parent_handle = HANDLE::default(); - let r = DuplicateHandle( - GetCurrentProcess(), - job, - parent, - &mut parent_handle, - 0, - false, - DUPLICATE_SAME_ACCESS, - ) - .ok(); - - // If this failed, well at least we tried! An example of DuplicateHandle - // failing in the past has been when the wrong python2 package spawned this - // build system (e.g., the `python2` package in MSYS instead of - // `mingw-w64-x86_64-python2`). Not sure why it failed, but the "failure - // mode" here is that we only clean everything up when the build system - // dies, not when the python parent does, so not too bad. - if r.is_err() { - CloseHandle(job); - } -} diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/src/bin/main.rs index d87fb6a9cef..d87fb6a9cef 100644 --- a/src/bootstrap/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index 20cd63b966b..241ae16e595 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -15,20 +15,24 @@ //! switching compilers for the bootstrap and for build scripts will probably //! never get replaced. -include!("../dylib_util.rs"); -include!("./_helper.rs"); - use std::env; use std::path::PathBuf; -use std::process::{exit, Child, Command}; +use std::process::{Child, Command}; use std::time::Instant; +use dylib_util::{dylib_path, dylib_path_var}; + +#[path = "../utils/bin_helpers.rs"] +mod bin_helpers; + +#[path = "../utils/dylib.rs"] +mod dylib_util; + fn main() { let args = env::args_os().skip(1).collect::<Vec<_>>(); let arg = |name| args.windows(2).find(|args| args[0] == name).and_then(|args| args[1].to_str()); - let stage = parse_rustc_stage(); - let verbose = parse_rustc_verbose(); + let verbose = bin_helpers::parse_rustc_verbose(); // Detect whether or not we're a build script depending on whether --target // is passed (a bit janky...) @@ -108,36 +112,13 @@ fn main() { cmd.arg("-Ztls-model=initial-exec"); } } else { - // FIXME(rust-lang/cargo#5754) we shouldn't be using special env vars - // here, but rather Cargo should know what flags to pass rustc itself. - - // Override linker if necessary. - if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") { - cmd.arg(format!("-Clinker={host_linker}")); - } - if env::var_os("RUSTC_HOST_FUSE_LD_LLD").is_some() { - cmd.arg("-Clink-args=-fuse-ld=lld"); - } - - if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") { - if s == "true" { - cmd.arg("-C").arg("target-feature=+crt-static"); - } - if s == "false" { - cmd.arg("-C").arg("target-feature=-crt-static"); + // Find any host flags that were passed by bootstrap. + // The flags are stored in a RUSTC_HOST_FLAGS variable, separated by spaces. + if let Ok(flags) = std::env::var("RUSTC_HOST_FLAGS") { + for flag in flags.split(' ') { + cmd.arg(flag); } } - - // Cargo doesn't pass RUSTFLAGS to proc_macros: - // https://github.com/rust-lang/cargo/issues/4423 - // Thus, if we are on stage 0, we explicitly set `--cfg=bootstrap`. - // We also declare that the flag is expected, which we need to do to not - // get warnings about it being unexpected. - if stage == "0" { - cmd.arg("--cfg=bootstrap"); - } - cmd.arg("-Zunstable-options"); - cmd.arg("--check-cfg=values(bootstrap)"); } if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") { @@ -217,6 +198,12 @@ fn main() { eprintln!("{prefix} libdir: {libdir:?}"); } + if env::var_os("RUSTC_BOLT_LINK_FLAGS").is_some() { + if let Some("rustc_driver") = crate_name { + cmd.arg("-Clink-args=-Wl,-q"); + } + } + let start = Instant::now(); let (child, status) = { let errmsg = format!("\nFailed to run:\n{cmd:?}\n-------------"); diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/src/bin/rustdoc.rs index 6561c1c1933..f5f80ba2a0b 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/src/bin/rustdoc.rs @@ -5,17 +5,21 @@ use std::env; use std::ffi::OsString; use std::path::PathBuf; -use std::process::{exit, Command}; +use std::process::Command; -include!("../dylib_util.rs"); +use dylib_util::{dylib_path, dylib_path_var}; -include!("./_helper.rs"); +#[path = "../utils/bin_helpers.rs"] +mod bin_helpers; + +#[path = "../utils/dylib.rs"] +mod dylib_util; fn main() { let args = env::args_os().skip(1).collect::<Vec<_>>(); - let stage = parse_rustc_stage(); - let verbose = parse_rustc_verbose(); + let stage = bin_helpers::parse_rustc_stage(); + let verbose = bin_helpers::parse_rustc_verbose(); let rustdoc = env::var_os("RUSTDOC_REAL").expect("RUSTDOC_REAL was not set"); let libdir = env::var_os("RUSTDOC_LIBDIR").expect("RUSTDOC_LIBDIR was not set"); diff --git a/src/bootstrap/bin/sccache-plus-cl.rs b/src/bootstrap/src/bin/sccache-plus-cl.rs index 554c2dd4d81..554c2dd4d81 100644 --- a/src/bootstrap/bin/sccache-plus-cl.rs +++ b/src/bootstrap/src/bin/sccache-plus-cl.rs diff --git a/src/bootstrap/check.rs b/src/bootstrap/src/core/build_steps/check.rs index b417abc00f5..121925b56a0 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -1,10 +1,12 @@ //! Implementation of compiling the compiler and standard library, in "check"-based modes. -use crate::builder::{crate_description, Alias, Builder, Kind, RunConfig, ShouldRun, Step}; -use crate::cache::Interned; -use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo}; -use crate::config::TargetSelection; -use crate::tool::{prepare_tool_cargo, SourceType}; +use crate::core::build_steps::compile::{ + add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, +}; +use crate::core::build_steps::tool::{prepare_tool_cargo, SourceType}; +use crate::core::builder::{crate_description, Alias, Builder, Kind, RunConfig, ShouldRun, Step}; +use crate::core::config::TargetSelection; +use crate::utils::cache::Interned; use crate::INTERNER; use crate::{Compiler, Mode, Subcommand}; use std::path::{Path, PathBuf}; @@ -16,7 +18,7 @@ pub struct Std { /// /// This shouldn't be used from other steps; see the comment on [`compile::Rustc`]. /// - /// [`compile::Rustc`]: crate::compile::Rustc + /// [`compile::Rustc`]: crate::core::build_steps::compile::Rustc crates: Interned<Vec<String>>, } @@ -193,7 +195,7 @@ pub struct Rustc { /// /// This shouldn't be used from other steps; see the comment on [`compile::Rustc`]. /// - /// [`compile::Rustc`]: crate::compile::Rustc + /// [`compile::Rustc`]: crate::core::build_steps::compile::Rustc crates: Interned<Vec<String>>, } @@ -237,8 +239,8 @@ impl Step for Rustc { // the sysroot for the compiler to find. Otherwise, we're going to // fail when building crates that need to generate code (e.g., build // scripts and their dependencies). - builder.ensure(crate::compile::Std::new(compiler, compiler.host)); - builder.ensure(crate::compile::Std::new(compiler, target)); + builder.ensure(crate::core::build_steps::compile::Std::new(compiler, compiler.host)); + builder.ensure(crate::core::build_steps::compile::Std::new(compiler, target)); } else { builder.ensure(Std::new(target)); } @@ -387,7 +389,7 @@ impl Step for RustAnalyzer { &["rust-analyzer/in-rust-tree".to_owned()], ); - cargo.allow_features(crate::tool::RustAnalyzer::ALLOW_FEATURES); + cargo.allow_features(crate::core::build_steps::tool::RustAnalyzer::ALLOW_FEATURES); // For ./x.py clippy, don't check those targets because // linting tests and benchmarks can produce very noisy results diff --git a/src/bootstrap/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs index 7389816b44c..679770ce0ec 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/src/core/build_steps/clean.rs @@ -9,9 +9,9 @@ use std::fs; use std::io::{self, ErrorKind}; use std::path::Path; -use crate::builder::{crate_description, Builder, RunConfig, ShouldRun, Step}; -use crate::cache::Interned; -use crate::util::t; +use crate::core::builder::{crate_description, Builder, RunConfig, ShouldRun, Step}; +use crate::utils::cache::Interned; +use crate::utils::helpers::t; use crate::{Build, Compiler, Mode, Subcommand}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] diff --git a/src/bootstrap/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 6821ded1458..441931e415c 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -19,16 +19,17 @@ use std::str; use serde_derive::Deserialize; -use crate::builder::crate_description; -use crate::builder::Cargo; -use crate::builder::{Builder, Kind, PathSet, RunConfig, ShouldRun, Step, TaskPath}; -use crate::cache::{Interned, INTERNER}; -use crate::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection}; -use crate::dist; -use crate::llvm; -use crate::tool::SourceType; -use crate::util::get_clang_cl_resource_dir; -use crate::util::{exe, is_debug_info, is_dylib, output, symlink_dir, t, up_to_date}; +use crate::core::build_steps::dist; +use crate::core::build_steps::llvm; +use crate::core::build_steps::tool::SourceType; +use crate::core::builder::crate_description; +use crate::core::builder::Cargo; +use crate::core::builder::{Builder, Kind, PathSet, RunConfig, ShouldRun, Step, TaskPath}; +use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection}; +use crate::utils::cache::{Interned, INTERNER}; +use crate::utils::helpers::{ + exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, output, symlink_dir, t, up_to_date, +}; use crate::LLVM_TOOLS; use crate::{CLang, Compiler, DependencyType, GitRepo, Mode}; use filetime::FileTime; @@ -510,7 +511,7 @@ impl Step for StdLink { let (libdir, hostdir) = if self.force_recompile && builder.download_rustc() { // NOTE: copies part of `sysroot_libdir` to avoid having to add a new `force_recompile` argument there too let lib = builder.sysroot_libdir_relative(self.compiler); - let sysroot = builder.ensure(crate::compile::Sysroot { + let sysroot = builder.ensure(crate::core::build_steps::compile::Sysroot { compiler: self.compiler, force_recompile: self.force_recompile, }); @@ -906,6 +907,11 @@ impl Step for Rustc { cargo.arg("-p").arg(krate); } + if builder.build.config.enable_bolt_settings && compiler.stage == 1 { + // Relocations are required for BOLT to work. + cargo.env("RUSTC_BOLT_LINK_FLAGS", "1"); + } + let _guard = builder.msg_sysroot_tool( Kind::Build, compiler.stage, @@ -1011,7 +1017,8 @@ pub fn rustc_cargo_env( // detected that LLVM is already built and good to go which helps prevent // busting caches (e.g. like #71152). if builder.config.llvm_enabled() { - let building_is_expensive = crate::llvm::prebuilt_llvm_config(builder, target).is_err(); + let building_is_expensive = + crate::core::build_steps::llvm::prebuilt_llvm_config(builder, target).is_err(); // `top_stage == stage` might be false for `check --stage 1`, if we are building the stage 1 compiler let can_skip_build = builder.kind == Kind::Check && builder.top_stage == stage; let should_skip_build = building_is_expensive && can_skip_build; @@ -1679,7 +1686,7 @@ impl Step for Assemble { builder.copy(&lld_install.join("bin").join(&src_exe), &libdir_bin.join(&dst_exe)); let self_contained_lld_dir = libdir_bin.join("gcc-ld"); t!(fs::create_dir(&self_contained_lld_dir)); - let lld_wrapper_exe = builder.ensure(crate::tool::LldWrapper { + let lld_wrapper_exe = builder.ensure(crate::core::build_steps::tool::LldWrapper { compiler: build_compiler, target: target_compiler.host, }); diff --git a/src/bootstrap/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 05556d2f679..47f41ab288d 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -19,16 +19,16 @@ use std::process::Command; use object::read::archive::ArchiveFile; use object::BinaryFormat; -use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; -use crate::cache::{Interned, INTERNER}; -use crate::channel; -use crate::compile; -use crate::config::TargetSelection; -use crate::doc::DocumentationFormat; -use crate::llvm; -use crate::tarball::{GeneratedTarball, OverlayKind, Tarball}; -use crate::tool::{self, Tool}; -use crate::util::{exe, is_dylib, output, t, timeit}; +use crate::core::build_steps::compile; +use crate::core::build_steps::doc::DocumentationFormat; +use crate::core::build_steps::llvm; +use crate::core::build_steps::tool::{self, Tool}; +use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; +use crate::core::config::TargetSelection; +use crate::utils::cache::{Interned, INTERNER}; +use crate::utils::channel; +use crate::utils::helpers::{exe, is_dylib, output, t, timeit}; +use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball}; use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS}; pub fn pkgname(builder: &Builder<'_>, component: &str) -> String { @@ -104,7 +104,7 @@ impl Step for JsonDocs { /// Builds the `rust-docs-json` installer component. fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> { let host = self.host; - builder.ensure(crate::doc::Std::new( + builder.ensure(crate::core::build_steps::doc::Std::new( builder.top_stage, host, builder, @@ -488,7 +488,7 @@ impl Step for Rustc { let man_src = builder.src.join("src/doc/man"); let man_dst = image.join("share/man/man1"); - // don't use our `bootstrap::util::{copy, cp_r}`, because those try + // don't use our `bootstrap::{copy, cp_r}`, because those try // to hardlink, and we don't want to edit the source templates for file_entry in builder.read_dir(&man_src) { let page_src = file_entry.path(); @@ -1002,11 +1002,15 @@ impl Step for PlainSourceTarball { channel::write_commit_info_file(&plain_dst_src, info); } - // If we're building from git sources, we need to vendor a complete distribution. - if builder.rust_info().is_managed_git_subrepository() { - // Ensure we have the submodules checked out. - builder.update_submodule(Path::new("src/tools/cargo")); - builder.update_submodule(Path::new("src/tools/rust-analyzer")); + // If we're building from git or tarball sources, we need to vendor + // a complete distribution. + if builder.rust_info().is_managed_git_subrepository() + || builder.rust_info().is_from_tarball() + { + if builder.rust_info().is_managed_git_subrepository() { + // Ensure we have the submodules checked out. + builder.update_submodule(Path::new("src/tools/cargo")); + } // Vendor all Cargo dependencies let mut cmd = Command::new(&builder.initial_cargo); @@ -2056,7 +2060,7 @@ impl Step for LlvmTools { } } - builder.ensure(crate::llvm::Llvm { target }); + builder.ensure(crate::core::build_steps::llvm::Llvm { target }); let mut tarball = Tarball::new(builder, "llvm-tools", &target.triple); tarball.set_overlay(OverlayKind::LLVM); @@ -2115,10 +2119,10 @@ impl Step for RustDev { let mut tarball = Tarball::new(builder, "rust-dev", &target.triple); tarball.set_overlay(OverlayKind::LLVM); - builder.ensure(crate::llvm::Llvm { target }); + builder.ensure(crate::core::build_steps::llvm::Llvm { target }); // We want to package `lld` to use it with `download-ci-llvm`. - builder.ensure(crate::llvm::Lld { target }); + builder.ensure(crate::core::build_steps::llvm::Lld { target }); let src_bindir = builder.llvm_out(target).join("bin"); // If updating this list, you likely want to change diff --git a/src/bootstrap/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 505f06ed12d..628a4ece8e9 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -10,13 +10,13 @@ use std::fs; use std::path::{Path, PathBuf}; -use crate::builder::crate_description; -use crate::builder::{Alias, Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; -use crate::cache::{Interned, INTERNER}; -use crate::compile; -use crate::config::{Config, TargetSelection}; -use crate::tool::{self, prepare_tool_cargo, SourceType, Tool}; -use crate::util::{dir_is_empty, symlink_dir, t, up_to_date}; +use crate::core::build_steps::compile; +use crate::core::build_steps::tool::{self, prepare_tool_cargo, SourceType, Tool}; +use crate::core::builder::crate_description; +use crate::core::builder::{Alias, Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; +use crate::core::config::{Config, TargetSelection}; +use crate::utils::cache::{Interned, INTERNER}; +use crate::utils::helpers::{dir_is_empty, symlink_dir, t, up_to_date}; use crate::Mode; macro_rules! submodule_helper { diff --git a/src/bootstrap/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 11f2762f766..0e260e69c85 100644 --- a/src/bootstrap/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -1,7 +1,7 @@ //! Runs rustfmt on the repository. -use crate::builder::Builder; -use crate::util::{output, program_out_of_date, t}; +use crate::core::builder::Builder; +use crate::utils::helpers::{output, program_out_of_date, t}; use build_helper::ci::CiEnv; use build_helper::git::get_git_modified_files; use ignore::WalkBuilder; diff --git a/src/bootstrap/install.rs b/src/bootstrap/src/core/build_steps/install.rs index 885b3a78236..391995b7c3b 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -8,15 +8,13 @@ use std::fs; use std::path::{Component, Path, PathBuf}; use std::process::Command; -use crate::util::t; - -use crate::dist; -use crate::tarball::GeneratedTarball; +use crate::core::build_steps::dist; +use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; +use crate::core::config::{Config, TargetSelection}; +use crate::utils::helpers::t; +use crate::utils::tarball::GeneratedTarball; use crate::{Compiler, Kind}; -use crate::builder::{Builder, RunConfig, ShouldRun, Step}; -use crate::config::{Config, TargetSelection}; - #[cfg(target_os = "illumos")] const SHELL: &str = "bash"; #[cfg(not(target_os = "illumos"))] diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 4556831589b..24351118a5a 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -16,11 +16,10 @@ use std::io; use std::path::{Path, PathBuf}; use std::process::Command; -use crate::builder::{Builder, RunConfig, ShouldRun, Step}; -use crate::channel; -use crate::config::{Config, TargetSelection}; -use crate::util::get_clang_cl_resource_dir; -use crate::util::{self, exe, output, t, up_to_date}; +use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; +use crate::core::config::{Config, TargetSelection}; +use crate::utils::channel; +use crate::utils::helpers::{self, exe, get_clang_cl_resource_dir, output, t, up_to_date}; use crate::{CLang, GitRepo, Kind}; use build_helper::ci::CiEnv; @@ -281,7 +280,7 @@ impl Step for Llvm { let _guard = builder.msg_unstaged(Kind::Build, "LLVM", target); t!(stamp.remove()); - let _time = util::timeit(&builder); + let _time = helpers::timeit(&builder); t!(fs::create_dir_all(&out_dir)); // https://llvm.org/docs/CMake.html @@ -410,7 +409,7 @@ impl Step for Llvm { let mut enabled_llvm_projects = Vec::new(); - if util::forcing_clang_based_tests() { + if helpers::forcing_clang_based_tests() { enabled_llvm_projects.push("clang"); enabled_llvm_projects.push("compiler-rt"); } @@ -528,8 +527,12 @@ impl Step for Llvm { // If the shared library exists in LLVM's `/build/lib/` or `/lib/` folders, strip its // debuginfo. - crate::compile::strip_debug(builder, target, &out_dir.join("lib").join(&lib_name)); - crate::compile::strip_debug( + crate::core::build_steps::compile::strip_debug( + builder, + target, + &out_dir.join("lib").join(&lib_name), + ); + crate::core::build_steps::compile::strip_debug( builder, target, &out_dir.join("build").join("lib").join(&lib_name), @@ -846,7 +849,7 @@ impl Step for Lld { } let _guard = builder.msg_unstaged(Kind::Build, "LLD", target); - let _time = util::timeit(&builder); + let _time = helpers::timeit(&builder); t!(fs::create_dir_all(&out_dir)); let mut cfg = cmake::Config::new(builder.src.join("src/llvm-project/lld")); @@ -877,7 +880,7 @@ impl Step for Lld { // `LD_LIBRARY_PATH` overrides) // if builder.config.rpath_enabled(target) - && util::use_host_linker(target) + && helpers::use_host_linker(target) && builder.config.llvm_link_shared() && target.contains("linux") { @@ -970,7 +973,7 @@ impl Step for Sanitizers { let _guard = builder.msg_unstaged(Kind::Build, "sanitizers", self.target); t!(stamp.remove()); - let _time = util::timeit(&builder); + let _time = helpers::timeit(&builder); let mut cfg = cmake::Config::new(&compiler_rt_dir); cfg.profile("Release"); diff --git a/src/bootstrap/src/core/build_steps/mod.rs b/src/bootstrap/src/core/build_steps/mod.rs new file mode 100644 index 00000000000..50d83789be8 --- /dev/null +++ b/src/bootstrap/src/core/build_steps/mod.rs @@ -0,0 +1,15 @@ +pub(crate) mod check; +pub(crate) mod clean; +pub(crate) mod compile; +pub(crate) mod dist; +pub(crate) mod doc; +pub(crate) mod format; +pub(crate) mod install; +pub(crate) mod llvm; +pub(crate) mod run; +pub(crate) mod setup; +pub(crate) mod suggest; +pub(crate) mod synthetic_targets; +pub(crate) mod test; +pub(crate) mod tool; +pub(crate) mod toolstate; diff --git a/src/bootstrap/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 4082f5bb9b1..d1d6b7e869e 100644 --- a/src/bootstrap/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -1,15 +1,13 @@ use std::path::PathBuf; use std::process::Command; -use clap_complete::shells; - -use crate::builder::{Builder, RunConfig, ShouldRun, Step}; -use crate::config::TargetSelection; -use crate::dist::distdir; -use crate::flags::get_completion; -use crate::test; -use crate::tool::{self, SourceType, Tool}; -use crate::util::output; +use crate::core::build_steps::dist::distdir; +use crate::core::build_steps::test; +use crate::core::build_steps::tool::{self, SourceType, Tool}; +use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; +use crate::core::config::flags::get_completion; +use crate::core::config::TargetSelection; +use crate::utils::helpers::output; use crate::Mode; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -268,23 +266,29 @@ impl Step for GenerateWindowsSys { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct GenerateCompletions; +macro_rules! generate_completions { + ( $( ( $shell:ident, $filename:expr ) ),* ) => { + $( + if let Some(comp) = get_completion($shell, &$filename) { + std::fs::write(&$filename, comp).expect(&format!("writing {} completion", stringify!($shell))); + } + )* + }; +} + impl Step for GenerateCompletions { type Output = (); /// Uses `clap_complete` to generate shell completions. fn run(self, builder: &Builder<'_>) { - // FIXME(clubby789): enable zsh when clap#4898 is fixed - let [bash, fish, powershell] = ["x.py.sh", "x.py.fish", "x.py.ps1"] - .map(|filename| builder.src.join("src/etc/completions").join(filename)); - if let Some(comp) = get_completion(shells::Bash, &bash) { - std::fs::write(&bash, comp).expect("writing bash completion"); - } - if let Some(comp) = get_completion(shells::Fish, &fish) { - std::fs::write(&fish, comp).expect("writing fish completion"); - } - if let Some(comp) = get_completion(shells::PowerShell, &powershell) { - std::fs::write(&powershell, comp).expect("writing powershell completion"); - } + use clap_complete::shells::{Bash, Fish, PowerShell, Zsh}; + + generate_completions!( + (Bash, builder.src.join("src/etc/completions/x.py.sh")), + (Zsh, builder.src.join("src/etc/completions/x.py.zsh")), + (Fish, builder.src.join("src/etc/completions/x.py.fish")), + (PowerShell, builder.src.join("src/etc/completions/x.py.ps1")) + ); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { diff --git a/src/bootstrap/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 14ec33147fb..ebe093674fc 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -1,4 +1,4 @@ -use crate::builder::{Builder, RunConfig, ShouldRun, Step}; +use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::Config; use crate::{t, CONFIG_CHANGE_HISTORY}; use sha2::Digest; @@ -12,6 +12,7 @@ use std::str::FromStr; use std::{fmt, fs, io}; #[cfg(test)] +#[path = "../../tests/setup.rs"] mod tests; #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] @@ -35,7 +36,7 @@ static SETTINGS_HASHES: &[&str] = &[ "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923", "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a", ]; -static RUST_ANALYZER_SETTINGS: &str = include_str!("../etc/rust_analyzer_settings.json"); +static RUST_ANALYZER_SETTINGS: &str = include_str!("../../../../etc/rust_analyzer_settings.json"); impl Profile { fn include_path(&self, src_path: &Path) -> PathBuf { diff --git a/src/bootstrap/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs index f225104bda9..82fb10cebe0 100644 --- a/src/bootstrap/suggest.rs +++ b/src/bootstrap/src/core/build_steps/suggest.rs @@ -1,12 +1,11 @@ #![cfg_attr(feature = "build-metrics", allow(unused))] -use std::str::FromStr; - -use std::path::PathBuf; - use clap::Parser; +use std::path::PathBuf; +use std::str::FromStr; -use crate::{builder::Builder, tool::Tool}; +use crate::core::build_steps::tool::Tool; +use crate::core::builder::Builder; /// Suggests a list of possible `x.py` commands to run based on modified files in branch. pub fn suggest(builder: &Builder<'_>, run: bool) { @@ -62,7 +61,7 @@ pub fn suggest(builder: &Builder<'_>, run: bool) { for sug in suggestions { let mut build: crate::Build = builder.build.clone(); build.config.paths = sug.2; - build.config.cmd = crate::flags::Flags::parse_from(["x.py", sug.0]).cmd; + build.config.cmd = crate::core::config::flags::Flags::parse_from(["x.py", sug.0]).cmd; if let Some(stage) = sug.1 { build.config.stage = stage; } diff --git a/src/bootstrap/synthetic_targets.rs b/src/bootstrap/src/core/build_steps/synthetic_targets.rs index 7eeac9025c9..d2c65b740da 100644 --- a/src/bootstrap/synthetic_targets.rs +++ b/src/bootstrap/src/core/build_steps/synthetic_targets.rs @@ -7,8 +7,8 @@ //! one of the target specs already defined in this module, or create new ones by adding a new step //! that calls create_synthetic_target. -use crate::builder::{Builder, ShouldRun, Step}; -use crate::config::TargetSelection; +use crate::core::builder::{Builder, ShouldRun, Step}; +use crate::core::config::TargetSelection; use crate::Compiler; use std::process::{Command, Stdio}; @@ -76,7 +76,7 @@ fn create_synthetic_target( std::fs::write(&path, &serde_json::to_vec_pretty(&spec).unwrap()).unwrap(); let target = TargetSelection::create_synthetic(&name, path.to_str().unwrap()); - crate::cc_detect::find_target(builder, target); + crate::utils::cc_detect::find_target(builder, target); target } diff --git a/src/bootstrap/test.rs b/src/bootstrap/src/core/build_steps/test.rs index ba030f0f525..831a86940fb 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -13,21 +13,24 @@ use std::process::{Command, Stdio}; use clap_complete::shells; -use crate::builder::crate_description; -use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; -use crate::cache::Interned; -use crate::cache::INTERNER; -use crate::compile; -use crate::config::TargetSelection; -use crate::dist; -use crate::doc::DocumentationFormat; -use crate::flags::Subcommand; -use crate::llvm; -use crate::render_tests::add_flags_and_try_run_tests; -use crate::synthetic_targets::MirOptPanicAbortSyntheticTarget; -use crate::tool::{self, SourceType, Tool}; -use crate::toolstate::ToolState; -use crate::util::{self, add_link_lib_path, dylib_path, dylib_path_var, output, t, up_to_date}; +use crate::core::build_steps::compile; +use crate::core::build_steps::dist; +use crate::core::build_steps::doc::DocumentationFormat; +use crate::core::build_steps::llvm; +use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget; +use crate::core::build_steps::tool::{self, SourceType, Tool}; +use crate::core::build_steps::toolstate::ToolState; +use crate::core::builder::crate_description; +use crate::core::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; +use crate::core::config::flags::get_completion; +use crate::core::config::flags::Subcommand; +use crate::core::config::TargetSelection; +use crate::utils; +use crate::utils::cache::{Interned, INTERNER}; +use crate::utils::helpers::{ + self, add_link_lib_path, dylib_path, dylib_path_var, output, t, up_to_date, +}; +use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests}; use crate::{envify, CLang, DocTests, GitRepo, Mode}; const ADB_TEST_DIR: &str = "/data/local/tmp/work"; @@ -167,7 +170,7 @@ You can skip linkcheck with --skip src/tools/linkchecker" // Run the linkchecker. let _guard = builder.msg(Kind::Test, compiler.stage, "Linkcheck", bootstrap_host, bootstrap_host); - let _time = util::timeit(&builder); + let _time = helpers::timeit(&builder); builder.run_delaying_failure(linkchecker.arg(builder.out.join(host.triple).join("doc"))); } @@ -219,7 +222,11 @@ impl Step for HtmlCheck { } // Ensure that a few different kinds of documentation are available. builder.default_doc(&[]); - builder.ensure(crate::doc::Rustc::new(builder.top_stage, self.target, builder)); + builder.ensure(crate::core::build_steps::doc::Rustc::new( + builder.top_stage, + self.target, + builder, + )); builder.run_delaying_failure( builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target)), @@ -260,7 +267,7 @@ impl Step for Cargotest { let out_dir = builder.out.join("ct"); t!(fs::create_dir_all(&out_dir)); - let _time = util::timeit(&builder); + let _time = helpers::timeit(&builder); let mut cmd = builder.tool_cmd(Tool::CargoTest); builder.run_delaying_failure( cmd.arg(&cargo) @@ -328,7 +335,7 @@ impl Step for Cargo { builder, ); - let _time = util::timeit(&builder); + let _time = helpers::timeit(&builder); add_flags_and_try_run_tests(builder, &mut cargo); } } @@ -642,7 +649,7 @@ impl Step for Miri { // does not understand the flags added by `add_flags_and_try_run_test`. let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", compiler, target, builder); { - let _time = util::timeit(&builder); + let _time = helpers::timeit(&builder); builder.run(&mut cargo); } @@ -658,7 +665,7 @@ impl Step for Miri { let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", compiler, target, builder); { - let _time = util::timeit(&builder); + let _time = helpers::timeit(&builder); builder.run(&mut cargo); } } @@ -698,7 +705,7 @@ impl Step for Miri { let mut cargo = Command::from(cargo); { - let _time = util::timeit(&builder); + let _time = helpers::timeit(&builder); builder.run(&mut cargo); } } @@ -859,7 +866,7 @@ impl Step for RustdocTheme { if builder.is_fuse_ld_lld(self.compiler.host) { cmd.env( "RUSTDOC_LLD_NO_THREADS", - util::lld_flag_no_threads(self.compiler.host.contains("windows")), + helpers::lld_flag_no_threads(self.compiler.host.contains("windows")), ); } builder.run_delaying_failure(&mut cmd); @@ -900,7 +907,8 @@ impl Step for RustdocJSStd { .arg("--test-folder") .arg(builder.src.join("tests/rustdoc-js-std")); for path in &builder.paths { - if let Some(p) = util::is_valid_test_suite_arg(path, "tests/rustdoc-js-std", builder) { + if let Some(p) = helpers::is_valid_test_suite_arg(path, "tests/rustdoc-js-std", builder) + { if !p.ends_with(".js") { eprintln!("A non-js file was given: `{}`", path.display()); panic!("Cannot run rustdoc-js-std tests"); @@ -908,7 +916,7 @@ impl Step for RustdocJSStd { command.arg("--test-file").arg(path); } } - builder.ensure(crate::doc::Std::new( + builder.ensure(crate::core::build_steps::doc::Std::new( builder.top_stage, self.target, builder, @@ -1035,7 +1043,7 @@ impl Step for RustdocGUI { .env("RUSTC", builder.rustc(self.compiler)); for path in &builder.paths { - if let Some(p) = util::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder) { + if let Some(p) = helpers::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder) { if !p.ends_with(".goml") { eprintln!("A non-goml file was given: `{}`", path.display()); panic!("Cannot run rustdoc-gui tests"); @@ -1058,7 +1066,7 @@ impl Step for RustdocGUI { cmd.arg("--npm").arg(npm); } - let _time = util::timeit(&builder); + let _time = helpers::timeit(&builder); let _guard = builder.msg_sysroot_tool( Kind::Test, self.compiler.stage, @@ -1066,7 +1074,7 @@ impl Step for RustdocGUI { self.compiler.host, self.target, ); - crate::render_tests::try_run_tests(builder, &mut cmd, true); + try_run_tests(builder, &mut cmd, true); } } @@ -1126,7 +1134,7 @@ help: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to ); crate::exit!(1); } - crate::format::format(&builder, !builder.config.cmd.bless(), &[]); + crate::core::build_steps::format::format(&builder, !builder.config.cmd.bless(), &[]); } builder.info("tidy check"); @@ -1135,13 +1143,14 @@ help: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to builder.ensure(ExpandYamlAnchors); builder.info("x.py completions check"); - let [bash, fish, powershell] = ["x.py.sh", "x.py.fish", "x.py.ps1"] + let [bash, zsh, fish, powershell] = ["x.py.sh", "x.py.zsh", "x.py.fish", "x.py.ps1"] .map(|filename| builder.src.join("src/etc/completions").join(filename)); if builder.config.cmd.bless() { - builder.ensure(crate::run::GenerateCompletions); - } else if crate::flags::get_completion(shells::Bash, &bash).is_some() - || crate::flags::get_completion(shells::Fish, &fish).is_some() - || crate::flags::get_completion(shells::PowerShell, &powershell).is_some() + builder.ensure(crate::core::build_steps::run::GenerateCompletions); + } else if get_completion(shells::Bash, &bash).is_some() + || get_completion(shells::Fish, &fish).is_some() + || get_completion(shells::PowerShell, &powershell).is_some() + || crate::flags::get_completion(shells::Zsh, &zsh).is_some() { eprintln!( "x.py completions were changed; run `x.py run generate-completions` to update them" @@ -1402,10 +1411,10 @@ impl Step for MirOpt { // have been detected by bootstrap if the target we're testing wasn't in the // --target flags. if !builder.cc.borrow().contains_key(&target_32bit) { - crate::cc_detect::find_target(builder, target_32bit); + utils::cc_detect::find_target(builder, target_32bit); } if !builder.cc.borrow().contains_key(&target_64bit) { - crate::cc_detect::find_target(builder, target_64bit); + utils::cc_detect::find_target(builder, target_64bit); } vec![target_32bit, target_64bit] @@ -1678,7 +1687,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the } } - if util::forcing_clang_based_tests() { + if helpers::forcing_clang_based_tests() { let clang_exe = builder.llvm_out(target).join("bin").join("clang"); cmd.arg("--run-clang-based-tests-with").arg(clang_exe); } @@ -1697,7 +1706,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the // Get test-args by striping suite path let mut test_args: Vec<&str> = paths .iter() - .filter_map(|p| util::is_valid_test_suite_arg(p, suite_path, builder)) + .filter_map(|p| helpers::is_valid_test_suite_arg(p, suite_path, builder)) .collect(); test_args.append(&mut builder.config.test_args()); @@ -1886,7 +1895,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the compiler.host, target, ); - crate::render_tests::try_run_tests(builder, &mut cmd, false); + try_run_tests(builder, &mut cmd, false); if let Some(compare_mode) = compare_mode { cmd.arg("--compare-mode").arg(compare_mode); @@ -1908,8 +1917,8 @@ note: if you're sure you want to do this, please open an issue as to why. In the "Check compiletest suite={} mode={} compare_mode={} ({} -> {})", suite, mode, compare_mode, &compiler.host, target )); - let _time = util::timeit(&builder); - crate::render_tests::try_run_tests(builder, &mut cmd, false); + let _time = helpers::timeit(&builder); + try_run_tests(builder, &mut cmd, false); } } } @@ -1980,7 +1989,7 @@ impl BookTest { compiler.host, compiler.host, ); - let _time = util::timeit(&builder); + let _time = helpers::timeit(&builder); let toolstate = if builder.run_delaying_failure(&mut rustbook_cmd) { ToolState::TestPass } else { @@ -2002,7 +2011,7 @@ impl BookTest { // Do a breadth-first traversal of the `src/doc` directory and just run // tests for all files that end in `*.md` let mut stack = vec![builder.src.join(self.path)]; - let _time = util::timeit(&builder); + let _time = helpers::timeit(&builder); let mut files = Vec::new(); while let Some(p) = stack.pop() { if p.is_dir() { @@ -2113,7 +2122,7 @@ impl Step for ErrorIndex { let guard = builder.msg(Kind::Test, compiler.stage, "error-index", compiler.host, compiler.host); - let _time = util::timeit(&builder); + let _time = helpers::timeit(&builder); builder.run_quiet(&mut tool); drop(guard); // The tests themselves need to link to std, so make sure it is @@ -2235,7 +2244,7 @@ fn run_cargo_test<'a>( ) -> bool { let mut cargo = prepare_cargo_test(cargo, libtest_args, crates, primary_crate, compiler, target, builder); - let _time = util::timeit(&builder); + let _time = helpers::timeit(&builder); let _group = description.into().and_then(|what| { builder.msg_sysroot_tool(Kind::Test, compiler.stage, what, compiler.host, target) }); @@ -2630,7 +2639,7 @@ impl Step for RemoteCopyLibs { for f in t!(builder.sysroot_libdir(compiler, target).read_dir()) { let f = t!(f); let name = f.file_name().into_string().unwrap(); - if util::is_dylib(&name) { + if helpers::is_dylib(&name) { builder.run(Command::new(&tool).arg("push").arg(f.path())); } } @@ -2675,7 +2684,9 @@ impl Step for Distcheck { .current_dir(&dir), ); builder.run( - Command::new(util::make(&builder.config.build.triple)).arg("check").current_dir(&dir), + Command::new(helpers::make(&builder.config.build.triple)) + .arg("check") + .current_dir(&dir), ); // Now make sure that rust-src has all of libstd's dependencies @@ -2832,7 +2843,7 @@ impl Step for LintDocs { /// Tests that the lint examples in the rustc book generate the correct /// lints and have the expected format. fn run(self, builder: &Builder<'_>) { - builder.ensure(crate::doc::RustcBook { + builder.ensure(crate::core::build_steps::doc::RustcBook { compiler: self.compiler, target: self.target, validate: true, @@ -2940,10 +2951,6 @@ impl Step for TestHelpers { let _guard = builder.msg_unstaged(Kind::Build, "test helpers", target); t!(fs::create_dir_all(&dst)); let mut cfg = cc::Build::new(); - // FIXME: Workaround for https://github.com/emscripten-core/emscripten/issues/9013 - if target.contains("emscripten") { - cfg.pic(false); - } // We may have found various cross-compilers a little differently due to our // extra configuration, so inform cc of these compilers. Note, though, that @@ -3055,7 +3062,7 @@ impl Step for CodegenCranelift { &compiler.host, target )); - let _time = util::timeit(&builder); + let _time = helpers::timeit(&builder); // FIXME handle vendoring for source tarballs before removing the --skip-test below let download_dir = builder.out.join("cg_clif_download"); diff --git a/src/bootstrap/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index f094dd9d7c9..5702fa62d7c 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -3,12 +3,12 @@ use std::fs; use std::path::PathBuf; use std::process::Command; -use crate::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step}; -use crate::channel::GitInfo; -use crate::compile; -use crate::config::TargetSelection; -use crate::toolstate::ToolState; -use crate::util::{add_dylib_path, exe, t}; +use crate::core::build_steps::compile; +use crate::core::build_steps::toolstate::ToolState; +use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step}; +use crate::core::config::TargetSelection; +use crate::utils::channel::GitInfo; +use crate::utils::helpers::{add_dylib_path, exe, t}; use crate::Compiler; use crate::Mode; use crate::{gha, Kind}; diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/src/core/build_steps/toolstate.rs index 308023537d5..f892577ccbf 100644 --- a/src/bootstrap/toolstate.rs +++ b/src/bootstrap/src/core/build_steps/toolstate.rs @@ -1,5 +1,5 @@ -use crate::builder::{Builder, RunConfig, ShouldRun, Step}; -use crate::util::t; +use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; +use crate::utils::helpers::t; use serde_derive::{Deserialize, Serialize}; use std::collections::HashMap; use std::env; diff --git a/src/bootstrap/builder.rs b/src/bootstrap/src/core/builder.rs index 46a62eed952..039a87e760d 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -12,20 +12,15 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::time::{Duration, Instant}; -use crate::cache::{Cache, Interned, INTERNER}; -use crate::config::{DryRun, SplitDebuginfo, TargetSelection}; -use crate::doc; -use crate::flags::{Color, Subcommand}; -use crate::install; -use crate::llvm; -use crate::run; -use crate::setup; -use crate::test; -use crate::tool::{self, SourceType}; -use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir, output, t}; +use crate::core::build_steps::llvm; +use crate::core::build_steps::tool::{self, SourceType}; +use crate::core::build_steps::{check, clean, compile, dist, doc, install, run, setup, test}; +use crate::core::config::flags::{Color, Subcommand}; +use crate::core::config::{DryRun, SplitDebuginfo, TargetSelection}; +use crate::utils::cache::{Cache, Interned, INTERNER}; +use crate::utils::helpers::{self, add_dylib_path, add_link_lib_path, exe, libdir, output, t}; +use crate::Crate; use crate::EXTRA_CHECK_CFGS; -use crate::{check, compile, Crate}; -use crate::{clean, dist}; use crate::{Build, CLang, DocTests, GitRepo, Mode}; pub use crate::Compiler; @@ -36,6 +31,10 @@ pub use crate::Compiler; use clap::ValueEnum; use once_cell::sync::{Lazy, OnceCell}; +#[cfg(test)] +#[path = "../tests/builder.rs"] +mod tests; + pub struct Builder<'a> { pub build: &'a Build, pub top_stage: u32, @@ -723,7 +722,7 @@ impl<'a> Builder<'a> { check::Bootstrap ), Kind::Test => describe!( - crate::toolstate::ToolStateCheck, + crate::core::build_steps::toolstate::ToolStateCheck, test::ExpandYamlAnchors, test::Tidy, test::Ui, @@ -1174,9 +1173,6 @@ impl<'a> Builder<'a> { if let Some(linker) = self.linker(compiler.host) { cmd.env("RUSTDOC_LINKER", linker); } - if self.is_fuse_ld_lld(compiler.host) { - cmd.env("RUSTDOC_FUSE_LD_LLD", "1"); - } cmd } @@ -1268,6 +1264,8 @@ impl<'a> Builder<'a> { let mut cargo = self.bare_cargo(compiler, mode, target, cmd); let out_dir = self.stage_out(compiler, mode); + let mut hostflags = HostFlags::default(); + // Codegen backends are not yet tracked by -Zbinary-dep-depinfo, // so we need to explicitly clear out if they've been updated. for backend in self.codegen_backends(compiler) { @@ -1298,8 +1296,8 @@ impl<'a> Builder<'a> { // See comment in rustc_llvm/build.rs for why this is necessary, largely llvm-config // needs to not accidentally link to libLLVM in stage0/lib. - cargo.env("REAL_LIBRARY_PATH_VAR", &util::dylib_path_var()); - if let Some(e) = env::var_os(util::dylib_path_var()) { + cargo.env("REAL_LIBRARY_PATH_VAR", &helpers::dylib_path_var()); + if let Some(e) = env::var_os(helpers::dylib_path_var()) { cargo.env("REAL_LIBRARY_PATH", e); } @@ -1312,7 +1310,7 @@ impl<'a> Builder<'a> { // rustc_llvm. But if LLVM is stale, that'll be a tiny amount // of work comparatively, and we'd likely need to rebuild it anyway, // so that's okay. - if crate::llvm::prebuilt_llvm_config(self, target).is_err() { + if crate::core::build_steps::llvm::prebuilt_llvm_config(self, target).is_err() { cargo.env("RUST_CHECK", "1"); } } @@ -1439,6 +1437,20 @@ impl<'a> Builder<'a> { } } + // FIXME(rust-lang/cargo#5754) we shouldn't be using special command arguments + // to the host invocation here, but rather Cargo should know what flags to pass rustc + // itself. + if stage == 0 { + hostflags.arg("--cfg=bootstrap"); + } + // Cargo doesn't pass RUSTFLAGS to proc_macros: + // https://github.com/rust-lang/cargo/issues/4423 + // Thus, if we are on stage 0, we explicitly set `--cfg=bootstrap`. + // We also declare that the flag is expected, which we need to do to not + // get warnings about it being unexpected. + hostflags.arg("-Zunstable-options"); + hostflags.arg("--check-cfg=values(bootstrap)"); + // FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`, // but this breaks CI. At the very least, stage0 `rustdoc` needs `--cfg bootstrap`. See // #71458. @@ -1630,7 +1642,7 @@ impl<'a> Builder<'a> { // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it // fun to pass a flag to a tool to pass a flag to pass a flag to a tool // to change a flag in a binary? - if self.config.rpath_enabled(target) && util::use_host_linker(target) { + if self.config.rpath_enabled(target) && helpers::use_host_linker(target) { let libdir = self.sysroot_libdir_relative(compiler).to_str().unwrap(); let rpath = if target.contains("apple") { // Note that we need to take one extra step on macOS to also pass @@ -1655,11 +1667,10 @@ impl<'a> Builder<'a> { } if let Some(host_linker) = self.linker(compiler.host) { - cargo.env("RUSTC_HOST_LINKER", host_linker); + hostflags.arg(format!("-Clinker={}", host_linker.display())); } if self.is_fuse_ld_lld(compiler.host) { - cargo.env("RUSTC_HOST_FUSE_LD_LLD", "1"); - cargo.env("RUSTDOC_FUSE_LD_LLD", "1"); + hostflags.arg("-Clink-args=-fuse-ld=lld"); } if let Some(target_linker) = self.linker(target) { @@ -1743,7 +1754,8 @@ impl<'a> Builder<'a> { } if let Some(x) = self.crt_static(compiler.host) { - cargo.env("RUSTC_HOST_CRT_STATIC", x.to_string()); + let sign = if x { "+" } else { "-" }; + hostflags.arg(format!("-Ctarget-feature={sign}crt-static")); } if let Some(map_to) = self.build.debuginfo_map_to(GitRepo::Rustc) { @@ -2055,7 +2067,7 @@ impl<'a> Builder<'a> { cargo.env("RUSTFLAGS", &rustc_args.join(" ")); } - Cargo { command: cargo, rustflags, rustdocflags, allow_features } + Cargo { command: cargo, rustflags, rustdocflags, hostflags, allow_features } } /// Ensure that a given step is built, returning its output. This will @@ -2184,9 +2196,6 @@ impl<'a> Builder<'a> { } } -#[cfg(test)] -mod tests; - /// Represents flag values in `String` form with whitespace delimiter to pass it to the compiler later. /// /// `-Z crate-attr` flags will be applied recursively on the target code using the `rustc_parse::parser::Parser`. @@ -2233,11 +2242,36 @@ impl Rustflags { } } +/// Flags that are passed to the `rustc` shim binary. +/// These flags will only be applied when compiling host code, i.e. when +/// `--target` is unset. +#[derive(Debug, Default)] +pub struct HostFlags { + rustc: Vec<String>, +} + +impl HostFlags { + const SEPARATOR: &'static str = " "; + + /// Adds a host rustc flag. + fn arg<S: Into<String>>(&mut self, flag: S) { + let value = flag.into().trim().to_string(); + assert!(!value.contains(Self::SEPARATOR)); + self.rustc.push(value); + } + + /// Encodes all the flags into a single string. + fn encode(self) -> String { + self.rustc.join(Self::SEPARATOR) + } +} + #[derive(Debug)] pub struct Cargo { command: Command, rustflags: Rustflags, rustdocflags: Rustflags, + hostflags: HostFlags, allow_features: String, } @@ -2309,6 +2343,11 @@ impl From<Cargo> for Command { cargo.command.env("RUSTDOCFLAGS", rustdocflags); } + let encoded_hostflags = cargo.hostflags.encode(); + if !encoded_hostflags.is_empty() { + cargo.command.env("RUSTC_HOST_FLAGS", encoded_hostflags); + } + if !cargo.allow_features.is_empty() { cargo.command.env("RUSTC_ALLOW_FEATURES", cargo.allow_features); } diff --git a/src/bootstrap/config.rs b/src/bootstrap/src/core/config/config.rs index 1755c3166de..7ca1bbad968 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -4,6 +4,7 @@ //! how the build runs. #[cfg(test)] +#[path = "../../tests/config.rs"] mod tests; use std::cell::{Cell, RefCell}; @@ -17,19 +18,20 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::str::FromStr; -use crate::cache::{Interned, INTERNER}; -use crate::cc_detect::{ndk_compiler, Language}; -use crate::channel::{self, GitInfo}; -use crate::compile::CODEGEN_BACKEND_PREFIX; -pub use crate::flags::Subcommand; -use crate::flags::{Color, Flags, Warnings}; -use crate::util::{exe, output, t}; +use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX; +use crate::core::config::flags::{Color, Flags, Warnings}; +use crate::utils::cache::{Interned, INTERNER}; +use crate::utils::cc_detect::{ndk_compiler, Language}; +use crate::utils::channel::{self, GitInfo}; +use crate::utils::helpers::{exe, output, t}; use build_helper::exit; use once_cell::sync::OnceCell; use semver::Version; use serde::{Deserialize, Deserializer}; use serde_derive::Deserialize; +pub use crate::core::config::flags::Subcommand; + macro_rules! check_ci_llvm { ($name:expr) => { assert!( @@ -234,6 +236,7 @@ pub struct Config { pub llvm_profile_use: Option<String>, pub llvm_profile_generate: bool, pub llvm_libunwind_default: Option<LlvmLibunwind>, + pub enable_bolt_settings: bool, pub reproducible_artifacts: Vec<String>, @@ -546,7 +549,7 @@ impl Target { /// `Config` structure. #[derive(Deserialize, Default)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] -struct TomlConfig { +pub(crate) struct TomlConfig { changelog_seen: Option<usize>, // FIXME: Deprecated field. Remove it at 2024. change_id: Option<usize>, build: Option<Build>, @@ -1128,6 +1131,7 @@ impl Config { config.free_args = std::mem::take(&mut flags.free_args); config.llvm_profile_use = flags.llvm_profile_use; config.llvm_profile_generate = flags.llvm_profile_generate; + config.enable_bolt_settings = flags.enable_bolt_settings; // Infer the rest of the configuration. @@ -1267,7 +1271,7 @@ impl Config { // To avoid writing to random places on the file system, `config.out` needs to be an absolute path. if !config.out.is_absolute() { // `canonicalize` requires the path to already exist. Use our vendored copy of `absolute` instead. - config.out = crate::util::absolute(&config.out); + config.out = crate::utils::helpers::absolute(&config.out); } config.initial_rustc = if let Some(rustc) = build.rustc { @@ -1525,11 +1529,12 @@ impl Config { config.llvm_from_ci = match llvm.download_ci_llvm { Some(StringOrBool::String(s)) => { assert_eq!(s, "if-available", "unknown option `{s}` for download-ci-llvm"); - crate::llvm::is_ci_llvm_available(&config, asserts) + crate::core::build_steps::llvm::is_ci_llvm_available(&config, asserts) } Some(StringOrBool::Bool(b)) => b, None => { - config.channel == "dev" && crate::llvm::is_ci_llvm_available(&config, asserts) + config.channel == "dev" + && crate::core::build_steps::llvm::is_ci_llvm_available(&config, asserts) } }; @@ -1571,8 +1576,8 @@ impl Config { config.llvm_link_shared.set(Some(true)); } } else { - config.llvm_from_ci = - config.channel == "dev" && crate::llvm::is_ci_llvm_available(&config, false); + config.llvm_from_ci = config.channel == "dev" + && crate::core::build_steps::llvm::is_ci_llvm_available(&config, false); } if let Some(t) = toml.target { diff --git a/src/bootstrap/flags.rs b/src/bootstrap/src/core/config/flags.rs index e0291e407b3..dea55303544 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -7,9 +7,9 @@ use std::path::{Path, PathBuf}; use clap::{CommandFactory, Parser, ValueEnum}; -use crate::builder::{Builder, Kind}; -use crate::config::{target_selection_list, Config, TargetSelectionList}; -use crate::setup::Profile; +use crate::core::build_steps::setup::Profile; +use crate::core::builder::{Builder, Kind}; +use crate::core::config::{target_selection_list, Config, TargetSelectionList}; use crate::{Build, DocTests}; #[derive(Copy, Clone, Default, Debug, ValueEnum)] @@ -152,6 +152,9 @@ pub struct Flags { /// generate PGO profile with llvm built for rustc #[arg(global(true), long)] pub llvm_profile_generate: bool, + /// Enable BOLT link flags + #[arg(global(true), long)] + pub enable_bolt_settings: bool, /// Additional reproducible artifacts that should be added to the reproducible artifacts archive. #[arg(global(true), long)] pub reproducible_artifact: Vec<String>, diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs new file mode 100644 index 00000000000..9c6861826d6 --- /dev/null +++ b/src/bootstrap/src/core/config/mod.rs @@ -0,0 +1,4 @@ +pub(crate) mod config; +pub(crate) mod flags; + +pub use config::*; diff --git a/src/bootstrap/download.rs b/src/bootstrap/src/core/download.rs index 8e9614ec89a..5541a2f3e35 100644 --- a/src/bootstrap/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -11,13 +11,10 @@ use build_helper::ci::CiEnv; use once_cell::sync::OnceCell; use xz2::bufread::XzDecoder; -use crate::{ - config::RustfmtMetadata, - llvm::detect_llvm_sha, - t, - util::{check_run, exe, program_out_of_date}, - Config, -}; +use crate::core::build_steps::llvm::detect_llvm_sha; +use crate::core::config::RustfmtMetadata; +use crate::utils::helpers::{check_run, exe, program_out_of_date}; +use crate::{t, Config}; static SHOULD_FIX_BINS_AND_DYLIBS: OnceCell<bool> = OnceCell::new(); @@ -320,25 +317,43 @@ impl Config { } /// Returns whether the SHA256 checksum of `path` matches `expected`. - fn verify(&self, path: &Path, expected: &str) -> bool { + pub(crate) fn verify(&self, path: &Path, expected: &str) -> bool { use sha2::Digest; self.verbose(&format!("verifying {}", path.display())); + + if self.dry_run() { + return false; + } + let mut hasher = sha2::Sha256::new(); - // FIXME: this is ok for rustfmt (4.1 MB large at time of writing), but it seems memory-intensive for rustc and larger components. - // Consider using streaming IO instead? - let contents = if self.dry_run() { vec![] } else { t!(fs::read(path)) }; - hasher.update(&contents); - let found = hex::encode(hasher.finalize().as_slice()); - let verified = found == expected; - if !verified && !self.dry_run() { + + let file = t!(File::open(path)); + let mut reader = BufReader::new(file); + + loop { + let buffer = t!(reader.fill_buf()); + let l = buffer.len(); + // break if EOF + if l == 0 { + break; + } + hasher.update(buffer); + reader.consume(l); + } + + let checksum = hex::encode(hasher.finalize().as_slice()); + let verified = checksum == expected; + + if !verified { println!( "invalid checksum: \n\ - found: {found}\n\ + found: {checksum}\n\ expected: {expected}", ); } - return verified; + + verified } } diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/src/core/metadata.rs index 3b20ceac875..5802082326a 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/src/core/metadata.rs @@ -3,8 +3,8 @@ use std::process::Command; use serde_derive::Deserialize; -use crate::cache::INTERNER; -use crate::util::output; +use crate::utils::cache::INTERNER; +use crate::utils::helpers::output; use crate::{t, Build, Crate}; /// For more information, see the output of diff --git a/src/bootstrap/src/core/mod.rs b/src/bootstrap/src/core/mod.rs new file mode 100644 index 00000000000..9e18d6704d4 --- /dev/null +++ b/src/bootstrap/src/core/mod.rs @@ -0,0 +1,6 @@ +pub(crate) mod build_steps; +pub(crate) mod builder; +pub(crate) mod config; +pub(crate) mod download; +pub(crate) mod metadata; +pub(crate) mod sanity; diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/src/core/sanity.rs index 0febdf250d3..eec3be66a12 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -15,9 +15,9 @@ use std::fs; use std::path::PathBuf; use std::process::Command; -use crate::cache::INTERNER; -use crate::config::Target; -use crate::util::output; +use crate::core::config::Target; +use crate::utils::cache::INTERNER; +use crate::utils::helpers::output; use crate::Build; pub struct Finder { diff --git a/src/bootstrap/lib.rs b/src/bootstrap/src/lib.rs index 5c78015e560..97c743074af 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -28,70 +28,28 @@ use std::str; use build_helper::ci::{gha, CiEnv}; use build_helper::exit; -use channel::GitInfo; -use config::{DryRun, Target}; use filetime::FileTime; use once_cell::sync::OnceCell; - -use crate::builder::Kind; -use crate::config::{LlvmLibunwind, TargetSelection}; -use crate::util::{ - dir_is_empty, exe, libdir, mtime, output, run, run_suppressed, symlink_dir, try_run_suppressed, +use termcolor::{ColorChoice, StandardStream, WriteColor}; +use utils::channel::GitInfo; + +use crate::core::builder; +use crate::core::builder::Kind; +use crate::core::config::flags; +use crate::core::config::{DryRun, Target}; +use crate::core::config::{LlvmLibunwind, TargetSelection}; +use crate::utils::cache::{Interned, INTERNER}; +use crate::utils::helpers::{ + self, dir_is_empty, exe, libdir, mtime, output, run, run_suppressed, symlink_dir, + try_run_suppressed, }; -mod builder; -mod cache; -mod cc_detect; -mod channel; -mod check; -mod clean; -mod compile; -mod config; -mod dist; -mod doc; -mod download; -mod flags; -mod format; -mod install; -mod llvm; -mod metadata; -mod render_tests; -mod run; -mod sanity; -mod setup; -mod suggest; -mod synthetic_targets; -mod tarball; -mod test; -mod tool; -mod toolstate; -pub mod util; - -#[cfg(feature = "build-metrics")] -mod metrics; - -#[cfg(windows)] -mod job; - -#[cfg(all(unix, not(target_os = "haiku")))] -mod job { - pub unsafe fn setup(build: &mut crate::Build) { - if build.config.low_priority { - libc::setpriority(libc::PRIO_PGRP as _, 0, 10); - } - } -} - -#[cfg(any(target_os = "haiku", target_os = "hermit", not(any(unix, windows))))] -mod job { - pub unsafe fn setup(_build: &mut crate::Build) {} -} +mod core; +mod utils; -pub use crate::builder::PathSet; -use crate::cache::{Interned, INTERNER}; -pub use crate::config::Config; -pub use crate::flags::Subcommand; -use termcolor::{ColorChoice, StandardStream, WriteColor}; +pub use crate::core::builder::PathSet; +pub use crate::core::config::flags::Subcommand; +pub use crate::core::config::Config; const LLVM_TOOLS: &[&str] = &[ "llvm-cov", // used to generate coverage report @@ -138,18 +96,9 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &str, Option<&[&'static str]>)] = &[ (Some(Mode::Std), "freebsd13", None), (Some(Mode::Std), "backtrace_in_libstd", None), /* Extra values not defined in the built-in targets yet, but used in std */ - // #[cfg(bootstrap)] - (Some(Mode::Std), "target_vendor", Some(&["unikraft"])), (Some(Mode::Std), "target_env", Some(&["libnx"])), - // #[cfg(bootstrap)] hurd - (Some(Mode::Std), "target_os", Some(&["teeos", "hurd"])), - (Some(Mode::Rustc), "target_os", Some(&["hurd"])), - // #[cfg(bootstrap)] mips32r6, mips64r6 - ( - Some(Mode::Std), - "target_arch", - Some(&["asmjs", "spirv", "nvptx", "xtensa", "mips32r6", "mips64r6", "csky"]), - ), + // (Some(Mode::Std), "target_os", Some(&[])), + (Some(Mode::Std), "target_arch", Some(&["asmjs", "spirv", "nvptx", "xtensa"])), /* Extra names used by dependencies */ // FIXME: Used by serde_json, but we should not be triggering on external dependencies. (Some(Mode::Rustc), "no_btreemap_remove_entry", None), @@ -219,12 +168,12 @@ pub struct Build { src: PathBuf, out: PathBuf, bootstrap_out: PathBuf, - cargo_info: channel::GitInfo, - rust_analyzer_info: channel::GitInfo, - clippy_info: channel::GitInfo, - miri_info: channel::GitInfo, - rustfmt_info: channel::GitInfo, - in_tree_llvm_info: channel::GitInfo, + cargo_info: GitInfo, + rust_analyzer_info: GitInfo, + clippy_info: GitInfo, + miri_info: GitInfo, + rustfmt_info: GitInfo, + in_tree_llvm_info: GitInfo, local_rebuild: bool, fail_fast: bool, doc_tests: DocTests, @@ -257,7 +206,7 @@ pub struct Build { prerelease_version: Cell<Option<u32>>, #[cfg(feature = "build-metrics")] - metrics: metrics::BuildMetrics, + metrics: crate::utils::metrics::BuildMetrics, } #[derive(Debug, Clone)] @@ -368,6 +317,10 @@ impl Build { // https://github.com/rust-lang/rust/blob/a8a33cf27166d3eabaffc58ed3799e054af3b0c6/src/bootstrap/bootstrap.py#L796-L797 let is_sudo = match env::var_os("SUDO_USER") { Some(_sudo_user) => { + // SAFETY: getuid() system call is always successful and no return value is reserved + // to indicate an error. + // + // For more context, see https://man7.org/linux/man-pages/man2/geteuid.2.html let uid = unsafe { libc::getuid() }; uid == 0 } @@ -377,16 +330,15 @@ impl Build { let is_sudo = false; let omit_git_hash = config.omit_git_hash; - let rust_info = channel::GitInfo::new(omit_git_hash, &src); - let cargo_info = channel::GitInfo::new(omit_git_hash, &src.join("src/tools/cargo")); - let rust_analyzer_info = - channel::GitInfo::new(omit_git_hash, &src.join("src/tools/rust-analyzer")); - let clippy_info = channel::GitInfo::new(omit_git_hash, &src.join("src/tools/clippy")); - let miri_info = channel::GitInfo::new(omit_git_hash, &src.join("src/tools/miri")); - let rustfmt_info = channel::GitInfo::new(omit_git_hash, &src.join("src/tools/rustfmt")); + let rust_info = GitInfo::new(omit_git_hash, &src); + let cargo_info = GitInfo::new(omit_git_hash, &src.join("src/tools/cargo")); + let rust_analyzer_info = GitInfo::new(omit_git_hash, &src.join("src/tools/rust-analyzer")); + let clippy_info = GitInfo::new(omit_git_hash, &src.join("src/tools/clippy")); + let miri_info = GitInfo::new(omit_git_hash, &src.join("src/tools/miri")); + let rustfmt_info = GitInfo::new(omit_git_hash, &src.join("src/tools/rustfmt")); // we always try to use git for LLVM builds - let in_tree_llvm_info = channel::GitInfo::new(false, &src.join("src/llvm-project")); + let in_tree_llvm_info = GitInfo::new(false, &src.join("src/llvm-project")); let initial_target_libdir_str = if config.dry_run() { "/dummy/lib/path/to/lib/".to_string() @@ -479,7 +431,7 @@ impl Build { prerelease_version: Cell::new(None), #[cfg(feature = "build-metrics")] - metrics: metrics::BuildMetrics::init(), + metrics: crate::utils::metrics::BuildMetrics::init(), }; // If local-rust is the same major.minor as the current version, then force a @@ -498,7 +450,7 @@ impl Build { } build.verbose("finding compilers"); - cc_detect::find(&build); + utils::cc_detect::find(&build); // When running `setup`, the profile is about to change, so any requirements we have now may // be different on the next invocation. Don't check for them until the next time x.py is // run. This is ok because `setup` never runs any build commands, so it won't fail if commands are missing. @@ -506,7 +458,7 @@ impl Build { // Similarly, for `setup` we don't actually need submodules or cargo metadata. if !matches!(build.config.cmd, Subcommand::Setup { .. }) { build.verbose("running sanity check"); - sanity::check(&mut build); + crate::core::sanity::check(&mut build); // Make sure we update these before gathering metadata so we don't get an error about missing // Cargo.toml files. @@ -518,7 +470,7 @@ impl Build { build.update_existing_submodules(); build.verbose("learning about cargo"); - metadata::build(&mut build); + crate::core::metadata::build(&mut build); } // Make a symbolic link so we can use a consistent directory in the documentation. @@ -554,7 +506,7 @@ impl Build { // NOTE: The check for the empty directory is here because when running x.py the first time, // the submodule won't be checked out. Check it out now so we can build it. - if !channel::GitInfo::new(false, &absolute_path).is_managed_git_subrepository() + if !GitInfo::new(false, &absolute_path).is_managed_git_subrepository() && !dir_is_empty(&absolute_path) { return; @@ -668,7 +620,7 @@ impl Build { // Sample output: `submodule.src/rust-installer.path src/tools/rust-installer` let submodule = Path::new(line.splitn(2, ' ').nth(1).unwrap()); // Don't update the submodule unless it's already been cloned. - if channel::GitInfo::new(false, submodule).is_managed_git_subrepository() { + if GitInfo::new(false, submodule).is_managed_git_subrepository() { self.update_submodule(submodule); } } @@ -677,7 +629,7 @@ impl Build { /// Executes the entire build, as configured by the flags and configuration. pub fn build(&mut self) { unsafe { - job::setup(self); + crate::utils::job::setup(self); } // Download rustfmt early so that it can be used in rust-analyzer configs. @@ -686,10 +638,14 @@ impl Build { // hardcoded subcommands match &self.config.cmd { Subcommand::Format { check } => { - return format::format(&builder::Builder::new(&self), *check, &self.config.paths); + return core::build_steps::format::format( + &builder::Builder::new(&self), + *check, + &self.config.paths, + ); } Subcommand::Suggest { run } => { - return suggest::suggest(&builder::Builder::new(&self), *run); + return core::build_steps::suggest::suggest(&builder::Builder::new(&self), *run); } _ => (), } @@ -1070,7 +1026,7 @@ impl Build { /// Return a `Group` guard for a [`Step`] that is built for each `--stage`. /// - /// [`Step`]: crate::builder::Step + /// [`Step`]: crate::core::builder::Step #[must_use = "Groups should not be dropped until the Step finishes running"] #[track_caller] fn msg( @@ -1098,7 +1054,7 @@ impl Build { /// Return a `Group` guard for a [`Step`] that is only built once and isn't affected by `--stage`. /// - /// [`Step`]: crate::builder::Step + /// [`Step`]: crate::core::builder::Step #[must_use = "Groups should not be dropped until the Step finishes running"] #[track_caller] fn msg_unstaged( @@ -1258,7 +1214,7 @@ impl Build { // that are only existed in CXX libraries Some(self.cxx.borrow()[&target].path().into()) } else if target != self.config.build - && util::use_host_linker(target) + && helpers::use_host_linker(target) && !target.contains("msvc") { Some(self.cc(target)) @@ -1283,7 +1239,7 @@ impl Build { options[0] = Some("-Clink-arg=-fuse-ld=lld".to_string()); } - let no_threads = util::lld_flag_no_threads(target.contains("windows")); + let no_threads = helpers::lld_flag_no_threads(target.contains("windows")); options[1] = Some(format!("-Clink-arg=-Wl,{no_threads}")); } @@ -1423,7 +1379,7 @@ impl Build { fn extract_beta_rev_from_file<P: AsRef<Path>>(version_file: P) -> Option<String> { let version = fs::read_to_string(version_file).ok()?; - extract_beta_rev(&version) + helpers::extract_beta_rev(&version) } if let Some(s) = self.prerelease_version.get() { @@ -1737,7 +1693,7 @@ impl Build { /// Returns if config.ninja is enabled, and checks for ninja existence, /// exiting with a nicer error message if not. fn ninja(&self) -> bool { - let mut cmd_finder = crate::sanity::Finder::new(); + let mut cmd_finder = crate::core::sanity::Finder::new(); if self.config.ninja_in_file { // Some Linux distros rename `ninja` to `ninja-build`. @@ -1803,17 +1759,6 @@ to download LLVM rather than building it. } } -/// Extract the beta revision from the full version string. -/// -/// The full version string looks like "a.b.c-beta.y". And we need to extract -/// the "y" part from the string. -pub fn extract_beta_rev(version: &str) -> Option<String> { - let parts = version.splitn(2, "-beta.").collect::<Vec<_>>(); - let count = parts.get(1).and_then(|s| s.find(' ').map(|p| (&s[..p]).to_string())); - - count -} - #[cfg(unix)] fn chmod(path: &Path, perms: u32) { use std::os::unix::fs::*; diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/src/tests/builder.rs index 80e66622e8b..96139f7b099 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/src/tests/builder.rs @@ -1,6 +1,6 @@ use super::*; -use crate::config::{Config, DryRun, TargetSelection}; -use crate::doc::DocumentationFormat; +use crate::core::config::{Config, DryRun, TargetSelection}; +use crate::core::build_steps::doc::DocumentationFormat; use std::thread; fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config { @@ -22,7 +22,6 @@ fn configure_with_args(cmd: &[String], host: &[&str], target: &[&str]) -> Config ..Config::parse(&["check".to_owned()]) }); submodule_build.update_submodule(Path::new("src/doc/book")); - submodule_build.update_submodule(Path::new("src/tools/rust-analyzer")); config.submodules = Some(false); config.ninja_in_file = false; @@ -159,7 +158,7 @@ fn alias_and_path_for_library() { #[test] fn test_beta_rev_parsing() { - use crate::extract_beta_rev; + use crate::utils::helpers::extract_beta_rev; // single digit revision assert_eq!(extract_beta_rev("1.99.9-beta.7 (xxxxxx)"), Some("7".to_string())); @@ -175,7 +174,7 @@ fn test_beta_rev_parsing() { mod defaults { use super::{configure, first, run_build}; - use crate::builder::*; + use crate::core::builder::*; use crate::Config; use pretty_assertions::assert_eq; @@ -286,7 +285,7 @@ mod defaults { mod dist { use super::{first, run_build, Config}; - use crate::builder::*; + use crate::core::builder::*; use pretty_assertions::assert_eq; fn configure(host: &[&str], target: &[&str]) -> Config { diff --git a/src/bootstrap/config/tests.rs b/src/bootstrap/src/tests/config.rs index d091f33eee4..59bd52a94dc 100644 --- a/src/bootstrap/config/tests.rs +++ b/src/bootstrap/src/tests/config.rs @@ -1,9 +1,14 @@ -use crate::config::TomlConfig; - +use crate::core::config::TomlConfig; use super::{Config, Flags}; + use clap::CommandFactory; use serde::Deserialize; -use std::{env, path::Path}; +use std::{ + env, + fs::{remove_file, File}, + io::Write, + path::Path, +}; fn parse(config: &str) -> Config { Config::parse_inner(&["check".to_owned(), "--config=/does/not/exist".to_owned()], |&_| { @@ -13,7 +18,7 @@ fn parse(config: &str) -> Config { #[test] fn download_ci_llvm() { - if crate::llvm::is_ci_llvm_modified(&parse("")) { + if crate::core::build_steps::llvm::is_ci_llvm_modified(&parse("")) { eprintln!("Detected LLVM as non-available: running in CI and modified LLVM in this change"); return; } @@ -132,7 +137,7 @@ build-config = {} assert_eq!(config.change_id, Some(1), "setting top-level value"); assert_eq!( config.rust_lto, - crate::config::RustcLto::Fat, + crate::core::config::RustcLto::Fat, "setting string value without quotes" ); assert_eq!(config.gdb, Some("bar".into()), "setting string value with quotes"); @@ -170,7 +175,7 @@ fn profile_user_dist() { "profile = \"user\"".to_owned() } else { assert!(file.ends_with("config.dist.toml")); - std::fs::read_to_string(dbg!(file)).unwrap() + std::fs::read_to_string(file).unwrap() }; toml::from_str(&contents) .and_then(|table: toml::Value| TomlConfig::deserialize(table)) @@ -196,3 +201,19 @@ fn rust_optimize() { fn invalid_rust_optimize() { parse("rust.optimize = \"a\""); } + +#[test] +fn verify_file_integrity() { + let config = parse(""); + + let tempfile = config.tempdir().join(".tmp-test-file"); + File::create(&tempfile).unwrap().write_all(b"dummy value").unwrap(); + assert!(tempfile.exists()); + + assert!( + config + .verify(&tempfile, "7e255dd9542648a8779268a0f268b891a198e9828e860ed23f826440e786eae5") + ); + + remove_file(tempfile).unwrap(); +} diff --git a/src/bootstrap/setup/tests.rs b/src/bootstrap/src/tests/setup.rs index 0fe6e4a4644..0fe6e4a4644 100644 --- a/src/bootstrap/setup/tests.rs +++ b/src/bootstrap/src/tests/setup.rs diff --git a/src/bootstrap/bin/_helper.rs b/src/bootstrap/src/utils/bin_helpers.rs index 09aa471dba4..b9177c490ac 100644 --- a/src/bootstrap/bin/_helper.rs +++ b/src/bootstrap/src/utils/bin_helpers.rs @@ -1,8 +1,12 @@ +//! This file is meant to be included directly from bootstrap shims to avoid a +//! dependency on the bootstrap library. This reduces the binary size and +//! improves compilation time by reducing the linking time. + /// Parses the value of the "RUSTC_VERBOSE" environment variable and returns it as a `usize`. /// If it was not defined, returns 0 by default. /// /// Panics if "RUSTC_VERBOSE" is defined with the value that is not an unsigned integer. -fn parse_rustc_verbose() -> usize { +pub(crate) fn parse_rustc_verbose() -> usize { use std::str::FromStr; match std::env::var("RUSTC_VERBOSE") { @@ -14,11 +18,12 @@ fn parse_rustc_verbose() -> usize { /// Parses the value of the "RUSTC_STAGE" environment variable and returns it as a `String`. /// /// If "RUSTC_STAGE" was not set, the program will be terminated with 101. -fn parse_rustc_stage() -> String { +#[allow(unused)] +pub(crate) fn parse_rustc_stage() -> String { std::env::var("RUSTC_STAGE").unwrap_or_else(|_| { // Don't panic here; it's reasonable to try and run these shims directly. Give a helpful error instead. eprintln!("rustc shim: fatal: RUSTC_STAGE was not set"); eprintln!("rustc shim: note: use `x.py build -vvv` to see all environment variables set by bootstrap"); - exit(101); + std::process::exit(101); }) } diff --git a/src/bootstrap/cache.rs b/src/bootstrap/src/utils/cache.rs index 53e4ff03431..1b2aa9c234b 100644 --- a/src/bootstrap/cache.rs +++ b/src/bootstrap/src/utils/cache.rs @@ -14,7 +14,7 @@ use std::sync::Mutex; // FIXME: replace with std::lazy after it gets stabilized and reaches beta use once_cell::sync::Lazy; -use crate::builder::Step; +use crate::core::builder::Step; pub struct Interned<T>(usize, PhantomData<*const T>); diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index 2496c2a9db5..3d3f93f7720 100644 --- a/src/bootstrap/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -26,8 +26,8 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::{env, iter}; -use crate::config::{Target, TargetSelection}; -use crate::util::output; +use crate::core::config::{Target, TargetSelection}; +use crate::utils::helpers::output; use crate::{Build, CLang, GitRepo}; // The `cc` crate doesn't provide a way to obtain a path to the detected archiver, diff --git a/src/bootstrap/channel.rs b/src/bootstrap/src/utils/channel.rs index 87018574048..e59d7f22aaa 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/src/utils/channel.rs @@ -9,8 +9,7 @@ use std::fs; use std::path::Path; use std::process::Command; -use crate::util::output; -use crate::util::t; +use crate::utils::helpers::{output, t}; use crate::Build; #[derive(Clone, Default)] diff --git a/src/bootstrap/dylib_util.rs b/src/bootstrap/src/utils/dylib.rs index b14c0bed66c..279a6a010f1 100644 --- a/src/bootstrap/dylib_util.rs +++ b/src/bootstrap/src/utils/dylib.rs @@ -1,7 +1,4 @@ -// Various utilities for working with dylib paths. -// -// This file is meant to be included directly to avoid a dependency on the bootstrap library from -// the rustc and rustdoc wrappers. This improves compilation time by reducing the linking time. +//! Various utilities for working with dylib paths. /// Returns the environment variable which the dynamic library lookup path /// resides in for this platform. @@ -21,10 +18,10 @@ pub fn dylib_path_var() -> &'static str { /// Parses the `dylib_path_var()` environment variable, returning a list of /// paths that are members of this lookup path. -pub fn dylib_path() -> Vec<PathBuf> { - let var = match env::var_os(dylib_path_var()) { +pub fn dylib_path() -> Vec<std::path::PathBuf> { + let var = match std::env::var_os(dylib_path_var()) { Some(v) => v, None => return vec![], }; - env::split_paths(&var).collect() + std::env::split_paths(&var).collect() } diff --git a/src/bootstrap/util.rs b/src/bootstrap/src/utils/helpers.rs index 3c4a21434c0..bb84b70d987 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -12,10 +12,12 @@ use std::process::{Command, Stdio}; use std::str; use std::time::{Instant, SystemTime, UNIX_EPOCH}; -use crate::builder::Builder; -use crate::config::{Config, TargetSelection}; +use crate::core::builder::Builder; +use crate::core::config::{Config, TargetSelection}; use crate::OnceCell; +pub use crate::utils::dylib::{dylib_path, dylib_path_var}; + /// A helper macro to `unwrap` a result except also print out details like: /// /// * The file/line of the panic @@ -81,8 +83,6 @@ pub fn add_dylib_path(path: Vec<PathBuf>, cmd: &mut Command) { cmd.env(dylib_path_var(), t!(env::join_paths(list))); } -include!("dylib_util.rs"); - /// Adds a list of lookup paths to `cmd`'s link library lookup path. pub fn add_link_lib_path(path: Vec<PathBuf>, cmd: &mut Command) { let mut list = link_lib_path(); @@ -293,23 +293,6 @@ pub fn output(cmd: &mut Command) -> String { String::from_utf8(output.stdout).unwrap() } -pub fn output_result(cmd: &mut Command) -> Result<String, String> { - let output = match cmd.stderr(Stdio::inherit()).output() { - Ok(status) => status, - Err(e) => return Err(format!("failed to run command: {cmd:?}: {e}")), - }; - if !output.status.success() { - return Err(format!( - "command did not execute successfully: {:?}\n\ - expected success, got: {}\n{}", - cmd, - output.status, - String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))? - )); - } - Ok(String::from_utf8(output.stdout).map_err(|err| format!("{err:?}"))?) -} - /// Returns the last-modified time for `path`, or zero if it doesn't exist. pub fn mtime(path: &Path) -> SystemTime { fs::metadata(path).and_then(|f| f.modified()).unwrap_or(UNIX_EPOCH) @@ -495,3 +478,14 @@ pub fn lld_flag_no_threads(is_windows: bool) -> &'static str { pub fn dir_is_empty(dir: &Path) -> bool { t!(std::fs::read_dir(dir)).next().is_none() } + +/// Extract the beta revision from the full version string. +/// +/// The full version string looks like "a.b.c-beta.y". And we need to extract +/// the "y" part from the string. +pub fn extract_beta_rev(version: &str) -> Option<String> { + let parts = version.splitn(2, "-beta.").collect::<Vec<_>>(); + let count = parts.get(1).and_then(|s| s.find(' ').map(|p| (&s[..p]).to_string())); + + count +} diff --git a/src/bootstrap/src/utils/job.rs b/src/bootstrap/src/utils/job.rs new file mode 100644 index 00000000000..37235134a28 --- /dev/null +++ b/src/bootstrap/src/utils/job.rs @@ -0,0 +1,161 @@ +#[cfg(windows)] +pub use for_windows::*; + +#[cfg(any(target_os = "haiku", target_os = "hermit", not(any(unix, windows))))] +pub unsafe fn setup(_build: &mut crate::Build) {} + +#[cfg(all(unix, not(target_os = "haiku")))] +pub unsafe fn setup(build: &mut crate::Build) { + if build.config.low_priority { + libc::setpriority(libc::PRIO_PGRP as _, 0, 10); + } +} + +#[cfg(windows)] +mod for_windows { + //! Job management on Windows for bootstrapping + //! + //! Most of the time when you're running a build system (e.g., make) you expect + //! Ctrl-C or abnormal termination to actually terminate the entire tree of + //! process in play, not just the one at the top. This currently works "by + //! default" on Unix platforms because Ctrl-C actually sends a signal to the + //! *process group* rather than the parent process, so everything will get torn + //! down. On Windows, however, this does not happen and Ctrl-C just kills the + //! parent process. + //! + //! To achieve the same semantics on Windows we use Job Objects to ensure that + //! all processes die at the same time. Job objects have a mode of operation + //! where when all handles to the object are closed it causes all child + //! processes associated with the object to be terminated immediately. + //! Conveniently whenever a process in the job object spawns a new process the + //! child will be associated with the job object as well. This means if we add + //! ourselves to the job object we create then everything will get torn down! + //! + //! Unfortunately most of the time the build system is actually called from a + //! python wrapper (which manages things like building the build system) so this + //! all doesn't quite cut it so far. To go the last mile we duplicate the job + //! object handle into our parent process (a python process probably) and then + //! close our own handle. This means that the only handle to the job object + //! resides in the parent python process, so when python dies the whole build + //! system dies (as one would probably expect!). + //! + //! Note that this module has a #[cfg(windows)] above it as none of this logic + //! is required on Unix. + + use crate::Build; + use std::env; + use std::ffi::c_void; + use std::io; + use std::mem; + + use windows::{ + core::PCWSTR, + Win32::Foundation::{CloseHandle, DuplicateHandle, DUPLICATE_SAME_ACCESS, HANDLE}, + Win32::System::Diagnostics::Debug::{ + SetErrorMode, SEM_NOGPFAULTERRORBOX, THREAD_ERROR_MODE, + }, + Win32::System::JobObjects::{ + AssignProcessToJobObject, CreateJobObjectW, JobObjectExtendedLimitInformation, + SetInformationJobObject, JOBOBJECT_EXTENDED_LIMIT_INFORMATION, + JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS, + }, + Win32::System::Threading::{ + GetCurrentProcess, OpenProcess, BELOW_NORMAL_PRIORITY_CLASS, PROCESS_DUP_HANDLE, + }, + }; + + pub unsafe fn setup(build: &mut Build) { + // Enable the Windows Error Reporting dialog which msys disables, + // so we can JIT debug rustc + let mode = SetErrorMode(THREAD_ERROR_MODE::default()); + let mode = THREAD_ERROR_MODE(mode); + SetErrorMode(mode & !SEM_NOGPFAULTERRORBOX); + + // Create a new job object for us to use + let job = CreateJobObjectW(None, PCWSTR::null()).unwrap(); + + // Indicate that when all handles to the job object are gone that all + // process in the object should be killed. Note that this includes our + // entire process tree by default because we've added ourselves and our + // children will reside in the job by default. + let mut info = JOBOBJECT_EXTENDED_LIMIT_INFORMATION::default(); + info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + if build.config.low_priority { + info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS; + info.BasicLimitInformation.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS.0; + } + let r = SetInformationJobObject( + job, + JobObjectExtendedLimitInformation, + &info as *const _ as *const c_void, + mem::size_of_val(&info) as u32, + ) + .ok(); + assert!(r.is_ok(), "{}", io::Error::last_os_error()); + + // Assign our process to this job object. Note that if this fails, one very + // likely reason is that we are ourselves already in a job object! This can + // happen on the build bots that we've got for Windows, or if just anyone + // else is instrumenting the build. In this case we just bail out + // immediately and assume that they take care of it. + // + // Also note that nested jobs (why this might fail) are supported in recent + // versions of Windows, but the version of Windows that our bots are running + // at least don't support nested job objects. + let r = AssignProcessToJobObject(job, GetCurrentProcess()).ok(); + if r.is_err() { + CloseHandle(job); + return; + } + + // If we've got a parent process (e.g., the python script that called us) + // then move ownership of this job object up to them. That way if the python + // script is killed (e.g., via ctrl-c) then we'll all be torn down. + // + // If we don't have a parent (e.g., this was run directly) then we + // intentionally leak the job object handle. When our process exits + // (normally or abnormally) it will close the handle implicitly, causing all + // processes in the job to be cleaned up. + let pid = match env::var("BOOTSTRAP_PARENT_ID") { + Ok(s) => s, + Err(..) => return, + }; + + let parent = match OpenProcess(PROCESS_DUP_HANDLE, false, pid.parse().unwrap()).ok() { + Some(parent) => parent, + _ => { + // If we get a null parent pointer here, it is possible that either + // we have an invalid pid or the parent process has been closed. + // Since the first case rarely happens + // (only when wrongly setting the environmental variable), + // it might be better to improve the experience of the second case + // when users have interrupted the parent process and we haven't finish + // duplicating the handle yet. We just need close the job object if that occurs. + CloseHandle(job); + return; + } + }; + + let mut parent_handle = HANDLE::default(); + let r = DuplicateHandle( + GetCurrentProcess(), + job, + parent, + &mut parent_handle, + 0, + false, + DUPLICATE_SAME_ACCESS, + ) + .ok(); + + // If this failed, well at least we tried! An example of DuplicateHandle + // failing in the past has been when the wrong python2 package spawned this + // build system (e.g., the `python2` package in MSYS instead of + // `mingw-w64-x86_64-python2`). Not sure why it failed, but the "failure + // mode" here is that we only clean everything up when the build system + // dies, not when the python parent does, so not too bad. + if r.is_err() { + CloseHandle(job); + } + } +} diff --git a/src/bootstrap/metrics.rs b/src/bootstrap/src/utils/metrics.rs index cf8d33dfcb0..65794f05d2d 100644 --- a/src/bootstrap/metrics.rs +++ b/src/bootstrap/src/utils/metrics.rs @@ -4,8 +4,8 @@ //! As this module requires additional dependencies not present during local builds, it's cfg'd //! away whenever the `build.metrics` config option is not set to `true`. -use crate::builder::{Builder, Step}; -use crate::util::t; +use crate::core::builder::{Builder, Step}; +use crate::utils::helpers::t; use crate::Build; use build_helper::metrics::{ JsonInvocation, JsonInvocationSystemStats, JsonNode, JsonRoot, JsonStepSystemStats, Test, diff --git a/src/bootstrap/src/utils/mod.rs b/src/bootstrap/src/utils/mod.rs new file mode 100644 index 00000000000..7dcb6a82862 --- /dev/null +++ b/src/bootstrap/src/utils/mod.rs @@ -0,0 +1,14 @@ +//! This module contains integral components of the build and configuration process, providing +//! support for a wide range of tasks and operations such as caching, tarballs, release +//! channels, job management, etc. + +pub(crate) mod cache; +pub(crate) mod cc_detect; +pub(crate) mod channel; +pub(crate) mod dylib; +pub(crate) mod helpers; +pub(crate) mod job; +#[cfg(feature = "build-metrics")] +pub(crate) mod metrics; +pub(crate) mod render_tests; +pub(crate) mod tarball; diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index 6802bf4511b..f97aa958513 100644 --- a/src/bootstrap/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -6,7 +6,7 @@ //! and rustc) libtest doesn't include the rendered human-readable output as a JSON field. We had //! to reimplement all the rendering logic in this module because of that. -use crate::builder::Builder; +use crate::core::builder::Builder; use std::io::{BufRead, BufReader, Read, Write}; use std::process::{ChildStdout, Command, Stdio}; use std::time::Duration; diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 95d909c5730..b437456f8a1 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -3,9 +3,10 @@ use std::{ process::Command, }; -use crate::builder::Builder; -use crate::channel; -use crate::util::t; +use crate::core::build_steps::dist::distdir; +use crate::core::builder::Builder; +use crate::utils::channel; +use crate::utils::helpers::t; #[derive(Copy, Clone)] pub(crate) enum OverlayKind { @@ -112,7 +113,7 @@ impl<'a> Tarball<'a> { } fn new_inner(builder: &'a Builder<'a>, component: &str, target: Option<String>) -> Self { - let pkgname = crate::dist::pkgname(builder, component); + let pkgname = crate::core::build_steps::dist::pkgname(builder, component); let mut temp_dir = builder.out.join("tmp").join("tarball").join(component); if let Some(target) = &target { @@ -265,7 +266,7 @@ impl<'a> Tarball<'a> { t!(std::fs::rename(&self.image_dir, &dest)); self.run(|this, cmd| { - let distdir = crate::dist::distdir(this.builder); + let distdir = distdir(this.builder); t!(std::fs::create_dir_all(&distdir)); cmd.arg("tarball") .arg("--input") @@ -292,7 +293,7 @@ impl<'a> Tarball<'a> { .arg("--non-installed-overlay") .arg(&self.overlay_dir) .arg("--output-dir") - .arg(crate::dist::distdir(self.builder)); + .arg(distdir(self.builder)); } fn run(self, build_cli: impl FnOnce(&Tarball<'a>, &mut Command)) -> GeneratedTarball { @@ -306,11 +307,11 @@ impl<'a> Tarball<'a> { self.builder.install(&self.builder.src.join(file), &self.overlay_dir, 0o644); } - let mut cmd = self.builder.tool_cmd(crate::tool::Tool::RustInstaller); + let mut cmd = self.builder.tool_cmd(crate::core::build_steps::tool::Tool::RustInstaller); let package_name = self.package_name(); self.builder.info(&format!("Dist {package_name}")); - let _time = crate::util::timeit(self.builder); + let _time = crate::utils::helpers::timeit(self.builder); build_cli(&self, &mut cmd); cmd.arg("--work-dir").arg(&self.temp_dir); @@ -344,7 +345,7 @@ impl<'a> Tarball<'a> { .unwrap_or("gz"); GeneratedTarball { - path: crate::dist::distdir(self.builder).join(format!("{package_name}.tar.{ext}")), + path: distdir(self.builder).join(format!("{package_name}.tar.{ext}")), decompressed_output, work: self.temp_dir, } diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gcc.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gcc.sh index 6da3f89220e..3b3ec5da74b 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gcc.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gcc.sh @@ -27,10 +27,15 @@ sed -i'' 's|ftp://gcc\.gnu\.org/|https://gcc.gnu.org/|g' ./contrib/download_prer ./contrib/download_prerequisites mkdir ../gcc-build cd ../gcc-build + +# '-fno-reorder-blocks-and-partition' is required to +# enable BOLT optimization of the C++ standard library, +# which is included in librustc_driver.so hide_output ../gcc-$GCC/configure \ --prefix=/rustroot \ --enable-languages=c,c++ \ - --disable-gnu-unique-object + --disable-gnu-unique-object \ + --enable-cxx-flags='-fno-reorder-blocks-and-partition' hide_output make -j$(nproc) hide_output make install ln -s gcc /rustroot/bin/cc diff --git a/src/doc/reference b/src/doc/reference -Subproject 5262e1c3b43a2c489df8f6717683a44c7a2260f +Subproject 142b2ed77d33f37a9973772bd95e6144ed9dce4 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject c954202c1e1720cba5628f99543cc01188c7d6f +Subproject 8eb3a01ab74c567b7174784892fb807f2c632d6 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject a13b7c28ed705891c681ce5417b3d1cdb12cecd +Subproject b98af7d661e4744baab81fb8dc7a049e44a4a99 diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 1fb5e56db5d..db834600b9c 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -244,7 +244,7 @@ target | std | host | notes `armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD [`armv6-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | ARMv6 NetBSD w/hard-float [`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? | | ARMv6K Nintendo 3DS, Horizon (Requires devkitARM toolchain) -[`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ? | | ARMv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain) +[`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ✓ | | ARMv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain) [`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | | ARMv7-A OpenHarmony | [`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | ARMv7-A Linux with uClibc, softfloat [`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | ARMv7-A Linux with uClibc, hardfloat diff --git a/src/doc/rustc/src/platform-support/android.md b/src/doc/rustc/src/platform-support/android.md index 4ef74295e0f..9ddf00e3a50 100644 --- a/src/doc/rustc/src/platform-support/android.md +++ b/src/doc/rustc/src/platform-support/android.md @@ -45,3 +45,19 @@ The riscv64-linux-android target is supported as a Tier 3 target. A list of all supported targets can be found [here](../platform-support.html) + +## Architecture Notes + +### riscv64-linux-android + +Currently the `riscv64-linux-android` target requires the following architecture features/extensions: + +* `a` (atomics) +* `d` (double-precision floating-point) +* `c` (compressed instruction set) +* `f` (single-precision floating-point) +* `m` (multiplication and division) +* `v` (vector) +* `Zba` (address calculation instructions) +* `Zbb` (base instructions) +* `Zbs` (single-bit instructions) diff --git a/src/doc/rustc/src/platform-support/armv7-sony-vita-newlibeabihf.md b/src/doc/rustc/src/platform-support/armv7-sony-vita-newlibeabihf.md index 49eed366dac..e1473bd966c 100644 --- a/src/doc/rustc/src/platform-support/armv7-sony-vita-newlibeabihf.md +++ b/src/doc/rustc/src/platform-support/armv7-sony-vita-newlibeabihf.md @@ -2,15 +2,16 @@ **Tier: 3** -This tier supports the ARM Cortex A9 processor running on a PlayStation Vita console. `armv7-vita-newlibeabihf` aims to have support for `std` crate using `newlib` as a bridge. +This tier supports the ARM Cortex A9 processor running on a PlayStation Vita console. Rust support for this target is not affiliated with Sony, and is not derived from nor used with any official Sony SDK. ## Target maintainers -* [@amg98](https://github.com/amg98) * [@nikarh](https://github.com/nikarh) +* [@pheki](https://github.com/pheki) +* [@ZetaNumbers](https://github.com/ZetaNumbers) ## Requirements @@ -20,18 +21,16 @@ This target is cross-compiled, and requires installing [VITASDK](https://vitasdk `alloc`, and `panic_abort`. `std` is partially supported, but mostly works. Some APIs are unimplemented -and will simply return an error, such as `std::process`. An allocator is provided -by default. +and will simply return an error, such as `std::process`. -In order to support some APIs, binaries must be linked against `libc` written -for the target, using a linker for the target. These are provided by the -VITASDK toolchain. +This target generates binaries in the ELF format with thumb ISA by default. + +Binaries are linked with `arm-vita-eabi-gcc` provided by VITASDK toolchain. -This target generates binaries in the ELF format with thumb ISA. ## Building the target -Rust does not ship pre-compiled artifacts for this target. You can use `build-std` flag to build binaries with `std`: +Rust does not ship pre-compiled artifacts for this target. You can use `build-std` flag to build ELF binaries with `std`: ```sh cargo build -Z build-std=std,panic_abort --target=armv7-sony-vita-newlibeabihf --release @@ -39,113 +38,45 @@ cargo build -Z build-std=std,panic_abort --target=armv7-sony-vita-newlibeabihf - ## Building Rust programs -To test your developed rust programs on PlayStation Vita, first you must correctly package your elf. These steps can be preformed using tools available in VITASDK, and can be automated using a tool like `cargo-make`. +The recommended way to build artifacts that can be installed and run on PlayStation Vita is by using the [cargo-vita](https://github.com/vita-rust/cargo-vita) tool. This tool uses `build-std` and VITASDK toolchain to build artifacts runnable on Vita. + +To install the tool run: + +```sh +cargo install cargo-vita +``` -First, set up environment variables for `VITASDK`, and it's binaries: +[VITASDK](https://vitasdk.org/) toolchain must be installed, and the `VITASDK` environment variable must be set to its location, e.g.: ```sh export VITASDK=/opt/vitasdk -export PATH=$PATH:$VITASDK/bin ``` -Use the example below as a template for your project: +Add the following section to your project's `Cargo.toml`: + ```toml -[env] -TITLE = "Rust Hello World" -TITLEID = "RUST00001" - -# At least a "sce_sys" folder should be place there for app metadata (title, icons, description...) -# You can find sample assets for that on $VITASDK/share/gcc-arm-vita-eabi/samples/hello_world/sce_sys/ -STATIC_DIR = "static" # Folder where static assets should be placed (sce_sys folder is at $STATIC_DIR/sce_sys) -CARGO_TARGET_DIR = { script = ["echo ${CARGO_TARGET_DIR:=target}"] } -CARGO_OUT_DIR = "${CARGO_TARGET_DIR}/${RUST_TARGET}/release" - -[tasks.build] -description = "Build the project using `cargo`." -command = "cargo" -args = ["build", "-Z", "build-std=std,panic_abort", "--target=armv7-sony-vita-newlibeabihf", "--release"] - -[tasks.strip] -description = "Strip the produced ELF executable." -dependencies = ["build"] -command = "arm-vita-eabi-strip" -args = ["-g", '${CARGO_OUT_DIR}/${CARGO_MAKE_CRATE_FS_NAME}.elf'] - -[tasks.velf] -description = "Build an VELF executable from the obtained ELF file." -dependencies = ["strip"] -command = "vita-elf-create" -args = ['${CARGO_OUT_DIR}/${CARGO_MAKE_CRATE_NAME}.elf', '${CARGO_OUT_DIR}/${CARGO_MAKE_CRATE_NAME}.velf'] - -[tasks.eboot-bin] -description = "Build an `eboot.bin` file from the obtained VELF file." -dependencies = ["velf"] -command = "vita-make-fself" -args = ["-s", '${CARGO_OUT_DIR}/${CARGO_MAKE_CRATE_NAME}.velf', '${CARGO_OUT_DIR}/eboot.bin'] - -[tasks.param-sfo] -description = "Build the `param.sfo` manifest using with given TITLE and TITLEID." -command = "vita-mksfoex" -args = ["-s", 'TITLE_ID=${TITLEID}', '${TITLE}', '${CARGO_OUT_DIR}/param.sfo'] - -[tasks.manifest] -description = "List all static resources into a manifest file." -script = [ - 'mkdir -p "${CARGO_OUT_DIR}"', - ''' - if [ -d "${STATIC_DIR}" ]; then - find "${STATIC_DIR}" -type f > "${CARGO_OUT_DIR}/MANIFEST" - else - touch "${CARGO_OUT_DIR}/MANIFEST" - fi - ''' -] - -[tasks.vpk] -description = "Build a VPK distribution of the project executable and resources." -dependencies = ["eboot-bin", "param-sfo", "manifest"] -script_runner = "@rust" -script = [ - ''' - use std::io::BufRead; - use std::fs::File; - - fn main() { - - let crate_name = env!("CARGO_MAKE_CRATE_NAME"); - let static_dir = env!("STATIC_DIR"); - let out_dir = std::path::PathBuf::from(env!("CARGO_OUT_DIR")); - - let mut cmd = ::std::process::Command::new("vita-pack-vpk"); - cmd.arg("-s").arg(out_dir.join("param.sfo")); - cmd.arg("-b").arg(out_dir.join("eboot.bin")); - - // Add files from MANIFEST - if let Ok(file) = File::open(out_dir.join("MANIFEST")) { - let mut reader = ::std::io::BufReader::new(file); - let mut lines = reader.lines(); - while let Some(Ok(line)) = lines.next() { - let p1 = ::std::path::PathBuf::from(line); // path on FS - let p2 = p1.strip_prefix(static_dir).unwrap(); // path in VPK - cmd.arg("--add").arg(format!("{}={}", p1.display(), p2.display())); - } - } - - cmd.arg(out_dir.join(format!("{}.vpk", crate_name))) - .output() - .expect("command failed."); - } - ''' -] +[package.metadata.vita] +# A unique 9 character alphanumeric identifier of the app. +title_id = "RUSTAPP01" +# A title that will be used for the app. Optional, name will be used if not defined +title_name = "My application" ``` -After running the above script, you should be able to get a *.vpk file in the same folder your *.elf executable resides. Now you can pick it and install it on your own PlayStation Vita using, or you can use an [Vita3K](https://vita3k.org/) emulator. +To build a VPK with ELF in the release profile, run: + +```sh +cargo vita build vpk --release +``` + +After building a *.vpk file it can be uploaded to a PlayStation Vita and installed, or used with a [Vita3K](https://vita3k.org/) emulator. ## Testing -Currently there is no support to run the rustc test suite for this target. +The default Rust test runner is supported, and tests can be compiled to an elf and packed to a *.vpk file using `cargo-vita` tool. Filtering tests is not currently supported since passing command-line arguments to the executable is not supported on Vita, so the runner will always execute all tests. + +The Rust test suite for `library/std` is not yet supported. ## Cross-compilation -This target can be cross-compiled from `x86_64` on either Windows, MacOS or Linux systems. Other hosts are not supported for cross-compilation. +This target can be cross-compiled from `x86_64` on Windows, MacOS or Linux systems. Other hosts are not supported for cross-compilation. diff --git a/src/doc/rustc/src/platform-support/unknown-uefi.md b/src/doc/rustc/src/platform-support/unknown-uefi.md index 370939520dc..1230ea22bd9 100644 --- a/src/doc/rustc/src/platform-support/unknown-uefi.md +++ b/src/doc/rustc/src/platform-support/unknown-uefi.md @@ -268,6 +268,8 @@ cargo build --target x86_64-unknown-uefi -Zbuild-std=std,panic_abort #### stdio - Uses `Simple Text Input Protocol` and `Simple Text Output Protocol`. - Note: UEFI uses CRLF for new line. This means Enter key is registered as CR instead of LF. +#### args +- Uses `EFI_LOADED_IMAGE_PROTOCOL->LoadOptions` ## Example: Hello World With std The following code features a valid UEFI application, including `stdio` and `alloc` (`OsString` and `Vec`): diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md index dbf0baec04c..1733c8fc9a2 100644 --- a/src/doc/rustdoc/src/advanced-features.md +++ b/src/doc/rustdoc/src/advanced-features.md @@ -110,3 +110,23 @@ https://doc.rust-lang.org/stable/std/?search=%s&go_to_first=true This URL adds the `go_to_first=true` query parameter which can be appended to any `rustdoc` search URL to automatically go to the first result. + +## `#[repr(transparent)]`: Documenting the transparent representation + +You can read more about `#[repr(transparent)]` itself in the [Rust Reference][repr-trans-ref] and +in the [Rustonomicon][repr-trans-nomicon]. + +Since this representation is only considered part of the public ABI if the single field with non-trivial +size or alignment is public and if the documentation does not state otherwise, Rustdoc helpfully displays +the attribute if and only if the non-1-ZST field is public or at least one field is public in case all +fields are 1-ZST fields. The term *1-ZST* refers to types that are one-aligned and zero-sized. + +It would seem that one can manually hide the attribute with `#[cfg_attr(not(doc), repr(transparent))]` +if one wishes to declare the representation as private even if the non-1-ZST field is public. +However, due to [current limitations][cross-crate-cfg-doc], this method is not always guaranteed to work. +Therefore, if you would like to do so, you should always write it down in prose independently of whether +you use `cfg_attr` or not. + +[repr-trans-ref]: https://doc.rust-lang.org/reference/type-layout.html#the-transparent-representation +[repr-trans-nomicon]: https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent +[cross-crate-cfg-doc]: https://github.com/rust-lang/rust/issues/114952 diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 7473b09920f..41602dec44c 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -207,6 +207,21 @@ To do so, the `#[doc(keyword = "...")]` attribute is used. Example: mod empty_mod {} ``` +### Use the Rust logo as the crate logo + +This is for official Rust project use only. + +Internal Rustdoc pages like settings.html and scrape-examples-help.html show the Rust logo. +This logo is tracked as a static resource. The attribute `#![doc(rust_logo)]` makes this same +built-in resource act as the main logo. + +```rust +#![feature(rustdoc_internals)] +#![allow(internal_features)] +#![doc(rust_logo)] +//! This crate has the Rust(tm) branding on it. +``` + ## Effects of other nightly features These nightly-only features are not primarily related to Rustdoc, @@ -613,10 +628,10 @@ Using this flag looks like this: ```bash $ rustdoc src/lib.rs -Z unstable-options \ - --check-cfg='names()' --check-cfg='values(feature, "foo", "bar")' + --check-cfg='cfg(feature, values("foo", "bar"))' ``` -The example above check every well known names (`target_os`, `doc`, `test`, ... via `names()`) +The example above check every well known names and values (`target_os`, `doc`, `test`, ...) and check the values of `feature`: `foo` and `bar`. ### `--generate-link-to-definition`: Generate links on types in source code diff --git a/src/doc/unstable-book/src/compiler-flags/check-cfg.md b/src/doc/unstable-book/src/compiler-flags/check-cfg.md index 10f0fbc5062..ca18ec567a4 100644 --- a/src/doc/unstable-book/src/compiler-flags/check-cfg.md +++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md @@ -10,97 +10,80 @@ This feature allows you to enable complete or partial checking of configuration. check them. The `--check-cfg` option takes a value, called the _check cfg specification_. The check cfg specification is parsed using the Rust metadata syntax, just as the `--cfg` option is. -`--check-cfg` option can take one of two forms: +`--check-cfg` option take one form: -1. `--check-cfg names(...)` enables checking condition names. -2. `--check-cfg values(...)` enables checking the values within list-valued conditions. - -These two options are independent. `names` checks only the namespace of condition names -while `values` checks only the namespace of the values of list-valued conditions. +1. `--check-cfg cfg(...)` enables checking the values within list-valued conditions. NOTE: No implicit expectation is added when using `--cfg` for both forms. Users are expected to -pass all expected names and values using `names(...)` and `values(...)`. +pass all expected names and values using `cfg(...)`. -## The `names(...)` form +## The `cfg(...)` form -The `names(...)` form enables checking the names. This form uses a named list: +The `cfg(...)` form enables checking the values within list-valued conditions. It has this +basic form: ```bash -rustc --check-cfg 'names(name1, name2, ... nameN)' +rustc --check-cfg 'cfg(name1, ..., nameN, values("value1", "value2", ... "valueN"))' ``` -where each `name` is a bare identifier (has no quotes). The order of the names is not significant. +where `name` is a bare identifier (has no quotes) and each `"value"` term is a quoted literal +string. `name` specifies the name of the condition, such as `feature` or `my_cfg`. -If `--check-cfg names(...)` is specified at least once, then `rustc` will check all references to -condition names. `rustc` will check every `#[cfg]` attribute, `#[cfg_attr]` attribute, `cfg` clause -inside `#[link]` attribute and `cfg!(...)` call against the provided list of expected condition -names. If a name is not present in this list, then `rustc` will report an `unexpected_cfgs` lint -diagnostic. The default diagnostic level for this lint is `Warn`. +When the `cfg(...)` option is specified, `rustc` will check every `#[cfg(name = "value")]` +attribute, `#[cfg_attr(name = "value")]` attribute, `#[link(name = "a", cfg(name = "value"))]` +and `cfg!(name = "value")` call. It will check that the `"value"` specified is present in the +list of expected values. If `"value"` is not in it, then `rustc` will report an `unexpected_cfgs` +lint diagnostic. The default diagnostic level for this lint is `Warn`. -If `--check-cfg names(...)` is not specified, then `rustc` will not check references to condition -names. +To enable checking of values, but to provide an empty set of expected values, use these forms: -`--check-cfg names(...)` may be specified more than once. The result is that the list of valid -condition names is merged across all options. It is legal for a condition name to be specified -more than once; redundantly specifying a condition name has no effect. +```bash +rustc --check-cfg 'cfg(name1, ..., nameN)' +rustc --check-cfg 'cfg(name1, ..., nameN, values())' +``` -To enable checking condition names with an empty set of valid condition names, use the following -form. The parentheses are required. +To enable checking of name but not values (i.e. unknown expected values), use this form: ```bash -rustc --check-cfg 'names()' +rustc --check-cfg 'cfg(name1, ..., nameN, values(any()))' ``` -Note that `--check-cfg 'names()'` is _not_ equivalent to omitting the option entirely. -The first form enables checking condition names, while specifying that there are no valid -condition names (outside of the set of well-known names defined by `rustc`). Omitting the -`--check-cfg 'names(...)'` option does not enable checking condition names. - -## The `values(...)` form +The `--check-cfg cfg(...)` option can be repeated, both for the same condition name and for +different names. If it is repeated for the same condition name, then the sets of values for that +condition are merged together (presedence is given to `any()`). -The `values(...)` form enables checking the values within list-valued conditions. It has this -form: +## Well known names and values -```bash -rustc --check-cfg `values(name, "value1", "value2", ... "valueN")' -``` +`rustc` has a internal list of well known names and their corresponding values. +Those well known names and values follows the same stability as what they refer to. -where `name` is a bare identifier (has no quotes) and each `"value"` term is a quoted literal -string. `name` specifies the name of the condition, such as `feature` or `target_os`. +Well known values checking is always enabled as long as a `--check-cfg` argument is present. -When the `values(...)` option is specified, `rustc` will check every `#[cfg(name = "value")]` -attribute, `#[cfg_attr(name = "value")]` attribute, `#[link(name = "a", cfg(name = "value"))]` -and `cfg!(name = "value")` call. It will check that the `"value"` specified is present in the -list of expected values. If `"value"` is not in it, then `rustc` will report an `unexpected_cfgs` -lint diagnostic. The default diagnostic level for this lint is `Warn`. +Well known names checking is always enable as long as a `--check-cfg` argument is present +**unless** any `cfg(any())` argument is passed. -To enable checking of values, but to provide an empty set of valid values, use this form: +To disable checking of well known names, use this form: ```bash -rustc --check-cfg `values(name)` +rustc --check-cfg 'cfg(any())' ``` -The `--check-cfg values(...)` option can be repeated, both for the same condition name and for -different names. If it is repeated for the same condition name, then the sets of values for that -condition are merged together. - -If `values()` is specified, then `rustc` will enable the checking of well-known values defined -by itself. Note that it's necessary to specify the `values()` form to enable the checking of -well known values, specifying the other forms doesn't implicitly enable it. +NOTE: If one want to enable values and names checking without having any cfg to declare, one +can use an empty `cfg()` argument. ## Examples Consider this command line: ```bash -rustc --check-cfg 'names(feature)' \ - --check-cfg 'values(feature, "lion", "zebra")' \ +rustc --check-cfg 'cfg(feature, values("lion", "zebra"))' \ --cfg 'feature="lion"' -Z unstable-options \ example.rs ``` This command line indicates that this crate has two features: `lion` and `zebra`. The `lion` -feature is enabled, while the `zebra` feature is disabled. Consider compiling this code: +feature is enabled, while the `zebra` feature is disabled. Exhaustive checking of names and +values are enabled by default. Consider compiling this code: ```rust // This is expected, and tame_lion() will be compiled @@ -119,35 +102,36 @@ fn poke_platypus() {} // and will cause a compiler warning (by default). #[cfg(feechure = "lion")] fn tame_lion() {} -``` -> Note: The `--check-cfg names(feature)` option is necessary only to enable checking the condition -> name, as in the last example. `feature` is a well-known (always-expected) condition name, and so -> it is not necessary to specify it in a `--check-cfg 'names(...)'` option. That option can be -> shortened to > `--check-cfg names()` in order to enable checking well-known condition names. +// This is UNEXPECTED, because 'windows' is a well known condition name, +// and because 'windows' doens't take any values, +// and will cause a compiler warning (by default). +#[cfg(windows = "unix")] +fn tame_windows() {} +``` ### Example: Checking condition names, but not values ```bash # This turns on checking for condition names, but not values, such as 'feature' values. -rustc --check-cfg 'names(is_embedded, has_feathers)' \ +rustc --check-cfg 'cfg(is_embedded, has_feathers, values(any()))' \ --cfg has_feathers -Z unstable-options ``` ```rust -#[cfg(is_embedded)] // This is expected as "is_embedded" was provided in names() -fn do_embedded() {} +#[cfg(is_embedded)] // This is expected as "is_embedded" was provided in cfg() +fn do_embedded() {} // and because names exhaustiveness was not disabled -#[cfg(has_feathers)] // This is expected as "has_feathers" was provided in names() -fn do_features() {} +#[cfg(has_feathers)] // This is expected as "has_feathers" was provided in cfg() +fn do_features() {} // and because names exhaustiveness was not disbaled -#[cfg(has_feathers = "zapping")] // This is expected as "has_feathers" was provided in names() +#[cfg(has_feathers = "zapping")] // This is expected as "has_feathers" was provided in cfg() // and because no value checking was enable for "has_feathers" // no warning is emitted for the value "zapping" fn do_zapping() {} #[cfg(has_mumble_frotz)] // This is UNEXPECTED because names checking is enable and - // "has_mumble_frotz" was not provided in names() + // "has_mumble_frotz" was not provided in cfg() fn do_mumble_frotz() {} ``` @@ -155,25 +139,25 @@ fn do_mumble_frotz() {} ```bash # This turns on checking for feature values, but not for condition names. -rustc --check-cfg 'values(feature, "zapping", "lasers")' \ +rustc --check-cfg 'configure(feature, values("zapping", "lasers"))' \ + --check-cfg 'cfg(any())' \ --cfg 'feature="zapping"' -Z unstable-options ``` ```rust -#[cfg(is_embedded)] // This is doesn't raise a warning, because names checking was not - // enable (ie not names()) +#[cfg(is_embedded)] // This is doesn't raise a warning, because names checking was + // disabled by 'cfg(any())' fn do_embedded() {} -#[cfg(has_feathers)] // Same as above, --check-cfg names(...) was never used so no name +#[cfg(has_feathers)] // Same as above, 'cfg(any())' was provided so no name // checking is performed fn do_features() {} - -#[cfg(feature = "lasers")] // This is expected, "lasers" is in the values(feature) list +#[cfg(feature = "lasers")] // This is expected, "lasers" is in the cfg(feature) list fn shoot_lasers() {} #[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in the - // --check-cfg values(feature) list + // cfg(feature) list fn write_shakespeare() {} ``` @@ -181,26 +165,92 @@ fn write_shakespeare() {} ```bash # This turns on checking for feature values and for condition names. -rustc --check-cfg 'names(is_embedded, has_feathers)' \ - --check-cfg 'values(feature, "zapping", "lasers")' \ +rustc --check-cfg 'cfg(is_embedded, has_feathers)' \ + --check-cfg 'cfg(feature, values("zapping", "lasers"))' \ --cfg has_feathers --cfg 'feature="zapping"' -Z unstable-options ``` ```rust -#[cfg(is_embedded)] // This is expected because "is_embedded" was provided in names() -fn do_embedded() {} +#[cfg(is_embedded)] // This is expected because "is_embedded" was provided in cfg() +fn do_embedded() {} // and doesn't take any value -#[cfg(has_feathers)] // This is expected because "has_feathers" was provided in names() -fn do_features() {} +#[cfg(has_feathers)] // This is expected because "has_feathers" was provided in cfg() +fn do_features() {} // and deosn't take any value -#[cfg(has_mumble_frotz)] // This is UNEXPECTED, because has_mumble_frotz is not in the - // --check-cfg names(...) list +#[cfg(has_mumble_frotz)] // This is UNEXPECTED, because "has_mumble_frotz" was never provided fn do_mumble_frotz() {} -#[cfg(feature = "lasers")] // This is expected, "lasers" is in the values(feature) list +#[cfg(feature = "lasers")] // This is expected, "lasers" is in the cfg(feature) list fn shoot_lasers() {} #[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in - // the values(feature) list + // the cfg(feature) list fn write_shakespeare() {} ``` + +## The deprecated `names(...)` form + +The `names(...)` form enables checking the names. This form uses a named list: + +```bash +rustc --check-cfg 'names(name1, name2, ... nameN)' +``` + +where each `name` is a bare identifier (has no quotes). The order of the names is not significant. + +If `--check-cfg names(...)` is specified at least once, then `rustc` will check all references to +condition names. `rustc` will check every `#[cfg]` attribute, `#[cfg_attr]` attribute, `cfg` clause +inside `#[link]` attribute and `cfg!(...)` call against the provided list of expected condition +names. If a name is not present in this list, then `rustc` will report an `unexpected_cfgs` lint +diagnostic. The default diagnostic level for this lint is `Warn`. + +If `--check-cfg names(...)` is not specified, then `rustc` will not check references to condition +names. + +`--check-cfg names(...)` may be specified more than once. The result is that the list of valid +condition names is merged across all options. It is legal for a condition name to be specified +more than once; redundantly specifying a condition name has no effect. + +To enable checking condition names with an empty set of valid condition names, use the following +form. The parentheses are required. + +```bash +rustc --check-cfg 'names()' +``` + +Note that `--check-cfg 'names()'` is _not_ equivalent to omitting the option entirely. +The first form enables checking condition names, while specifying that there are no valid +condition names (outside of the set of well-known names defined by `rustc`). Omitting the +`--check-cfg 'names(...)'` option does not enable checking condition names. + +## The deprecated `values(...)` form + +The `values(...)` form enables checking the values within list-valued conditions. It has this +form: + +```bash +rustc --check-cfg `values(name, "value1", "value2", ... "valueN")' +``` + +where `name` is a bare identifier (has no quotes) and each `"value"` term is a quoted literal +string. `name` specifies the name of the condition, such as `feature` or `target_os`. + +When the `values(...)` option is specified, `rustc` will check every `#[cfg(name = "value")]` +attribute, `#[cfg_attr(name = "value")]` attribute, `#[link(name = "a", cfg(name = "value"))]` +and `cfg!(name = "value")` call. It will check that the `"value"` specified is present in the +list of expected values. If `"value"` is not in it, then `rustc` will report an `unexpected_cfgs` +lint diagnostic. The default diagnostic level for this lint is `Warn`. + +To enable checking of values, but to provide an empty set of valid values, use this form: + +```bash +rustc --check-cfg `values(name)` +``` + +The `--check-cfg values(...)` option can be repeated, both for the same condition name and for +different names. If it is repeated for the same condition name, then the sets of values for that +condition are merged together. + +If `values()` is specified, then `rustc` will enable the checking of well-known values defined +by itself. Note that it's necessary to specify the `values()` form to enable the checking of +well known values, specifying the other forms doesn't implicitly enable it. diff --git a/src/doc/unstable-book/src/compiler-flags/no-jump-tables.md b/src/doc/unstable-book/src/compiler-flags/no-jump-tables.md new file mode 100644 index 00000000000..f096c20f4bd --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/no-jump-tables.md @@ -0,0 +1,19 @@ +# `no-jump-tables` + +The tracking issue for this feature is [#116592](https://github.com/rust-lang/rust/issues/116592) + +--- + +This option enables the `-fno-jump-tables` flag for LLVM, which makes the +codegen backend avoid generating jump tables when lowering switches. + +This option adds the LLVM `no-jump-tables=true` attribute to every function. + +The option can be used to help provide protection against +jump-oriented-programming (JOP) attacks, such as with the linux kernel's [IBT]. + +```sh +RUSTFLAGS="-Zno-jump-tables" cargo +nightly build -Z build-std +``` + +[IBT]: https://www.phoronix.com/news/Linux-IBT-By-Default-Tip diff --git a/src/doc/unstable-book/src/language-features/diagnostic-namespace.md b/src/doc/unstable-book/src/language-features/diagnostic-namespace.md new file mode 100644 index 00000000000..7c46811a27a --- /dev/null +++ b/src/doc/unstable-book/src/language-features/diagnostic-namespace.md @@ -0,0 +1,84 @@ +# `diagnostic_namespace` + +The tracking issue for this feature is: [#111996] + +[#111996]: https://github.com/rust-lang/rust/issues/111996 + +------------------------ + +The `diagnostic_namespace` feature permits customization of compilation errors. + +## diagnostic::on_unimplemented + +With [#114452] support for `diagnostic::on_unimplemented` was added. + +When used on a trait declaration, the following options are available: + +* `message` to customize the primary error message +* `note` to add a customized note message to an error message +* `label` to customize the label part of the error message + +The attribute will hint to the compiler to use these in error messages: +```rust +// some library +#![feature(diagnostic_namespace)] + +#[diagnostic::on_unimplemented( + message = "cannot insert element", + label = "cannot be put into a table", + note = "see <link> for more information about the Table api" +)] +pub trait Element { + // ... +} +``` + +```rust,compile_fail,E0277 +# #![feature(diagnostic_namespace)] +# +# #[diagnostic::on_unimplemented( +# message = "cannot insert element", +# label = "cannot be put into a table", +# note = "see <link> for more information about the Table api" +# )] +# pub trait Element { +# // ... +# } +# struct Table; +# impl Table { +# fn insert<T: Element>(&self, element: T) { +# // .. +# } +# } +# fn main() { +# let table = Table; +# let element = (); +// user code +table.insert(element); +# } +``` + +```text +error[E0277]: cannot insert element + --> src/main.rs:24:18 + | +24 | table.insert(element); + | ------ ^^^^^^^ cannot be put into a table + | | + | required by a bound introduced by this call + | + = help: the trait `Element` is not implemented for `<type>` + = note: see <link> for more information about the Table api +note: required by a bound in `Table::insert` + --> src/main.rs:15:18 + | +15 | fn insert<T: Element>(&self, element: T) { + | ^^^^^^^ required by this bound in `Table::insert` + +For more information about this error, try `rustc --explain E0277`. +``` + +See [RFC 3368] for more information. + +[#114452]: https://github.com/rust-lang/rust/pull/114452 +[RFC 3368]: https://github.com/rust-lang/rfcs/blob/master/text/3368-diagnostic-attribute-namespace.md diff --git a/src/doc/unstable-book/src/language-features/string-deref-patterns.md b/src/doc/unstable-book/src/language-features/string-deref-patterns.md new file mode 100644 index 00000000000..3723830751e --- /dev/null +++ b/src/doc/unstable-book/src/language-features/string-deref-patterns.md @@ -0,0 +1,45 @@ +# `string_deref_patterns` + +The tracking issue for this feature is: [#87121] + +[#87121]: https://github.com/rust-lang/rust/issues/87121 + +------------------------ + +This feature permits pattern matching `String` to `&str` through [its `Deref` implementation]. + +```rust +#![feature(string_deref_patterns)] + +pub enum Value { + String(String), + Number(u32), +} + +pub fn is_it_the_answer(value: Value) -> bool { + match value { + Value::String("42") => true, + Value::Number(42) => true, + _ => false, + } +} +``` + +Without this feature other constructs such as match guards have to be used. + +```rust +# pub enum Value { +# String(String), +# Number(u32), +# } +# +pub fn is_it_the_answer(value: Value) -> bool { + match value { + Value::String(s) if s == "42" => true, + Value::Number(42) => true, + _ => false, + } +} +``` + +[its `Deref` implementation]: https://doc.rust-lang.org/std/string/struct.String.html#impl-Deref-for-String diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index 151c4120ddf..85fcc37fd81 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -12,10 +12,10 @@ complete -c x.py -n "__fish_use_subcommand" -l keep-stage -d 'stage(s) to keep w complete -c x.py -n "__fish_use_subcommand" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f complete -c x.py -n "__fish_use_subcommand" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_use_subcommand" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x.py -n "__fish_use_subcommand" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_use_subcommand" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny '',warn '',default ''}" complete -c x.py -n "__fish_use_subcommand" -l error-format -d 'rustc error format' -r -f -complete -c x.py -n "__fish_use_subcommand" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" -complete -c x.py -n "__fish_use_subcommand" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_use_subcommand" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always '',never '',auto ''}" +complete -c x.py -n "__fish_use_subcommand" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true '',false ''}" complete -c x.py -n "__fish_use_subcommand" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F complete -c x.py -n "__fish_use_subcommand" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_use_subcommand" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F @@ -27,6 +27,7 @@ complete -c x.py -n "__fish_use_subcommand" -l include-default-paths -d 'include complete -c x.py -n "__fish_use_subcommand" -l dry-run -d 'dry run; don\'t build anything' complete -c x.py -n "__fish_use_subcommand" -l json-output -d 'use message-format=json' complete -c x.py -n "__fish_use_subcommand" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_use_subcommand" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_use_subcommand" -s h -l help -d 'Print help' complete -c x.py -n "__fish_use_subcommand" -f -a "build" -d 'Compile either the compiler or libraries' complete -c x.py -n "__fish_use_subcommand" -f -a "check" -d 'Compile either the compiler or libraries, using cargo check' @@ -56,10 +57,10 @@ complete -c x.py -n "__fish_seen_subcommand_from build" -l keep-stage -d 'stage( complete -c x.py -n "__fish_seen_subcommand_from build" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f complete -c x.py -n "__fish_seen_subcommand_from build" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_seen_subcommand_from build" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x.py -n "__fish_seen_subcommand_from build" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from build" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny '',warn '',default ''}" complete -c x.py -n "__fish_seen_subcommand_from build" -l error-format -d 'rustc error format' -r -f -complete -c x.py -n "__fish_seen_subcommand_from build" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" -complete -c x.py -n "__fish_seen_subcommand_from build" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from build" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always '',never '',auto ''}" +complete -c x.py -n "__fish_seen_subcommand_from build" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true '',false ''}" complete -c x.py -n "__fish_seen_subcommand_from build" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from build" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from build" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F @@ -71,6 +72,7 @@ complete -c x.py -n "__fish_seen_subcommand_from build" -l include-default-paths complete -c x.py -n "__fish_seen_subcommand_from build" -l dry-run -d 'dry run; don\'t build anything' complete -c x.py -n "__fish_seen_subcommand_from build" -l json-output -d 'use message-format=json' complete -c x.py -n "__fish_seen_subcommand_from build" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from build" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_seen_subcommand_from build" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_seen_subcommand_from check" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_seen_subcommand_from check" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" @@ -86,10 +88,10 @@ complete -c x.py -n "__fish_seen_subcommand_from check" -l keep-stage -d 'stage( complete -c x.py -n "__fish_seen_subcommand_from check" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f complete -c x.py -n "__fish_seen_subcommand_from check" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_seen_subcommand_from check" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x.py -n "__fish_seen_subcommand_from check" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from check" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny '',warn '',default ''}" complete -c x.py -n "__fish_seen_subcommand_from check" -l error-format -d 'rustc error format' -r -f -complete -c x.py -n "__fish_seen_subcommand_from check" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" -complete -c x.py -n "__fish_seen_subcommand_from check" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from check" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always '',never '',auto ''}" +complete -c x.py -n "__fish_seen_subcommand_from check" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true '',false ''}" complete -c x.py -n "__fish_seen_subcommand_from check" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from check" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from check" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F @@ -102,6 +104,7 @@ complete -c x.py -n "__fish_seen_subcommand_from check" -l include-default-paths complete -c x.py -n "__fish_seen_subcommand_from check" -l dry-run -d 'dry run; don\'t build anything' complete -c x.py -n "__fish_seen_subcommand_from check" -l json-output -d 'use message-format=json' complete -c x.py -n "__fish_seen_subcommand_from check" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from check" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_seen_subcommand_from check" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_seen_subcommand_from clippy" -s A -d 'clippy lints to allow' -r complete -c x.py -n "__fish_seen_subcommand_from clippy" -s D -d 'clippy lints to deny' -r @@ -121,10 +124,10 @@ complete -c x.py -n "__fish_seen_subcommand_from clippy" -l keep-stage -d 'stage complete -c x.py -n "__fish_seen_subcommand_from clippy" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f complete -c x.py -n "__fish_seen_subcommand_from clippy" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_seen_subcommand_from clippy" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x.py -n "__fish_seen_subcommand_from clippy" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny '',warn '',default ''}" complete -c x.py -n "__fish_seen_subcommand_from clippy" -l error-format -d 'rustc error format' -r -f -complete -c x.py -n "__fish_seen_subcommand_from clippy" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" -complete -c x.py -n "__fish_seen_subcommand_from clippy" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always '',never '',auto ''}" +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true '',false ''}" complete -c x.py -n "__fish_seen_subcommand_from clippy" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from clippy" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from clippy" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F @@ -137,6 +140,7 @@ complete -c x.py -n "__fish_seen_subcommand_from clippy" -l include-default-path complete -c x.py -n "__fish_seen_subcommand_from clippy" -l dry-run -d 'dry run; don\'t build anything' complete -c x.py -n "__fish_seen_subcommand_from clippy" -l json-output -d 'use message-format=json' complete -c x.py -n "__fish_seen_subcommand_from clippy" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_seen_subcommand_from clippy" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_seen_subcommand_from fix" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_seen_subcommand_from fix" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" @@ -152,10 +156,10 @@ complete -c x.py -n "__fish_seen_subcommand_from fix" -l keep-stage -d 'stage(s) complete -c x.py -n "__fish_seen_subcommand_from fix" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f complete -c x.py -n "__fish_seen_subcommand_from fix" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_seen_subcommand_from fix" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x.py -n "__fish_seen_subcommand_from fix" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from fix" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny '',warn '',default ''}" complete -c x.py -n "__fish_seen_subcommand_from fix" -l error-format -d 'rustc error format' -r -f -complete -c x.py -n "__fish_seen_subcommand_from fix" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" -complete -c x.py -n "__fish_seen_subcommand_from fix" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from fix" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always '',never '',auto ''}" +complete -c x.py -n "__fish_seen_subcommand_from fix" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true '',false ''}" complete -c x.py -n "__fish_seen_subcommand_from fix" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from fix" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from fix" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F @@ -167,6 +171,7 @@ complete -c x.py -n "__fish_seen_subcommand_from fix" -l include-default-paths - complete -c x.py -n "__fish_seen_subcommand_from fix" -l dry-run -d 'dry run; don\'t build anything' complete -c x.py -n "__fish_seen_subcommand_from fix" -l json-output -d 'use message-format=json' complete -c x.py -n "__fish_seen_subcommand_from fix" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from fix" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_seen_subcommand_from fix" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_seen_subcommand_from fmt" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_seen_subcommand_from fmt" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" @@ -182,10 +187,10 @@ complete -c x.py -n "__fish_seen_subcommand_from fmt" -l keep-stage -d 'stage(s) complete -c x.py -n "__fish_seen_subcommand_from fmt" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f complete -c x.py -n "__fish_seen_subcommand_from fmt" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_seen_subcommand_from fmt" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x.py -n "__fish_seen_subcommand_from fmt" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny '',warn '',default ''}" complete -c x.py -n "__fish_seen_subcommand_from fmt" -l error-format -d 'rustc error format' -r -f -complete -c x.py -n "__fish_seen_subcommand_from fmt" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" -complete -c x.py -n "__fish_seen_subcommand_from fmt" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always '',never '',auto ''}" +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true '',false ''}" complete -c x.py -n "__fish_seen_subcommand_from fmt" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from fmt" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from fmt" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F @@ -198,6 +203,7 @@ complete -c x.py -n "__fish_seen_subcommand_from fmt" -l include-default-paths - complete -c x.py -n "__fish_seen_subcommand_from fmt" -l dry-run -d 'dry run; don\'t build anything' complete -c x.py -n "__fish_seen_subcommand_from fmt" -l json-output -d 'use message-format=json' complete -c x.py -n "__fish_seen_subcommand_from fmt" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_seen_subcommand_from fmt" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_seen_subcommand_from doc" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_seen_subcommand_from doc" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" @@ -213,10 +219,10 @@ complete -c x.py -n "__fish_seen_subcommand_from doc" -l keep-stage -d 'stage(s) complete -c x.py -n "__fish_seen_subcommand_from doc" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f complete -c x.py -n "__fish_seen_subcommand_from doc" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_seen_subcommand_from doc" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x.py -n "__fish_seen_subcommand_from doc" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from doc" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny '',warn '',default ''}" complete -c x.py -n "__fish_seen_subcommand_from doc" -l error-format -d 'rustc error format' -r -f -complete -c x.py -n "__fish_seen_subcommand_from doc" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" -complete -c x.py -n "__fish_seen_subcommand_from doc" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from doc" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always '',never '',auto ''}" +complete -c x.py -n "__fish_seen_subcommand_from doc" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true '',false ''}" complete -c x.py -n "__fish_seen_subcommand_from doc" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from doc" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from doc" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F @@ -230,6 +236,7 @@ complete -c x.py -n "__fish_seen_subcommand_from doc" -l include-default-paths - complete -c x.py -n "__fish_seen_subcommand_from doc" -l dry-run -d 'dry run; don\'t build anything' complete -c x.py -n "__fish_seen_subcommand_from doc" -l json-output -d 'use message-format=json' complete -c x.py -n "__fish_seen_subcommand_from doc" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from doc" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_seen_subcommand_from doc" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_seen_subcommand_from test" -l skip -d 'skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times' -r -F complete -c x.py -n "__fish_seen_subcommand_from test" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r @@ -251,10 +258,10 @@ complete -c x.py -n "__fish_seen_subcommand_from test" -l keep-stage -d 'stage(s complete -c x.py -n "__fish_seen_subcommand_from test" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f complete -c x.py -n "__fish_seen_subcommand_from test" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_seen_subcommand_from test" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x.py -n "__fish_seen_subcommand_from test" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from test" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny '',warn '',default ''}" complete -c x.py -n "__fish_seen_subcommand_from test" -l error-format -d 'rustc error format' -r -f -complete -c x.py -n "__fish_seen_subcommand_from test" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" -complete -c x.py -n "__fish_seen_subcommand_from test" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from test" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always '',never '',auto ''}" +complete -c x.py -n "__fish_seen_subcommand_from test" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true '',false ''}" complete -c x.py -n "__fish_seen_subcommand_from test" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from test" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from test" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F @@ -273,6 +280,7 @@ complete -c x.py -n "__fish_seen_subcommand_from test" -l include-default-paths complete -c x.py -n "__fish_seen_subcommand_from test" -l dry-run -d 'dry run; don\'t build anything' complete -c x.py -n "__fish_seen_subcommand_from test" -l json-output -d 'use message-format=json' complete -c x.py -n "__fish_seen_subcommand_from test" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from test" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_seen_subcommand_from test" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_seen_subcommand_from bench" -l test-args -r complete -c x.py -n "__fish_seen_subcommand_from bench" -l config -d 'TOML configuration file for build' -r -F @@ -289,10 +297,10 @@ complete -c x.py -n "__fish_seen_subcommand_from bench" -l keep-stage -d 'stage( complete -c x.py -n "__fish_seen_subcommand_from bench" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f complete -c x.py -n "__fish_seen_subcommand_from bench" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_seen_subcommand_from bench" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x.py -n "__fish_seen_subcommand_from bench" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from bench" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny '',warn '',default ''}" complete -c x.py -n "__fish_seen_subcommand_from bench" -l error-format -d 'rustc error format' -r -f -complete -c x.py -n "__fish_seen_subcommand_from bench" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" -complete -c x.py -n "__fish_seen_subcommand_from bench" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from bench" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always '',never '',auto ''}" +complete -c x.py -n "__fish_seen_subcommand_from bench" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true '',false ''}" complete -c x.py -n "__fish_seen_subcommand_from bench" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from bench" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from bench" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F @@ -304,6 +312,7 @@ complete -c x.py -n "__fish_seen_subcommand_from bench" -l include-default-paths complete -c x.py -n "__fish_seen_subcommand_from bench" -l dry-run -d 'dry run; don\'t build anything' complete -c x.py -n "__fish_seen_subcommand_from bench" -l json-output -d 'use message-format=json' complete -c x.py -n "__fish_seen_subcommand_from bench" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from bench" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_seen_subcommand_from bench" -s h -l help -d 'Print help' complete -c x.py -n "__fish_seen_subcommand_from clean" -l stage -d 'Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used' -r complete -c x.py -n "__fish_seen_subcommand_from clean" -l config -d 'TOML configuration file for build' -r -F @@ -319,10 +328,10 @@ complete -c x.py -n "__fish_seen_subcommand_from clean" -l keep-stage -d 'stage( complete -c x.py -n "__fish_seen_subcommand_from clean" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f complete -c x.py -n "__fish_seen_subcommand_from clean" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_seen_subcommand_from clean" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x.py -n "__fish_seen_subcommand_from clean" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from clean" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny '',warn '',default ''}" complete -c x.py -n "__fish_seen_subcommand_from clean" -l error-format -d 'rustc error format' -r -f -complete -c x.py -n "__fish_seen_subcommand_from clean" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" -complete -c x.py -n "__fish_seen_subcommand_from clean" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from clean" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always '',never '',auto ''}" +complete -c x.py -n "__fish_seen_subcommand_from clean" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true '',false ''}" complete -c x.py -n "__fish_seen_subcommand_from clean" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from clean" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from clean" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F @@ -335,6 +344,7 @@ complete -c x.py -n "__fish_seen_subcommand_from clean" -l include-default-paths complete -c x.py -n "__fish_seen_subcommand_from clean" -l dry-run -d 'dry run; don\'t build anything' complete -c x.py -n "__fish_seen_subcommand_from clean" -l json-output -d 'use message-format=json' complete -c x.py -n "__fish_seen_subcommand_from clean" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from clean" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_seen_subcommand_from clean" -s h -l help -d 'Print help' complete -c x.py -n "__fish_seen_subcommand_from dist" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_seen_subcommand_from dist" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" @@ -350,10 +360,10 @@ complete -c x.py -n "__fish_seen_subcommand_from dist" -l keep-stage -d 'stage(s complete -c x.py -n "__fish_seen_subcommand_from dist" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f complete -c x.py -n "__fish_seen_subcommand_from dist" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_seen_subcommand_from dist" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x.py -n "__fish_seen_subcommand_from dist" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from dist" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny '',warn '',default ''}" complete -c x.py -n "__fish_seen_subcommand_from dist" -l error-format -d 'rustc error format' -r -f -complete -c x.py -n "__fish_seen_subcommand_from dist" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" -complete -c x.py -n "__fish_seen_subcommand_from dist" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from dist" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always '',never '',auto ''}" +complete -c x.py -n "__fish_seen_subcommand_from dist" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true '',false ''}" complete -c x.py -n "__fish_seen_subcommand_from dist" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from dist" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from dist" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F @@ -365,6 +375,7 @@ complete -c x.py -n "__fish_seen_subcommand_from dist" -l include-default-paths complete -c x.py -n "__fish_seen_subcommand_from dist" -l dry-run -d 'dry run; don\'t build anything' complete -c x.py -n "__fish_seen_subcommand_from dist" -l json-output -d 'use message-format=json' complete -c x.py -n "__fish_seen_subcommand_from dist" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from dist" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_seen_subcommand_from dist" -s h -l help -d 'Print help' complete -c x.py -n "__fish_seen_subcommand_from install" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_seen_subcommand_from install" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" @@ -380,10 +391,10 @@ complete -c x.py -n "__fish_seen_subcommand_from install" -l keep-stage -d 'stag complete -c x.py -n "__fish_seen_subcommand_from install" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f complete -c x.py -n "__fish_seen_subcommand_from install" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_seen_subcommand_from install" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x.py -n "__fish_seen_subcommand_from install" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from install" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny '',warn '',default ''}" complete -c x.py -n "__fish_seen_subcommand_from install" -l error-format -d 'rustc error format' -r -f -complete -c x.py -n "__fish_seen_subcommand_from install" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" -complete -c x.py -n "__fish_seen_subcommand_from install" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from install" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always '',never '',auto ''}" +complete -c x.py -n "__fish_seen_subcommand_from install" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true '',false ''}" complete -c x.py -n "__fish_seen_subcommand_from install" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from install" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from install" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F @@ -395,6 +406,7 @@ complete -c x.py -n "__fish_seen_subcommand_from install" -l include-default-pat complete -c x.py -n "__fish_seen_subcommand_from install" -l dry-run -d 'dry run; don\'t build anything' complete -c x.py -n "__fish_seen_subcommand_from install" -l json-output -d 'use message-format=json' complete -c x.py -n "__fish_seen_subcommand_from install" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from install" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print help' complete -c x.py -n "__fish_seen_subcommand_from run" -l args -d 'arguments for the tool' -r complete -c x.py -n "__fish_seen_subcommand_from run" -l config -d 'TOML configuration file for build' -r -F @@ -411,10 +423,10 @@ complete -c x.py -n "__fish_seen_subcommand_from run" -l keep-stage -d 'stage(s) complete -c x.py -n "__fish_seen_subcommand_from run" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f complete -c x.py -n "__fish_seen_subcommand_from run" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_seen_subcommand_from run" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x.py -n "__fish_seen_subcommand_from run" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from run" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny '',warn '',default ''}" complete -c x.py -n "__fish_seen_subcommand_from run" -l error-format -d 'rustc error format' -r -f -complete -c x.py -n "__fish_seen_subcommand_from run" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" -complete -c x.py -n "__fish_seen_subcommand_from run" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from run" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always '',never '',auto ''}" +complete -c x.py -n "__fish_seen_subcommand_from run" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true '',false ''}" complete -c x.py -n "__fish_seen_subcommand_from run" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from run" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from run" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F @@ -426,6 +438,7 @@ complete -c x.py -n "__fish_seen_subcommand_from run" -l include-default-paths - complete -c x.py -n "__fish_seen_subcommand_from run" -l dry-run -d 'dry run; don\'t build anything' complete -c x.py -n "__fish_seen_subcommand_from run" -l json-output -d 'use message-format=json' complete -c x.py -n "__fish_seen_subcommand_from run" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from run" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_seen_subcommand_from run" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_seen_subcommand_from setup" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_seen_subcommand_from setup" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" @@ -441,10 +454,10 @@ complete -c x.py -n "__fish_seen_subcommand_from setup" -l keep-stage -d 'stage( complete -c x.py -n "__fish_seen_subcommand_from setup" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f complete -c x.py -n "__fish_seen_subcommand_from setup" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_seen_subcommand_from setup" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x.py -n "__fish_seen_subcommand_from setup" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from setup" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny '',warn '',default ''}" complete -c x.py -n "__fish_seen_subcommand_from setup" -l error-format -d 'rustc error format' -r -f -complete -c x.py -n "__fish_seen_subcommand_from setup" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" -complete -c x.py -n "__fish_seen_subcommand_from setup" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from setup" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always '',never '',auto ''}" +complete -c x.py -n "__fish_seen_subcommand_from setup" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true '',false ''}" complete -c x.py -n "__fish_seen_subcommand_from setup" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from setup" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from setup" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F @@ -456,6 +469,7 @@ complete -c x.py -n "__fish_seen_subcommand_from setup" -l include-default-paths complete -c x.py -n "__fish_seen_subcommand_from setup" -l dry-run -d 'dry run; don\'t build anything' complete -c x.py -n "__fish_seen_subcommand_from setup" -l json-output -d 'use message-format=json' complete -c x.py -n "__fish_seen_subcommand_from setup" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from setup" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_seen_subcommand_from setup" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_seen_subcommand_from suggest" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_seen_subcommand_from suggest" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" @@ -471,10 +485,10 @@ complete -c x.py -n "__fish_seen_subcommand_from suggest" -l keep-stage -d 'stag complete -c x.py -n "__fish_seen_subcommand_from suggest" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f complete -c x.py -n "__fish_seen_subcommand_from suggest" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" complete -c x.py -n "__fish_seen_subcommand_from suggest" -s j -l jobs -d 'number of jobs to run in parallel' -r -f -complete -c x.py -n "__fish_seen_subcommand_from suggest" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny '',warn '',default ''}" complete -c x.py -n "__fish_seen_subcommand_from suggest" -l error-format -d 'rustc error format' -r -f -complete -c x.py -n "__fish_seen_subcommand_from suggest" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" -complete -c x.py -n "__fish_seen_subcommand_from suggest" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always '',never '',auto ''}" +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true '',false ''}" complete -c x.py -n "__fish_seen_subcommand_from suggest" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from suggest" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F complete -c x.py -n "__fish_seen_subcommand_from suggest" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F @@ -487,4 +501,5 @@ complete -c x.py -n "__fish_seen_subcommand_from suggest" -l include-default-pat complete -c x.py -n "__fish_seen_subcommand_from suggest" -l dry-run -d 'dry run; don\'t build anything' complete -c x.py -n "__fish_seen_subcommand_from suggest" -l json-output -d 'use message-format=json' complete -c x.py -n "__fish_seen_subcommand_from suggest" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l enable-bolt-settings -d 'Enable BOLT link flags' complete -c x.py -n "__fish_seen_subcommand_from suggest" -s h -l help -d 'Print help (see more with \'--help\')' diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index cafb8eed12d..07e1b0ace9d 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -53,6 +53,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--enable-bolt-settings', 'enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help') [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help') [CompletionResult]::new('build', 'build', [CompletionResultType]::ParameterValue, 'Compile either the compiler or libraries') @@ -104,6 +105,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--enable-bolt-settings', 'enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -142,15 +144,16 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--enable-bolt-settings', 'enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break } 'x.py;clippy' { - [CompletionResult]::new('-A', 'A', [CompletionResultType]::ParameterName, 'clippy lints to allow') - [CompletionResult]::new('-D', 'D', [CompletionResultType]::ParameterName, 'clippy lints to deny') - [CompletionResult]::new('-W', 'W', [CompletionResultType]::ParameterName, 'clippy lints to warn on') - [CompletionResult]::new('-F', 'F', [CompletionResultType]::ParameterName, 'clippy lints to forbid') + [CompletionResult]::new('-A', 'A ', [CompletionResultType]::ParameterName, 'clippy lints to allow') + [CompletionResult]::new('-D', 'D ', [CompletionResultType]::ParameterName, 'clippy lints to deny') + [CompletionResult]::new('-W', 'W ', [CompletionResultType]::ParameterName, 'clippy lints to warn on') + [CompletionResult]::new('-F', 'F ', [CompletionResultType]::ParameterName, 'clippy lints to forbid') [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`') [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') @@ -184,6 +187,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--enable-bolt-settings', 'enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -221,6 +225,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--enable-bolt-settings', 'enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -259,6 +264,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--enable-bolt-settings', 'enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -298,6 +304,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--enable-bolt-settings', 'enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -348,6 +355,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--enable-bolt-settings', 'enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -386,6 +394,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--enable-bolt-settings', 'enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help') [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help') break @@ -424,6 +433,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--enable-bolt-settings', 'enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help') [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help') break @@ -461,6 +471,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--enable-bolt-settings', 'enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help') [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help') break @@ -498,6 +509,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--enable-bolt-settings', 'enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help') [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help') break @@ -536,6 +548,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--enable-bolt-settings', 'enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -573,6 +586,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--enable-bolt-settings', 'enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break @@ -611,6 +625,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--enable-bolt-settings', 'enable-bolt-settings', [CompletionResultType]::ParameterName, 'Enable BOLT link flags') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') break diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh index 3c57e71bdb7..241bc058e7b 100644 --- a/src/etc/completions/x.py.sh +++ b/src/etc/completions/x.py.sh @@ -61,7 +61,7 @@ _x.py() { case "${cmd}" in x.py) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]... build check clippy fix fmt doc test bench clean dist install run setup suggest" + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --reproducible-artifact --set --help [PATHS]... [ARGS]... build check clippy fix fmt doc test bench clean dist install run setup suggest" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -171,7 +171,7 @@ _x.py() { return 0 ;; x.py__bench) - opts="-v -i -j -h --test-args --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --test-args --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --reproducible-artifact --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -285,7 +285,7 @@ _x.py() { return 0 ;; x.py__build) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --reproducible-artifact --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -395,7 +395,7 @@ _x.py() { return 0 ;; x.py__check) - opts="-v -i -j -h --all-targets --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --all-targets --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --reproducible-artifact --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -505,7 +505,7 @@ _x.py() { return 0 ;; x.py__clean) - opts="-v -i -j -h --all --stage --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --all --stage --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --reproducible-artifact --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -615,7 +615,7 @@ _x.py() { return 0 ;; x.py__clippy) - opts="-A -D -W -F -v -i -j -h --fix --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..." + opts="-A -D -W -F -v -i -j -h --fix --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --reproducible-artifact --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -741,7 +741,7 @@ _x.py() { return 0 ;; x.py__dist) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --reproducible-artifact --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -851,7 +851,7 @@ _x.py() { return 0 ;; x.py__doc) - opts="-v -i -j -h --open --json --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --open --json --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --reproducible-artifact --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -961,7 +961,7 @@ _x.py() { return 0 ;; x.py__fix) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --reproducible-artifact --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1071,7 +1071,7 @@ _x.py() { return 0 ;; x.py__fmt) - opts="-v -i -j -h --check --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --check --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --reproducible-artifact --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1181,7 +1181,7 @@ _x.py() { return 0 ;; x.py__install) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --reproducible-artifact --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1291,7 +1291,7 @@ _x.py() { return 0 ;; x.py__run) - opts="-v -i -j -h --args --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --args --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --reproducible-artifact --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1405,7 +1405,7 @@ _x.py() { return 0 ;; x.py__setup) - opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [<PROFILE>|hook|vscode|link] [PATHS]... [ARGS]..." + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --reproducible-artifact --set --help [<PROFILE>|hook|vscode|link] [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1515,7 +1515,7 @@ _x.py() { return 0 ;; x.py__suggest) - opts="-v -i -j -h --run --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --run --verbose --incremental --config --build-dir --build --host --target --exclude --skip --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --reproducible-artifact --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1625,7 +1625,7 @@ _x.py() { return 0 ;; x.py__test) - opts="-v -i -j -h --no-fail-fast --skip --test-args --rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --reproducible-artifact --set --help [PATHS]... [ARGS]..." + opts="-v -i -j -h --no-fail-fast --skip --test-args --rustc-args --no-doc --doc --bless --extra-checks --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --enable-bolt-settings --reproducible-artifact --set --help [PATHS]... [ARGS]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1761,4 +1761,4 @@ _x.py() { esac } -complete -F _x.py -o bashdefault -o default x.py +complete -F _x.py -o nosort -o bashdefault -o default x.py diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh new file mode 100644 index 00000000000..89959701a06 --- /dev/null +++ b/src/etc/completions/x.py.zsh @@ -0,0 +1,751 @@ +#compdef x.py + +autoload -U is-at-least + +_x.py() { + typeset -A opt_args + typeset -a _arguments_options + local ret=1 + + if is-at-least 5.2; then + _arguments_options=(-s -S -C) + else + _arguments_options=(-s -C) + fi + + local context curcontext="$curcontext" state line + _arguments "${_arguments_options[@]}" \ +'--config=[TOML configuration file for build]:FILE:_files' \ +'--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \ +'--build=[build target of the stage0 compiler]:BUILD:( )' \ +'--host=[host targets to build]:HOST:( )' \ +'--target=[target targets to build]:TARGET:( )' \ +'*--exclude=[build paths to exclude]:PATH:_files' \ +'*--skip=[build paths to skip]:PATH:_files' \ +'--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \ +'--on-fail=[command to run on failure]:CMD:_cmdstring' \ +'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \ +'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'--src=[path to the root of the rust checkout]:DIR:_files -/' \ +'-j+[number of jobs to run in parallel]:JOBS:( )' \ +'--jobs=[number of jobs to run in parallel]:JOBS:( )' \ +'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ +'--error-format=[rustc error format]:FORMAT:( )' \ +'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ +'--llvm-skip-rebuild=[whether rebuilding llvm should be skipped, overriding \`skip-rebuld\` in config.toml]:VALUE:(true false)' \ +'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ +'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ +'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ +'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \ +'*--set=[override options in config.toml]:section.option=value:( )' \ +'*-v[use verbose output (-vv for very verbose)]' \ +'*--verbose[use verbose output (-vv for very verbose)]' \ +'-i[use incremental compilation]' \ +'--incremental[use incremental compilation]' \ +'--include-default-paths[include default paths in addition to the provided ones]' \ +'--dry-run[dry run; don'\''t build anything]' \ +'--json-output[use message-format=json]' \ +'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ +'--enable-bolt-settings[Enable BOLT link flags]' \ +'-h[Print help]' \ +'--help[Print help]' \ +'::paths -- paths for the subcommand:_files' \ +'::free_args -- arguments passed to subcommands:' \ +":: :_x.py_commands" \ +"*::: :->bootstrap" \ +&& ret=0 + case $state in + (bootstrap) + words=($line[3] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:x.py-command-$line[3]:" + case $line[3] in + (build) +_arguments "${_arguments_options[@]}" \ +'--config=[TOML configuration file for build]:FILE:_files' \ +'--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \ +'--build=[build target of the stage0 compiler]:BUILD:( )' \ +'--host=[host targets to build]:HOST:( )' \ +'--target=[target targets to build]:TARGET:( )' \ +'*--exclude=[build paths to exclude]:PATH:_files' \ +'*--skip=[build paths to skip]:PATH:_files' \ +'--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \ +'--on-fail=[command to run on failure]:CMD:_cmdstring' \ +'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \ +'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'--src=[path to the root of the rust checkout]:DIR:_files -/' \ +'-j+[number of jobs to run in parallel]:JOBS:( )' \ +'--jobs=[number of jobs to run in parallel]:JOBS:( )' \ +'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ +'--error-format=[rustc error format]:FORMAT:( )' \ +'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ +'--llvm-skip-rebuild=[whether rebuilding llvm should be skipped, overriding \`skip-rebuld\` in config.toml]:VALUE:(true false)' \ +'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ +'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ +'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ +'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \ +'*--set=[override options in config.toml]:section.option=value:( )' \ +'*-v[use verbose output (-vv for very verbose)]' \ +'*--verbose[use verbose output (-vv for very verbose)]' \ +'-i[use incremental compilation]' \ +'--incremental[use incremental compilation]' \ +'--include-default-paths[include default paths in addition to the provided ones]' \ +'--dry-run[dry run; don'\''t build anything]' \ +'--json-output[use message-format=json]' \ +'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ +'--enable-bolt-settings[Enable BOLT link flags]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::paths -- paths for the subcommand:_files' \ +&& ret=0 +;; +(check) +_arguments "${_arguments_options[@]}" \ +'--config=[TOML configuration file for build]:FILE:_files' \ +'--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \ +'--build=[build target of the stage0 compiler]:BUILD:( )' \ +'--host=[host targets to build]:HOST:( )' \ +'--target=[target targets to build]:TARGET:( )' \ +'*--exclude=[build paths to exclude]:PATH:_files' \ +'*--skip=[build paths to skip]:PATH:_files' \ +'--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \ +'--on-fail=[command to run on failure]:CMD:_cmdstring' \ +'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \ +'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'--src=[path to the root of the rust checkout]:DIR:_files -/' \ +'-j+[number of jobs to run in parallel]:JOBS:( )' \ +'--jobs=[number of jobs to run in parallel]:JOBS:( )' \ +'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ +'--error-format=[rustc error format]:FORMAT:( )' \ +'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ +'--llvm-skip-rebuild=[whether rebuilding llvm should be skipped, overriding \`skip-rebuld\` in config.toml]:VALUE:(true false)' \ +'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ +'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ +'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ +'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \ +'*--set=[override options in config.toml]:section.option=value:( )' \ +'--all-targets[Check all targets]' \ +'*-v[use verbose output (-vv for very verbose)]' \ +'*--verbose[use verbose output (-vv for very verbose)]' \ +'-i[use incremental compilation]' \ +'--incremental[use incremental compilation]' \ +'--include-default-paths[include default paths in addition to the provided ones]' \ +'--dry-run[dry run; don'\''t build anything]' \ +'--json-output[use message-format=json]' \ +'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ +'--enable-bolt-settings[Enable BOLT link flags]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::paths -- paths for the subcommand:_files' \ +&& ret=0 +;; +(clippy) +_arguments "${_arguments_options[@]}" \ +'*-A+[clippy lints to allow]:LINT: ' \ +'*-D+[clippy lints to deny]:LINT: ' \ +'*-W+[clippy lints to warn on]:LINT: ' \ +'*-F+[clippy lints to forbid]:LINT: ' \ +'--config=[TOML configuration file for build]:FILE:_files' \ +'--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \ +'--build=[build target of the stage0 compiler]:BUILD:( )' \ +'--host=[host targets to build]:HOST:( )' \ +'--target=[target targets to build]:TARGET:( )' \ +'*--exclude=[build paths to exclude]:PATH:_files' \ +'*--skip=[build paths to skip]:PATH:_files' \ +'--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \ +'--on-fail=[command to run on failure]:CMD:_cmdstring' \ +'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \ +'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'--src=[path to the root of the rust checkout]:DIR:_files -/' \ +'-j+[number of jobs to run in parallel]:JOBS:( )' \ +'--jobs=[number of jobs to run in parallel]:JOBS:( )' \ +'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ +'--error-format=[rustc error format]:FORMAT:( )' \ +'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ +'--llvm-skip-rebuild=[whether rebuilding llvm should be skipped, overriding \`skip-rebuld\` in config.toml]:VALUE:(true false)' \ +'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ +'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ +'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ +'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \ +'*--set=[override options in config.toml]:section.option=value:( )' \ +'--fix[]' \ +'*-v[use verbose output (-vv for very verbose)]' \ +'*--verbose[use verbose output (-vv for very verbose)]' \ +'-i[use incremental compilation]' \ +'--incremental[use incremental compilation]' \ +'--include-default-paths[include default paths in addition to the provided ones]' \ +'--dry-run[dry run; don'\''t build anything]' \ +'--json-output[use message-format=json]' \ +'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ +'--enable-bolt-settings[Enable BOLT link flags]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::paths -- paths for the subcommand:_files' \ +&& ret=0 +;; +(fix) +_arguments "${_arguments_options[@]}" \ +'--config=[TOML configuration file for build]:FILE:_files' \ +'--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \ +'--build=[build target of the stage0 compiler]:BUILD:( )' \ +'--host=[host targets to build]:HOST:( )' \ +'--target=[target targets to build]:TARGET:( )' \ +'*--exclude=[build paths to exclude]:PATH:_files' \ +'*--skip=[build paths to skip]:PATH:_files' \ +'--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \ +'--on-fail=[command to run on failure]:CMD:_cmdstring' \ +'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \ +'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'--src=[path to the root of the rust checkout]:DIR:_files -/' \ +'-j+[number of jobs to run in parallel]:JOBS:( )' \ +'--jobs=[number of jobs to run in parallel]:JOBS:( )' \ +'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ +'--error-format=[rustc error format]:FORMAT:( )' \ +'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ +'--llvm-skip-rebuild=[whether rebuilding llvm should be skipped, overriding \`skip-rebuld\` in config.toml]:VALUE:(true false)' \ +'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ +'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ +'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ +'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \ +'*--set=[override options in config.toml]:section.option=value:( )' \ +'*-v[use verbose output (-vv for very verbose)]' \ +'*--verbose[use verbose output (-vv for very verbose)]' \ +'-i[use incremental compilation]' \ +'--incremental[use incremental compilation]' \ +'--include-default-paths[include default paths in addition to the provided ones]' \ +'--dry-run[dry run; don'\''t build anything]' \ +'--json-output[use message-format=json]' \ +'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ +'--enable-bolt-settings[Enable BOLT link flags]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::paths -- paths for the subcommand:_files' \ +&& ret=0 +;; +(fmt) +_arguments "${_arguments_options[@]}" \ +'--config=[TOML configuration file for build]:FILE:_files' \ +'--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \ +'--build=[build target of the stage0 compiler]:BUILD:( )' \ +'--host=[host targets to build]:HOST:( )' \ +'--target=[target targets to build]:TARGET:( )' \ +'*--exclude=[build paths to exclude]:PATH:_files' \ +'*--skip=[build paths to skip]:PATH:_files' \ +'--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \ +'--on-fail=[command to run on failure]:CMD:_cmdstring' \ +'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \ +'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'--src=[path to the root of the rust checkout]:DIR:_files -/' \ +'-j+[number of jobs to run in parallel]:JOBS:( )' \ +'--jobs=[number of jobs to run in parallel]:JOBS:( )' \ +'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ +'--error-format=[rustc error format]:FORMAT:( )' \ +'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ +'--llvm-skip-rebuild=[whether rebuilding llvm should be skipped, overriding \`skip-rebuld\` in config.toml]:VALUE:(true false)' \ +'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ +'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ +'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ +'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \ +'*--set=[override options in config.toml]:section.option=value:( )' \ +'--check[check formatting instead of applying]' \ +'*-v[use verbose output (-vv for very verbose)]' \ +'*--verbose[use verbose output (-vv for very verbose)]' \ +'-i[use incremental compilation]' \ +'--incremental[use incremental compilation]' \ +'--include-default-paths[include default paths in addition to the provided ones]' \ +'--dry-run[dry run; don'\''t build anything]' \ +'--json-output[use message-format=json]' \ +'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ +'--enable-bolt-settings[Enable BOLT link flags]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::paths -- paths for the subcommand:_files' \ +&& ret=0 +;; +(doc) +_arguments "${_arguments_options[@]}" \ +'--config=[TOML configuration file for build]:FILE:_files' \ +'--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \ +'--build=[build target of the stage0 compiler]:BUILD:( )' \ +'--host=[host targets to build]:HOST:( )' \ +'--target=[target targets to build]:TARGET:( )' \ +'*--exclude=[build paths to exclude]:PATH:_files' \ +'*--skip=[build paths to skip]:PATH:_files' \ +'--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \ +'--on-fail=[command to run on failure]:CMD:_cmdstring' \ +'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \ +'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'--src=[path to the root of the rust checkout]:DIR:_files -/' \ +'-j+[number of jobs to run in parallel]:JOBS:( )' \ +'--jobs=[number of jobs to run in parallel]:JOBS:( )' \ +'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ +'--error-format=[rustc error format]:FORMAT:( )' \ +'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ +'--llvm-skip-rebuild=[whether rebuilding llvm should be skipped, overriding \`skip-rebuld\` in config.toml]:VALUE:(true false)' \ +'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ +'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ +'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ +'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \ +'*--set=[override options in config.toml]:section.option=value:( )' \ +'--open[open the docs in a browser]' \ +'--json[render the documentation in JSON format in addition to the usual HTML format]' \ +'*-v[use verbose output (-vv for very verbose)]' \ +'*--verbose[use verbose output (-vv for very verbose)]' \ +'-i[use incremental compilation]' \ +'--incremental[use incremental compilation]' \ +'--include-default-paths[include default paths in addition to the provided ones]' \ +'--dry-run[dry run; don'\''t build anything]' \ +'--json-output[use message-format=json]' \ +'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ +'--enable-bolt-settings[Enable BOLT link flags]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::paths -- paths for the subcommand:_files' \ +&& ret=0 +;; +(test) +_arguments "${_arguments_options[@]}" \ +'*--skip=[skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times]:SUBSTRING:_files' \ +'*--test-args=[extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)]:ARGS: ' \ +'*--rustc-args=[extra options to pass the compiler when running tests]:ARGS: ' \ +'--extra-checks=[comma-separated list of other files types to check (accepts py, py\:lint, py\:fmt, shell)]:EXTRA_CHECKS: ' \ +'--compare-mode=[mode describing what file the actual ui output will be compared to]:COMPARE MODE: ' \ +'--pass=[force {check,build,run}-pass tests to this mode]:check | build | run: ' \ +'--run=[whether to execute run-* tests]:auto | always | never: ' \ +'--config=[TOML configuration file for build]:FILE:_files' \ +'--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \ +'--build=[build target of the stage0 compiler]:BUILD:( )' \ +'--host=[host targets to build]:HOST:( )' \ +'--target=[target targets to build]:TARGET:( )' \ +'*--exclude=[build paths to exclude]:PATH:_files' \ +'--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \ +'--on-fail=[command to run on failure]:CMD:_cmdstring' \ +'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \ +'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'--src=[path to the root of the rust checkout]:DIR:_files -/' \ +'-j+[number of jobs to run in parallel]:JOBS:( )' \ +'--jobs=[number of jobs to run in parallel]:JOBS:( )' \ +'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ +'--error-format=[rustc error format]:FORMAT:( )' \ +'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ +'--llvm-skip-rebuild=[whether rebuilding llvm should be skipped, overriding \`skip-rebuld\` in config.toml]:VALUE:(true false)' \ +'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ +'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ +'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ +'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \ +'*--set=[override options in config.toml]:section.option=value:( )' \ +'--no-fail-fast[run all tests regardless of failure]' \ +'--no-doc[do not run doc tests]' \ +'--doc[only run doc tests]' \ +'--bless[whether to automatically update stderr/stdout files]' \ +'--force-rerun[rerun tests even if the inputs are unchanged]' \ +'--only-modified[only run tests that result has been changed]' \ +'--rustfix-coverage[enable this to generate a Rustfix coverage file, which is saved in \`/<build_base>/rustfix_missing_coverage.txt\`]' \ +'*-v[use verbose output (-vv for very verbose)]' \ +'*--verbose[use verbose output (-vv for very verbose)]' \ +'-i[use incremental compilation]' \ +'--incremental[use incremental compilation]' \ +'--include-default-paths[include default paths in addition to the provided ones]' \ +'--dry-run[dry run; don'\''t build anything]' \ +'--json-output[use message-format=json]' \ +'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ +'--enable-bolt-settings[Enable BOLT link flags]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::paths -- paths for the subcommand:_files' \ +&& ret=0 +;; +(bench) +_arguments "${_arguments_options[@]}" \ +'*--test-args=[]:TEST_ARGS: ' \ +'--config=[TOML configuration file for build]:FILE:_files' \ +'--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \ +'--build=[build target of the stage0 compiler]:BUILD:( )' \ +'--host=[host targets to build]:HOST:( )' \ +'--target=[target targets to build]:TARGET:( )' \ +'*--exclude=[build paths to exclude]:PATH:_files' \ +'*--skip=[build paths to skip]:PATH:_files' \ +'--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \ +'--on-fail=[command to run on failure]:CMD:_cmdstring' \ +'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \ +'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'--src=[path to the root of the rust checkout]:DIR:_files -/' \ +'-j+[number of jobs to run in parallel]:JOBS:( )' \ +'--jobs=[number of jobs to run in parallel]:JOBS:( )' \ +'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ +'--error-format=[rustc error format]:FORMAT:( )' \ +'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ +'--llvm-skip-rebuild=[whether rebuilding llvm should be skipped, overriding \`skip-rebuld\` in config.toml]:VALUE:(true false)' \ +'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ +'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ +'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ +'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \ +'*--set=[override options in config.toml]:section.option=value:( )' \ +'*-v[use verbose output (-vv for very verbose)]' \ +'*--verbose[use verbose output (-vv for very verbose)]' \ +'-i[use incremental compilation]' \ +'--incremental[use incremental compilation]' \ +'--include-default-paths[include default paths in addition to the provided ones]' \ +'--dry-run[dry run; don'\''t build anything]' \ +'--json-output[use message-format=json]' \ +'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ +'--enable-bolt-settings[Enable BOLT link flags]' \ +'-h[Print help]' \ +'--help[Print help]' \ +'*::paths -- paths for the subcommand:_files' \ +&& ret=0 +;; +(clean) +_arguments "${_arguments_options[@]}" \ +'--stage=[Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used]:N: ' \ +'--config=[TOML configuration file for build]:FILE:_files' \ +'--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \ +'--build=[build target of the stage0 compiler]:BUILD:( )' \ +'--host=[host targets to build]:HOST:( )' \ +'--target=[target targets to build]:TARGET:( )' \ +'*--exclude=[build paths to exclude]:PATH:_files' \ +'*--skip=[build paths to skip]:PATH:_files' \ +'--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \ +'--on-fail=[command to run on failure]:CMD:_cmdstring' \ +'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'--src=[path to the root of the rust checkout]:DIR:_files -/' \ +'-j+[number of jobs to run in parallel]:JOBS:( )' \ +'--jobs=[number of jobs to run in parallel]:JOBS:( )' \ +'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ +'--error-format=[rustc error format]:FORMAT:( )' \ +'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ +'--llvm-skip-rebuild=[whether rebuilding llvm should be skipped, overriding \`skip-rebuld\` in config.toml]:VALUE:(true false)' \ +'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ +'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ +'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ +'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \ +'*--set=[override options in config.toml]:section.option=value:( )' \ +'--all[Clean the entire build directory (not used by default)]' \ +'*-v[use verbose output (-vv for very verbose)]' \ +'*--verbose[use verbose output (-vv for very verbose)]' \ +'-i[use incremental compilation]' \ +'--incremental[use incremental compilation]' \ +'--include-default-paths[include default paths in addition to the provided ones]' \ +'--dry-run[dry run; don'\''t build anything]' \ +'--json-output[use message-format=json]' \ +'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ +'--enable-bolt-settings[Enable BOLT link flags]' \ +'-h[Print help]' \ +'--help[Print help]' \ +'*::paths -- paths for the subcommand:_files' \ +&& ret=0 +;; +(dist) +_arguments "${_arguments_options[@]}" \ +'--config=[TOML configuration file for build]:FILE:_files' \ +'--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \ +'--build=[build target of the stage0 compiler]:BUILD:( )' \ +'--host=[host targets to build]:HOST:( )' \ +'--target=[target targets to build]:TARGET:( )' \ +'*--exclude=[build paths to exclude]:PATH:_files' \ +'*--skip=[build paths to skip]:PATH:_files' \ +'--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \ +'--on-fail=[command to run on failure]:CMD:_cmdstring' \ +'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \ +'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'--src=[path to the root of the rust checkout]:DIR:_files -/' \ +'-j+[number of jobs to run in parallel]:JOBS:( )' \ +'--jobs=[number of jobs to run in parallel]:JOBS:( )' \ +'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ +'--error-format=[rustc error format]:FORMAT:( )' \ +'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ +'--llvm-skip-rebuild=[whether rebuilding llvm should be skipped, overriding \`skip-rebuld\` in config.toml]:VALUE:(true false)' \ +'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ +'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ +'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ +'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \ +'*--set=[override options in config.toml]:section.option=value:( )' \ +'*-v[use verbose output (-vv for very verbose)]' \ +'*--verbose[use verbose output (-vv for very verbose)]' \ +'-i[use incremental compilation]' \ +'--incremental[use incremental compilation]' \ +'--include-default-paths[include default paths in addition to the provided ones]' \ +'--dry-run[dry run; don'\''t build anything]' \ +'--json-output[use message-format=json]' \ +'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ +'--enable-bolt-settings[Enable BOLT link flags]' \ +'-h[Print help]' \ +'--help[Print help]' \ +'*::paths -- paths for the subcommand:_files' \ +&& ret=0 +;; +(install) +_arguments "${_arguments_options[@]}" \ +'--config=[TOML configuration file for build]:FILE:_files' \ +'--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \ +'--build=[build target of the stage0 compiler]:BUILD:( )' \ +'--host=[host targets to build]:HOST:( )' \ +'--target=[target targets to build]:TARGET:( )' \ +'*--exclude=[build paths to exclude]:PATH:_files' \ +'*--skip=[build paths to skip]:PATH:_files' \ +'--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \ +'--on-fail=[command to run on failure]:CMD:_cmdstring' \ +'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \ +'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'--src=[path to the root of the rust checkout]:DIR:_files -/' \ +'-j+[number of jobs to run in parallel]:JOBS:( )' \ +'--jobs=[number of jobs to run in parallel]:JOBS:( )' \ +'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ +'--error-format=[rustc error format]:FORMAT:( )' \ +'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ +'--llvm-skip-rebuild=[whether rebuilding llvm should be skipped, overriding \`skip-rebuld\` in config.toml]:VALUE:(true false)' \ +'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ +'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ +'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ +'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \ +'*--set=[override options in config.toml]:section.option=value:( )' \ +'*-v[use verbose output (-vv for very verbose)]' \ +'*--verbose[use verbose output (-vv for very verbose)]' \ +'-i[use incremental compilation]' \ +'--incremental[use incremental compilation]' \ +'--include-default-paths[include default paths in addition to the provided ones]' \ +'--dry-run[dry run; don'\''t build anything]' \ +'--json-output[use message-format=json]' \ +'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ +'--enable-bolt-settings[Enable BOLT link flags]' \ +'-h[Print help]' \ +'--help[Print help]' \ +'*::paths -- paths for the subcommand:_files' \ +&& ret=0 +;; +(run) +_arguments "${_arguments_options[@]}" \ +'*--args=[arguments for the tool]:ARGS: ' \ +'--config=[TOML configuration file for build]:FILE:_files' \ +'--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \ +'--build=[build target of the stage0 compiler]:BUILD:( )' \ +'--host=[host targets to build]:HOST:( )' \ +'--target=[target targets to build]:TARGET:( )' \ +'*--exclude=[build paths to exclude]:PATH:_files' \ +'*--skip=[build paths to skip]:PATH:_files' \ +'--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \ +'--on-fail=[command to run on failure]:CMD:_cmdstring' \ +'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \ +'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'--src=[path to the root of the rust checkout]:DIR:_files -/' \ +'-j+[number of jobs to run in parallel]:JOBS:( )' \ +'--jobs=[number of jobs to run in parallel]:JOBS:( )' \ +'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ +'--error-format=[rustc error format]:FORMAT:( )' \ +'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ +'--llvm-skip-rebuild=[whether rebuilding llvm should be skipped, overriding \`skip-rebuld\` in config.toml]:VALUE:(true false)' \ +'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ +'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ +'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ +'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \ +'*--set=[override options in config.toml]:section.option=value:( )' \ +'*-v[use verbose output (-vv for very verbose)]' \ +'*--verbose[use verbose output (-vv for very verbose)]' \ +'-i[use incremental compilation]' \ +'--incremental[use incremental compilation]' \ +'--include-default-paths[include default paths in addition to the provided ones]' \ +'--dry-run[dry run; don'\''t build anything]' \ +'--json-output[use message-format=json]' \ +'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ +'--enable-bolt-settings[Enable BOLT link flags]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::paths -- paths for the subcommand:_files' \ +&& ret=0 +;; +(setup) +_arguments "${_arguments_options[@]}" \ +'--config=[TOML configuration file for build]:FILE:_files' \ +'--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \ +'--build=[build target of the stage0 compiler]:BUILD:( )' \ +'--host=[host targets to build]:HOST:( )' \ +'--target=[target targets to build]:TARGET:( )' \ +'*--exclude=[build paths to exclude]:PATH:_files' \ +'*--skip=[build paths to skip]:PATH:_files' \ +'--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \ +'--on-fail=[command to run on failure]:CMD:_cmdstring' \ +'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \ +'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'--src=[path to the root of the rust checkout]:DIR:_files -/' \ +'-j+[number of jobs to run in parallel]:JOBS:( )' \ +'--jobs=[number of jobs to run in parallel]:JOBS:( )' \ +'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ +'--error-format=[rustc error format]:FORMAT:( )' \ +'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ +'--llvm-skip-rebuild=[whether rebuilding llvm should be skipped, overriding \`skip-rebuld\` in config.toml]:VALUE:(true false)' \ +'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ +'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ +'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ +'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \ +'*--set=[override options in config.toml]:section.option=value:( )' \ +'*-v[use verbose output (-vv for very verbose)]' \ +'*--verbose[use verbose output (-vv for very verbose)]' \ +'-i[use incremental compilation]' \ +'--incremental[use incremental compilation]' \ +'--include-default-paths[include default paths in addition to the provided ones]' \ +'--dry-run[dry run; don'\''t build anything]' \ +'--json-output[use message-format=json]' \ +'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ +'--enable-bolt-settings[Enable BOLT link flags]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'::profile -- Either the profile for `config.toml` or another setup action. May be omitted to set up interactively:_files' \ +'*::paths -- paths for the subcommand:_files' \ +&& ret=0 +;; +(suggest) +_arguments "${_arguments_options[@]}" \ +'--config=[TOML configuration file for build]:FILE:_files' \ +'--build-dir=[Build directory, overrides \`build.build-dir\` in \`config.toml\`]:DIR:_files -/' \ +'--build=[build target of the stage0 compiler]:BUILD:( )' \ +'--host=[host targets to build]:HOST:( )' \ +'--target=[target targets to build]:TARGET:( )' \ +'*--exclude=[build paths to exclude]:PATH:_files' \ +'*--skip=[build paths to skip]:PATH:_files' \ +'--rustc-error-format=[]:RUSTC_ERROR_FORMAT:( )' \ +'--on-fail=[command to run on failure]:CMD:_cmdstring' \ +'--stage=[stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)]:N:( )' \ +'*--keep-stage=[stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'*--keep-stage-std=[stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)]:N:( )' \ +'--src=[path to the root of the rust checkout]:DIR:_files -/' \ +'-j+[number of jobs to run in parallel]:JOBS:( )' \ +'--jobs=[number of jobs to run in parallel]:JOBS:( )' \ +'--warnings=[if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour]:deny|warn:(deny warn default)' \ +'--error-format=[rustc error format]:FORMAT:( )' \ +'--color=[whether to use color in cargo and rustc output]:STYLE:(always never auto)' \ +'--llvm-skip-rebuild=[whether rebuilding llvm should be skipped, overriding \`skip-rebuld\` in config.toml]:VALUE:(true false)' \ +'--rust-profile-generate=[generate PGO profile with rustc build]:PROFILE:_files' \ +'--rust-profile-use=[use PGO profile for rustc build]:PROFILE:_files' \ +'--llvm-profile-use=[use PGO profile for LLVM build]:PROFILE:_files' \ +'*--reproducible-artifact=[Additional reproducible artifacts that should be added to the reproducible artifacts archive]:REPRODUCIBLE_ARTIFACT: ' \ +'*--set=[override options in config.toml]:section.option=value:( )' \ +'--run[run suggested tests]' \ +'*-v[use verbose output (-vv for very verbose)]' \ +'*--verbose[use verbose output (-vv for very verbose)]' \ +'-i[use incremental compilation]' \ +'--incremental[use incremental compilation]' \ +'--include-default-paths[include default paths in addition to the provided ones]' \ +'--dry-run[dry run; don'\''t build anything]' \ +'--json-output[use message-format=json]' \ +'--llvm-profile-generate[generate PGO profile with llvm built for rustc]' \ +'--enable-bolt-settings[Enable BOLT link flags]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::paths -- paths for the subcommand:_files' \ +&& ret=0 +;; + esac + ;; +esac +} + +(( $+functions[_x.py_commands] )) || +_x.py_commands() { + local commands; commands=( +'build:Compile either the compiler or libraries' \ +'check:Compile either the compiler or libraries, using cargo check' \ +'clippy:Run Clippy (uses rustup/cargo-installed clippy binary)' \ +'fix:Run cargo fix' \ +'fmt:Run rustfmt' \ +'doc:Build documentation' \ +'test:Build and run some test suites' \ +'bench:Build and run some benchmarks' \ +'clean:Clean out build directories' \ +'dist:Build distribution artifacts' \ +'install:Install distribution artifacts' \ +'run:Run tools contained in this repository' \ +'setup:Set up the environment for development' \ +'suggest:Suggest a subset of tests to run, based on modified files' \ + ) + _describe -t commands 'x.py commands' commands "$@" +} +(( $+functions[_x.py__bench_commands] )) || +_x.py__bench_commands() { + local commands; commands=() + _describe -t commands 'x.py bench commands' commands "$@" +} +(( $+functions[_x.py__build_commands] )) || +_x.py__build_commands() { + local commands; commands=() + _describe -t commands 'x.py build commands' commands "$@" +} +(( $+functions[_x.py__check_commands] )) || +_x.py__check_commands() { + local commands; commands=() + _describe -t commands 'x.py check commands' commands "$@" +} +(( $+functions[_x.py__clean_commands] )) || +_x.py__clean_commands() { + local commands; commands=() + _describe -t commands 'x.py clean commands' commands "$@" +} +(( $+functions[_x.py__clippy_commands] )) || +_x.py__clippy_commands() { + local commands; commands=() + _describe -t commands 'x.py clippy commands' commands "$@" +} +(( $+functions[_x.py__dist_commands] )) || +_x.py__dist_commands() { + local commands; commands=() + _describe -t commands 'x.py dist commands' commands "$@" +} +(( $+functions[_x.py__doc_commands] )) || +_x.py__doc_commands() { + local commands; commands=() + _describe -t commands 'x.py doc commands' commands "$@" +} +(( $+functions[_x.py__fix_commands] )) || +_x.py__fix_commands() { + local commands; commands=() + _describe -t commands 'x.py fix commands' commands "$@" +} +(( $+functions[_x.py__fmt_commands] )) || +_x.py__fmt_commands() { + local commands; commands=() + _describe -t commands 'x.py fmt commands' commands "$@" +} +(( $+functions[_x.py__install_commands] )) || +_x.py__install_commands() { + local commands; commands=() + _describe -t commands 'x.py install commands' commands "$@" +} +(( $+functions[_x.py__run_commands] )) || +_x.py__run_commands() { + local commands; commands=() + _describe -t commands 'x.py run commands' commands "$@" +} +(( $+functions[_x.py__setup_commands] )) || +_x.py__setup_commands() { + local commands; commands=() + _describe -t commands 'x.py setup commands' commands "$@" +} +(( $+functions[_x.py__suggest_commands] )) || +_x.py__suggest_commands() { + local commands; commands=() + _describe -t commands 'x.py suggest commands' commands "$@" +} +(( $+functions[_x.py__test_commands] )) || +_x.py__test_commands() { + local commands; commands=() + _describe -t commands 'x.py test commands' commands "$@" +} + +if [ "$funcstack[1]" = "_x.py" ]; then + _x.py "$@" +else + compdef _x.py x.py +fi diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 29912b95703..38935b7d1bb 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" arrayvec = { version = "0.7", default-features = false } askama = { version = "0.12", default-features = false, features = ["config"] } itertools = "0.10.1" -minifier = "0.2.2" +minifier = "0.2.3" once_cell = "1.10.0" regex = "1" rustdoc-json-types = { path = "../rustdoc-json-types" } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b9d7acee63c..e08318e4f54 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -521,7 +521,7 @@ fn clean_generic_param_def<'tcx>( }, ) } - ty::GenericParamDefKind::Const { has_default, .. } => ( + ty::GenericParamDefKind::Const { has_default, is_host_effect } => ( def.name, GenericParamDefKind::Const { ty: Box::new(clean_middle_ty( @@ -541,6 +541,7 @@ fn clean_generic_param_def<'tcx>( )), false => None, }, + is_host_effect, }, ), }; @@ -597,6 +598,7 @@ fn clean_generic_param<'tcx>( ty: Box::new(clean_ty(ty, cx)), default: default .map(|ct| Box::new(ty::Const::from_anon_const(cx.tcx, ct.def_id).to_string())), + is_host_effect: cx.tcx.has_attr(param.def_id, sym::rustc_host), }, ), }; @@ -2508,14 +2510,22 @@ fn clean_generic_args<'tcx>( let args = generic_args .args .iter() - .map(|arg| match arg { - hir::GenericArg::Lifetime(lt) if !lt.is_anonymous() => { - GenericArg::Lifetime(clean_lifetime(*lt, cx)) - } - hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()), - hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)), - hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))), - hir::GenericArg::Infer(_inf) => GenericArg::Infer, + .filter_map(|arg| { + Some(match arg { + hir::GenericArg::Lifetime(lt) if !lt.is_anonymous() => { + GenericArg::Lifetime(clean_lifetime(*lt, cx)) + } + hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()), + hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)), + // FIXME(effects): This will still emit `<true>` for non-const impls of const traits + hir::GenericArg::Const(ct) + if cx.tcx.has_attr(ct.value.def_id, sym::rustc_host) => + { + return None; + } + hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))), + hir::GenericArg::Infer(_inf) => GenericArg::Infer, + }) }) .collect::<Vec<_>>() .into(); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 48ce0a89449..2a54266676d 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -713,12 +713,16 @@ impl Item { Some(tcx.visibility(def_id)) } - pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, keep_as_is: bool) -> Vec<String> { + pub(crate) fn attributes( + &self, + tcx: TyCtxt<'_>, + cache: &Cache, + keep_as_is: bool, + ) -> Vec<String> { const ALLOWED_ATTRIBUTES: &[Symbol] = - &[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive]; + &[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive]; use rustc_abi::IntegerType; - use rustc_middle::ty::ReprFlags; let mut attrs: Vec<String> = self .attrs @@ -739,20 +743,38 @@ impl Item { } }) .collect(); - if let Some(def_id) = self.def_id() && - !def_id.is_local() && - // This check is needed because `adt_def` will panic if not a compatible type otherwise... - matches!(self.type_(), ItemType::Struct | ItemType::Enum | ItemType::Union) + if !keep_as_is + && let Some(def_id) = self.def_id() + && let ItemType::Struct | ItemType::Enum | ItemType::Union = self.type_() { - let repr = tcx.adt_def(def_id).repr(); + let adt = tcx.adt_def(def_id); + let repr = adt.repr(); let mut out = Vec::new(); - if repr.flags.contains(ReprFlags::IS_C) { + if repr.c() { out.push("C"); } - if repr.flags.contains(ReprFlags::IS_TRANSPARENT) { - out.push("transparent"); + if repr.transparent() { + // Render `repr(transparent)` iff the non-1-ZST field is public or at least one + // field is public in case all fields are 1-ZST fields. + let render_transparent = cache.document_private + || adt + .all_fields() + .find(|field| { + let ty = + field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did)); + tcx.layout_of(tcx.param_env(field.did).and(ty)) + .is_ok_and(|layout| !layout.is_1zst()) + }) + .map_or_else( + || adt.all_fields().any(|field| field.vis.is_public()), + |field| field.vis.is_public(), + ); + + if render_transparent { + out.push("transparent"); + } } - if repr.flags.contains(ReprFlags::IS_SIMD) { + if repr.simd() { out.push("simd"); } let pack_s; @@ -777,10 +799,9 @@ impl Item { }; out.push(&int_s); } - if out.is_empty() { - return Vec::new(); + if !out.is_empty() { + attrs.push(format!("#[repr({})]", out.join(", "))); } - attrs.push(format!("#[repr({})]", out.join(", "))); } attrs } @@ -1306,7 +1327,7 @@ impl WherePredicate { pub(crate) enum GenericParamDefKind { Lifetime { outlives: Vec<Lifetime> }, Type { did: DefId, bounds: Vec<GenericBound>, default: Option<Box<Type>>, synthetic: bool }, - Const { ty: Box<Type>, default: Option<Box<String>> }, + Const { ty: Box<Type>, default: Option<Box<String>>, is_host_effect: bool }, } impl GenericParamDefKind { @@ -1326,9 +1347,10 @@ impl GenericParamDef { Self { name, kind: GenericParamDefKind::Lifetime { outlives: Vec::new() } } } - pub(crate) fn is_synthetic_type_param(&self) -> bool { + pub(crate) fn is_synthetic_param(&self) -> bool { match self.kind { - GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false, + GenericParamDefKind::Lifetime { .. } => false, + GenericParamDefKind::Const { is_host_effect, .. } => is_host_effect, GenericParamDefKind::Type { synthetic, .. } => synthetic, } } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 01078504b71..c5302570489 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -104,6 +104,10 @@ pub(crate) fn ty_args_to_args<'tcx>( arg: index, }), ))), + // FIXME(effects): this relies on the host effect being called `host`, which users could also name + // their const generics. + // FIXME(effects): this causes `host = true` and `host = false` generics to also be emitted. + GenericArgKind::Const(ct) if let ty::ConstKind::Param(p) = ct.kind() && p.name == sym::host => None, GenericArgKind::Const(ct) => { Some(GenericArg::Const(Box::new(clean_middle_const(kind.rebind(ct), cx)))) } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 3e6066c78fb..9066061f1a2 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -262,6 +262,7 @@ pub(crate) fn create_config( locale_resources: rustc_driver::DEFAULT_LOCALE_RESOURCES, lint_caps, parse_sess_created: None, + hash_untracked_state: None, register_lints: Some(Box::new(crate::lint::register_lints)), override_queries: Some(|_sess, providers| { // We do not register late module lints, so this only runs `MissingDoc`. diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 741d329fb19..db69cf5752d 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -104,6 +104,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { locale_resources: rustc_driver::DEFAULT_LOCALE_RESOURCES, lint_caps, parse_sess_created: None, + hash_untracked_state: None, register_lints: Some(Box::new(crate::lint::register_lints)), override_queries: None, make_codegen_backend: None, diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 4c6e7dfb987..4ccb5f2be34 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -221,19 +221,25 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { _ => self.cache.stripped_mod, }; + #[inline] + fn is_from_private_dep(tcx: TyCtxt<'_>, cache: &Cache, def_id: DefId) -> bool { + let krate = def_id.krate; + + cache.masked_crates.contains(&krate) || tcx.is_private_dep(krate) + } + // If the impl is from a masked crate or references something from a // masked crate then remove it completely. - if let clean::ImplItem(ref i) = *item.kind { - if self.cache.masked_crates.contains(&item.item_id.krate()) + if let clean::ImplItem(ref i) = *item.kind && + (self.cache.masked_crates.contains(&item.item_id.krate()) || i.trait_ .as_ref() - .map_or(false, |t| self.cache.masked_crates.contains(&t.def_id().krate)) + .map_or(false, |t| is_from_private_dep(self.tcx, self.cache, t.def_id())) || i.for_ .def_id(self.cache) - .map_or(false, |d| self.cache.masked_crates.contains(&d.krate)) - { - return None; - } + .map_or(false, |d| is_from_private_dep(self.tcx, self.cache, d))) + { + return None; } // Propagate a trait method's documentation to all implementors of the @@ -334,33 +340,37 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { // A crate has a module at its root, containing all items, // which should not be indexed. The crate-item itself is // inserted later on when serializing the search-index. - if item.item_id.as_def_id().map_or(false, |idx| !idx.is_crate_root()) { + if item.item_id.as_def_id().map_or(false, |idx| !idx.is_crate_root()) + && let ty = item.type_() + && (ty != ItemType::StructField + || u16::from_str_radix(s.as_str(), 10).is_err()) + { let desc = short_markdown_summary(&item.doc_value(), &item.link_names(self.cache)); - let ty = item.type_(); - if ty != ItemType::StructField - || u16::from_str_radix(s.as_str(), 10).is_err() - { - // In case this is a field from a tuple struct, we don't add it into - // the search index because its name is something like "0", which is - // not useful for rustdoc search. - self.cache.search_index.push(IndexItem { - ty, - name: s, - path: join_with_double_colon(path), - desc, - parent, - parent_idx: None, - search_type: get_function_type_for_search( - &item, - self.tcx, - clean_impl_generics(self.cache.parent_stack.last()).as_ref(), - self.cache, - ), - aliases: item.attrs.get_doc_aliases(), - deprecation: item.deprecation(self.tcx), - }); - } + // In case this is a field from a tuple struct, we don't add it into + // the search index because its name is something like "0", which is + // not useful for rustdoc search. + self.cache.search_index.push(IndexItem { + ty, + name: s, + path: join_with_double_colon(path), + desc, + parent, + parent_idx: None, + impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = self.cache.parent_stack.last() { + item_id.as_def_id() + } else { + None + }, + search_type: get_function_type_for_search( + &item, + self.tcx, + clean_impl_generics(self.cache.parent_stack.last()).as_ref(), + self.cache, + ), + aliases: item.attrs.get_doc_aliases(), + deprecation: item.deprecation(self.tcx), + }); } } (Some(parent), None) if is_inherent_impl_item => { @@ -371,6 +381,13 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { parent, item: item.clone(), impl_generics, + impl_id: if let Some(ParentStackItem::Impl { item_id, .. }) = + self.cache.parent_stack.last() + { + item_id.as_def_id() + } else { + None + }, }); } _ => {} @@ -541,6 +558,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { pub(crate) struct OrphanImplItem { pub(crate) parent: DefId, + pub(crate) impl_id: Option<DefId>, pub(crate) item: clean::Item, pub(crate) impl_generics: Option<(clean::Type, clean::Generics)>, } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 1983bb11e5b..aa3f7184b4e 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -250,8 +250,7 @@ impl clean::Generics { cx: &'a Context<'tcx>, ) -> impl fmt::Display + 'a + Captures<'tcx> { display_fn(move |f| { - let mut real_params = - self.params.iter().filter(|p| !p.is_synthetic_type_param()).peekable(); + let mut real_params = self.params.iter().filter(|p| !p.is_synthetic_param()).peekable(); if real_params.peek().is_none() { return Ok(()); } diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 8c5871d9126..d4b4db0f3fd 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -17,6 +17,7 @@ pub(crate) struct Layout { pub(crate) external_html: ExternalHtml, pub(crate) default_settings: FxHashMap<String, String>, pub(crate) krate: String, + pub(crate) krate_version: String, /// The given user css file which allow to customize the generated /// documentation theme. pub(crate) css_file_extension: Option<PathBuf>, @@ -31,6 +32,7 @@ pub(crate) struct Page<'a> { pub(crate) static_root_path: Option<&'a str>, pub(crate) description: &'a str, pub(crate) resource_suffix: &'a str, + pub(crate) rust_logo: bool, } impl<'a> Page<'a> { @@ -54,9 +56,19 @@ struct PageLayout<'a> { themes: Vec<String>, sidebar: String, content: String, - krate_with_trailing_slash: String, rust_channel: &'static str, pub(crate) rustdoc_version: &'a str, + // same as layout.krate, except on top-level pages like + // Settings, Help, All Crates, and About Scraped Examples, + // where these things instead give Rustdoc name and version. + // + // These are separate from the variables used for the search + // engine, because "Rustdoc" isn't necessarily a crate in + // the current workspace. + display_krate: &'a str, + display_krate_with_trailing_slash: String, + display_krate_version_number: &'a str, + display_krate_version_extra: &'a str, } pub(crate) fn render<T: Print, S: Print>( @@ -66,12 +78,26 @@ pub(crate) fn render<T: Print, S: Print>( t: T, style_files: &[StylePath], ) -> String { + let rustdoc_version = rustc_interface::util::version_str!().unwrap_or("unknown version"); + + let (display_krate, display_krate_version, display_krate_with_trailing_slash) = + if page.root_path == "./" { + // top level pages use Rust branding + ("Rustdoc", rustdoc_version, String::new()) + } else { + let display_krate_with_trailing_slash = + ensure_trailing_slash(&layout.krate).to_string(); + (&layout.krate[..], &layout.krate_version[..], display_krate_with_trailing_slash) + }; let static_root_path = page.get_static_root_path(); - let krate_with_trailing_slash = ensure_trailing_slash(&layout.krate).to_string(); + + // bootstrap passes in parts of the version separated by tabs, but other stuff might use spaces + let (display_krate_version_number, display_krate_version_extra) = + display_krate_version.split_once([' ', '\t']).unwrap_or((display_krate_version, "")); + let mut themes: Vec<String> = style_files.iter().map(|s| s.basename().unwrap()).collect(); themes.sort(); - let rustdoc_version = rustc_interface::util::version_str!().unwrap_or("unknown version"); let content = Buffer::html().to_display(t); // Note: This must happen before making the sidebar. let sidebar = Buffer::html().to_display(sidebar); PageLayout { @@ -82,7 +108,10 @@ pub(crate) fn render<T: Print, S: Print>( themes, sidebar, content, - krate_with_trailing_slash, + display_krate, + display_krate_with_trailing_slash, + display_krate_version_number, + display_krate_version_extra, rust_channel: *crate::clean::utils::DOC_CHANNEL, rustdoc_version, } diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 97714afaa45..bf8d1a80337 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -24,6 +24,7 @@ use super::{ sidebar::{sidebar_module_like, Sidebar}, AllTypes, LinkFromSrc, StylePath, }; +use crate::clean::utils::has_doc_flag; use crate::clean::{self, types::ExternalLocation, ExternalCrate, TypeAliasItem}; use crate::config::{ModuleSorting, RenderOptions}; use crate::docfs::{DocFS, PathError}; @@ -277,6 +278,7 @@ impl<'tcx> Context<'tcx> { title: &title, description: &desc, resource_suffix: &clone_shared.resource_suffix, + rust_logo: has_doc_flag(self.tcx(), LOCAL_CRATE.as_def_id(), sym::rust_logo), }; let mut page_buffer = Buffer::html(); print_item(self, it, &mut page_buffer, &page); @@ -528,12 +530,14 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { if let Some(url) = playground_url { playground = Some(markdown::Playground { crate_name: Some(krate.name(tcx)), url }); } + let krate_version = cache.crate_version.as_deref().unwrap_or_default(); let mut layout = layout::Layout { logo: String::new(), favicon: String::new(), external_html, default_settings, krate: krate.name(tcx).to_string(), + krate_version: krate_version.to_string(), css_file_extension: extension_css, scrape_examples_extension: !call_locations.is_empty(), }; @@ -658,21 +662,22 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { let shared = Rc::clone(&self.shared); let mut page = layout::Page { title: "List of all items in this crate", - css_class: "mod", + css_class: "mod sys", root_path: "../", static_root_path: shared.static_root_path.as_deref(), description: "List of all items in this crate", resource_suffix: &shared.resource_suffix, + rust_logo: has_doc_flag(self.tcx(), LOCAL_CRATE.as_def_id(), sym::rust_logo), }; let all = shared.all.replace(AllTypes::new()); let mut sidebar = Buffer::html(); let blocks = sidebar_module_like(all.item_sections()); let bar = Sidebar { - title_prefix: "Crate ", - title: crate_name.as_str(), + title_prefix: "", + title: "", is_crate: false, - version: "", + is_mod: false, blocks: vec![blocks], path: String::new(), }; @@ -689,9 +694,10 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { shared.fs.write(final_file, v)?; // Generating settings page. - page.title = "Rustdoc settings"; + page.title = "Settings"; page.description = "Settings of Rustdoc"; page.root_path = "./"; + page.rust_logo = true; let sidebar = "<h2 class=\"location\">Settings</h2><div class=\"sidebar-elems\"></div>"; let v = layout::render( @@ -739,9 +745,10 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { shared.fs.write(settings_file, v)?; // Generating help page. - page.title = "Rustdoc help"; + page.title = "Help"; page.description = "Documentation for Rustdoc"; page.root_path = "./"; + page.rust_logo = true; let sidebar = "<h2 class=\"location\">Help</h2><div class=\"sidebar-elems\"></div>"; let v = layout::render( diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 3e671a64b54..89e29d8b59b 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -54,7 +54,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::Mutability; use rustc_middle::middle::stability; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{ symbol::{sym, Symbol}, BytePos, FileName, RealFileName, @@ -102,6 +102,7 @@ pub(crate) struct IndexItem { pub(crate) desc: String, pub(crate) parent: Option<DefId>, pub(crate) parent_idx: Option<isize>, + pub(crate) impl_id: Option<DefId>, pub(crate) search_type: Option<IndexItemFunctionType>, pub(crate) aliases: Box<[Symbol]>, pub(crate) deprecation: Option<Deprecation>, @@ -867,10 +868,10 @@ fn assoc_method( let (indent, indent_str, end_newline) = if parent == ItemType::Trait { header_len += 4; let indent_str = " "; - write!(w, "{}", render_attributes_in_pre(meth, indent_str, tcx)); + write!(w, "{}", render_attributes_in_pre(meth, indent_str, cx)); (4, indent_str, Ending::NoNewline) } else { - render_attributes_in_code(w, meth, tcx); + render_attributes_in_code(w, meth, cx); (0, "", Ending::Newline) }; w.reserve(header_len + "<a href=\"\" class=\"fn\">{".len() + "</a>".len()); @@ -1046,13 +1047,13 @@ fn render_assoc_item( // When an attribute is rendered inside a `<pre>` tag, it is formatted using // a whitespace prefix and newline. -fn render_attributes_in_pre<'a, 'b: 'a>( +fn render_attributes_in_pre<'a, 'tcx: 'a>( it: &'a clean::Item, prefix: &'a str, - tcx: TyCtxt<'b>, -) -> impl fmt::Display + Captures<'a> + Captures<'b> { + cx: &'a Context<'tcx>, +) -> impl fmt::Display + Captures<'a> + Captures<'tcx> { crate::html::format::display_fn(move |f| { - for a in it.attributes(tcx, false) { + for a in it.attributes(cx.tcx(), cx.cache(), false) { writeln!(f, "{prefix}{a}")?; } Ok(()) @@ -1061,8 +1062,8 @@ fn render_attributes_in_pre<'a, 'b: 'a>( // When an attribute is rendered inside a <code> tag, it is formatted using // a div to produce a newline after it. -fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, tcx: TyCtxt<'_>) { - for attr in it.attributes(tcx, false) { +fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) { + for attr in it.attributes(cx.tcx(), cx.cache(), false) { write!(w, "<div class=\"code-attribute\">{attr}</div>").unwrap(); } } @@ -1877,7 +1878,7 @@ pub(crate) fn render_impl_summary( aliases: &[String], ) { let inner_impl = i.inner_impl(); - let id = cx.derive_id(get_id_for_impl(&inner_impl.for_, inner_impl.trait_.as_ref(), cx)); + let id = cx.derive_id(get_id_for_impl(cx.tcx(), i.impl_item.item_id)); let aliases = if aliases.is_empty() { String::new() } else { @@ -1994,21 +1995,35 @@ pub(crate) fn small_url_encode(s: String) -> String { } } -fn get_id_for_impl(for_: &clean::Type, trait_: Option<&clean::Path>, cx: &Context<'_>) -> String { - match trait_ { - Some(t) => small_url_encode(format!("impl-{:#}-for-{:#}", t.print(cx), for_.print(cx))), - None => small_url_encode(format!("impl-{:#}", for_.print(cx))), - } +fn get_id_for_impl<'tcx>(tcx: TyCtxt<'tcx>, impl_id: ItemId) -> String { + use rustc_middle::ty::print::with_forced_trimmed_paths; + let (type_, trait_) = match impl_id { + ItemId::Auto { trait_, for_ } => { + let ty = tcx.type_of(for_).skip_binder(); + (ty, Some(ty::TraitRef::new(tcx, trait_, [ty]))) + } + ItemId::Blanket { impl_id, .. } | ItemId::DefId(impl_id) => { + match tcx.impl_subject(impl_id).skip_binder() { + ty::ImplSubject::Trait(trait_ref) => { + (trait_ref.args[0].expect_ty(), Some(trait_ref)) + } + ty::ImplSubject::Inherent(ty) => (ty, None), + } + } + }; + with_forced_trimmed_paths!(small_url_encode(if let Some(trait_) = trait_ { + format!("impl-{trait_}-for-{type_}", trait_ = trait_.print_only_trait_path()) + } else { + format!("impl-{type_}") + })) } fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> { match *item.kind { - clean::ItemKind::ImplItem(ref i) => { - i.trait_.as_ref().map(|trait_| { - // Alternative format produces no URLs, - // so this parameter does nothing. - (format!("{:#}", i.for_.print(cx)), get_id_for_impl(&i.for_, Some(trait_), cx)) - }) + clean::ItemKind::ImplItem(ref i) if i.trait_.is_some() => { + // Alternative format produces no URLs, + // so this parameter does nothing. + Some((format!("{:#}", i.for_.print(cx)), get_id_for_impl(cx.tcx(), item.item_id))) } _ => None, } @@ -2079,6 +2094,7 @@ impl ItemSection { const ALL: &'static [Self] = { use ItemSection::*; // NOTE: The order here affects the order in the UI. + // Keep this synchronized with addSidebarItems in main.js &[ Reexports, PrimitiveTypes, diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 467493cb0b3..f6432dc61ae 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -7,6 +7,7 @@ use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; use rustc_index::IndexVec; use rustc_middle::middle::stability; +use rustc_middle::query::Key; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; @@ -119,8 +120,7 @@ macro_rules! item_template_methods { fn render_attributes_in_pre<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { display_fn(move |f| { let (item, cx) = self.item_and_mut_cx(); - let tcx = cx.tcx(); - let v = render_attributes_in_pre(item, "", tcx); + let v = render_attributes_in_pre(item, "", &cx); write!(f, "{v}") }) } @@ -658,7 +658,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle w, "{attrs}{vis}{constness}{asyncness}{unsafety}{abi}fn \ {name}{generics}{decl}{notable_traits}{where_clause}", - attrs = render_attributes_in_pre(it, "", tcx), + attrs = render_attributes_in_pre(it, "", cx), vis = visibility, constness = constness, asyncness = asyncness, @@ -693,7 +693,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: write!( w, "{attrs}{vis}{unsafety}{is_auto}trait {name}{generics}{bounds}", - attrs = render_attributes_in_pre(it, "", tcx), + attrs = render_attributes_in_pre(it, "", cx), vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx), unsafety = t.unsafety(tcx).print_with_space(), is_auto = if t.is_auto(tcx) { "auto " } else { "" }, @@ -1172,7 +1172,7 @@ fn item_trait_alias( write!( w, "{attrs}trait {name}{generics}{where_b} = {bounds};", - attrs = render_attributes_in_pre(it, "", cx.tcx()), + attrs = render_attributes_in_pre(it, "", cx), name = it.name.unwrap(), generics = t.generics.print(cx), where_b = print_where_clause(&t.generics, cx, 0, Ending::Newline), @@ -1200,7 +1200,7 @@ fn item_opaque_ty( write!( w, "{attrs}type {name}{generics}{where_clause} = impl {bounds};", - attrs = render_attributes_in_pre(it, "", cx.tcx()), + attrs = render_attributes_in_pre(it, "", cx), name = it.name.unwrap(), generics = t.generics.print(cx), where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline), @@ -1225,7 +1225,7 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c write!( w, "{attrs}{vis}type {name}{generics}{where_clause} = {type_};", - attrs = render_attributes_in_pre(it, "", cx.tcx()), + attrs = render_attributes_in_pre(it, "", cx), vis = visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx), name = it.name.unwrap(), generics = t.generics.print(cx), @@ -1249,6 +1249,9 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c match inner_type { clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive } => { let variants_iter = || variants.iter().filter(|i| !i.is_stripped()); + let ty = cx.tcx().type_of(it.def_id().unwrap()).instantiate_identity(); + let enum_def_id = ty.ty_adt_id().unwrap(); + wrap_item(w, |w| { let variants_len = variants.len(); let variants_count = variants_iter().count(); @@ -1263,10 +1266,10 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c variants_count, has_stripped_entries, *is_non_exhaustive, - it.def_id().unwrap(), + enum_def_id, ) }); - item_variants(w, cx, it, &variants); + item_variants(w, cx, it, &variants, enum_def_id); } clean::TypeAliasInnerType::Union { fields } => { wrap_item(w, |w| { @@ -1411,7 +1414,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: let tcx = cx.tcx(); let count_variants = e.variants().count(); wrap_item(w, |w| { - render_attributes_in_code(w, it, tcx); + render_attributes_in_code(w, it, cx); write!( w, "{}enum {}{}", @@ -1435,16 +1438,21 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); if count_variants != 0 { - item_variants(w, cx, it, &e.variants); + item_variants(w, cx, it, &e.variants, it.def_id().unwrap()); } let def_id = it.item_id.expect_def_id(); write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); write!(w, "{}", document_type_layout(cx, def_id)); } -/// It'll return true if all variants are C-like variants and if at least one of them has a value -/// set. -fn should_show_enum_discriminant(variants: &IndexVec<VariantIdx, clean::Item>) -> bool { +/// It'll return false if any variant is not a C-like variant. Otherwise it'll return true if at +/// least one of them has an explicit discriminant or if the enum has `#[repr(C)]` or an integer +/// `repr`. +fn should_show_enum_discriminant( + cx: &Context<'_>, + enum_def_id: DefId, + variants: &IndexVec<VariantIdx, clean::Item>, +) -> bool { let mut has_variants_with_value = false; for variant in variants { if let clean::VariantItem(ref var) = *variant.kind && @@ -1455,7 +1463,11 @@ fn should_show_enum_discriminant(variants: &IndexVec<VariantIdx, clean::Item>) - return false; } } - has_variants_with_value + if has_variants_with_value { + return true; + } + let repr = cx.tcx().adt_def(enum_def_id).repr(); + repr.c() || repr.int.is_some() } fn display_c_like_variant( @@ -1493,7 +1505,7 @@ fn render_enum_fields( is_non_exhaustive: bool, enum_def_id: DefId, ) { - let should_show_enum_discriminant = should_show_enum_discriminant(variants); + let should_show_enum_discriminant = should_show_enum_discriminant(cx, enum_def_id, variants); if !g.is_some_and(|g| print_where_clause_and_check(w, g, cx)) { // If there wasn't a `where` clause, we add a whitespace. w.write_str(" "); @@ -1552,6 +1564,7 @@ fn item_variants( cx: &mut Context<'_>, it: &clean::Item, variants: &IndexVec<VariantIdx, clean::Item>, + enum_def_id: DefId, ) { let tcx = cx.tcx(); write!( @@ -1564,7 +1577,7 @@ fn item_variants( document_non_exhaustive_header(it), document_non_exhaustive(it) ); - let should_show_enum_discriminant = should_show_enum_discriminant(variants); + let should_show_enum_discriminant = should_show_enum_discriminant(cx, enum_def_id, variants); for (index, variant) in variants.iter_enumerated() { if variant.is_stripped() { continue; @@ -1594,7 +1607,7 @@ fn item_variants( var, index, should_show_enum_discriminant, - it.def_id().unwrap(), + enum_def_id, ); } else { w.write_str(variant.name.unwrap().as_str()); @@ -1720,7 +1733,7 @@ fn item_primitive(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Ite fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) { wrap_item(w, |w| { let tcx = cx.tcx(); - render_attributes_in_code(w, it, tcx); + render_attributes_in_code(w, it, cx); write!( w, @@ -1769,7 +1782,7 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) { wrap_item(w, |w| { - render_attributes_in_code(w, it, cx.tcx()); + render_attributes_in_code(w, it, cx); render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx); }); @@ -1829,7 +1842,7 @@ fn item_fields( fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { wrap_item(w, |buffer| { - render_attributes_in_code(buffer, it, cx.tcx()); + render_attributes_in_code(buffer, it, cx); write!( buffer, "{vis}static {mutability}{name}: {typ}", @@ -1847,7 +1860,7 @@ fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, fn item_foreign_type(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item) { wrap_item(w, |buffer| { buffer.write_str("extern {\n").unwrap(); - render_attributes_in_code(buffer, it, cx.tcx()); + render_attributes_in_code(buffer, it, cx); write!( buffer, " {}type {};\n}}", diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 78c443b2257..af1dab59496 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -12,7 +12,7 @@ use crate::formats::cache::{Cache, OrphanImplItem}; use crate::formats::item_type::ItemType; use crate::html::format::join_with_double_colon; use crate::html::markdown::short_markdown_summary; -use crate::html::render::{IndexItem, IndexItemFunctionType, RenderType, RenderTypeId}; +use crate::html::render::{self, IndexItem, IndexItemFunctionType, RenderType, RenderTypeId}; /// Builds the search index from the collected metadata pub(crate) fn build_index<'tcx>( @@ -26,7 +26,8 @@ pub(crate) fn build_index<'tcx>( // Attach all orphan items to the type's definition if the type // has since been learned. - for &OrphanImplItem { parent, ref item, ref impl_generics } in &cache.orphan_impl_items { + for &OrphanImplItem { impl_id, parent, ref item, ref impl_generics } in &cache.orphan_impl_items + { if let Some((fqp, _)) = cache.paths.get(&parent) { let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache)); cache.search_index.push(IndexItem { @@ -36,6 +37,7 @@ pub(crate) fn build_index<'tcx>( desc, parent: Some(parent), parent_idx: None, + impl_id, search_type: get_function_type_for_search(item, tcx, impl_generics.as_ref(), cache), aliases: item.attrs.get_doc_aliases(), deprecation: item.deprecation(tcx), @@ -222,6 +224,29 @@ pub(crate) fn build_index<'tcx>( }) .collect(); + // Find associated items that need disambiguators + let mut associated_item_duplicates = FxHashMap::<(isize, ItemType, Symbol), usize>::default(); + + for &item in &crate_items { + if item.impl_id.is_some() && let Some(parent_idx) = item.parent_idx { + let count = associated_item_duplicates + .entry((parent_idx, item.ty, item.name)) + .or_insert(0); + *count += 1; + } + } + + let associated_item_disambiguators = crate_items + .iter() + .enumerate() + .filter_map(|(index, item)| { + let impl_id = ItemId::DefId(item.impl_id?); + let parent_idx = item.parent_idx?; + let count = *associated_item_duplicates.get(&(parent_idx, item.ty, item.name))?; + if count > 1 { Some((index, render::get_id_for_impl(tcx, impl_id))) } else { None } + }) + .collect::<Vec<_>>(); + struct CrateData<'a> { doc: String, items: Vec<&'a IndexItem>, @@ -230,6 +255,8 @@ pub(crate) fn build_index<'tcx>( // // To be noted: the `usize` elements are indexes to `items`. aliases: &'a BTreeMap<String, Vec<usize>>, + // Used when a type has more than one impl with an associated item with the same name. + associated_item_disambiguators: &'a Vec<(usize, String)>, } struct Paths { @@ -382,6 +409,7 @@ pub(crate) fn build_index<'tcx>( crate_data.serialize_field("f", &functions)?; crate_data.serialize_field("c", &deprecated)?; crate_data.serialize_field("p", &paths)?; + crate_data.serialize_field("b", &self.associated_item_disambiguators)?; if has_aliases { crate_data.serialize_field("a", &self.aliases)?; } @@ -398,6 +426,7 @@ pub(crate) fn build_index<'tcx>( items: crate_items, paths: crate_paths, aliases: &aliases, + associated_item_disambiguators: &associated_item_disambiguators, }) .expect("failed serde conversion") // All these `replace` calls are because we have to go through JS string for JSON content. diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index 76f63c6f63e..fb429f237e3 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -19,7 +19,7 @@ pub(super) struct Sidebar<'a> { pub(super) title_prefix: &'static str, pub(super) title: &'a str, pub(super) is_crate: bool, - pub(super) version: &'a str, + pub(super) is_mod: bool, pub(super) blocks: Vec<LinkBlock<'a>>, pub(super) path: String, } @@ -99,12 +99,12 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buf || it.is_primitive() || it.is_union() || it.is_enum() - || it.is_mod() + // crate title is displayed as part of logo lockup + || (it.is_mod() && !it.is_crate()) || it.is_type_alias() { ( match *it.kind { - clean::ModuleItem(..) if it.is_crate() => "Crate ", clean::ModuleItem(..) => "Module ", _ => "", }, @@ -113,14 +113,22 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buf } else { ("", "") }; - let version = - if it.is_crate() { cx.cache().crate_version.as_deref().unwrap_or_default() } else { "" }; - let path: String = if !it.is_mod() { - cx.current.iter().map(|s| s.as_str()).intersperse("::").collect() + // need to show parent path header if: + // - it's a child module, instead of the crate root + // - there's a sidebar section for the item itself + // + // otherwise, the parent path header is redundant with the big crate + // branding area at the top of the sidebar + let sidebar_path = + if it.is_mod() { &cx.current[..cx.current.len() - 1] } else { &cx.current[..] }; + let path: String = if sidebar_path.len() > 1 || !title.is_empty() { + let path = sidebar_path.iter().map(|s| s.as_str()).intersperse("::").collect(); + if sidebar_path.len() == 1 { format!("crate {path}") } else { path } } else { "".into() }; - let sidebar = Sidebar { title_prefix, title, is_crate: it.is_crate(), version, blocks, path }; + let sidebar = + Sidebar { title_prefix, title, is_mod: it.is_mod(), is_crate: it.is_crate(), blocks, path }; sidebar.render_into(buffer).unwrap(); } @@ -503,8 +511,7 @@ fn sidebar_render_assoc_items( .iter() .filter_map(|it| { let trait_ = it.inner_impl().trait_.as_ref()?; - let encoded = - id_map.derive(super::get_id_for_impl(&it.inner_impl().for_, Some(trait_), cx)); + let encoded = id_map.derive(super::get_id_for_impl(cx.tcx(), it.impl_item.item_id)); let prefix = match it.inner_impl().polarity { ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "", diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index e824651e727..e68d5ab2fbd 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -336,11 +336,12 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex}; let dst = cx.dst.join("index.html"); let page = layout::Page { title: "Index of crates", - css_class: "mod", + css_class: "mod sys", root_path: "./", static_root_path: shared.static_root_path.as_deref(), description: "List of crates", resource_suffix: &shared.resource_suffix, + rust_logo: true, }; let content = format!( diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 1d6eafe51b9..4a218b9b37c 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -1,4 +1,5 @@ use crate::clean; +use crate::clean::utils::has_doc_flag; use crate::docfs::PathError; use crate::error::Error; use crate::html::format; @@ -13,6 +14,7 @@ use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::source_map::FileName; +use rustc_span::sym; use std::cell::RefCell; use std::ffi::OsStr; @@ -231,6 +233,7 @@ impl SourceCollector<'_, '_> { static_root_path: shared.static_root_path.as_deref(), description: &desc, resource_suffix: &shared.resource_suffix, + rust_logo: has_doc_flag(self.cx.tcx(), LOCAL_CRATE.as_def_id(), sym::rust_logo), }; let v = layout::render( &shared.layout, diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 47f9e650281..e2b4cc50dd5 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -461,19 +461,9 @@ img { display: none !important; } -.sidebar .logo-container { - margin-top: 10px; - margin-bottom: 10px; - text-align: center; -} - -.version { - overflow-wrap: break-word; -} - .logo-container > img { - height: 100px; - width: 100px; + height: 48px; + width: 48px; } ul.block, .block li { @@ -502,6 +492,7 @@ ul.block, .block li { } .sidebar-elems, +.sidebar > .version, .sidebar > h2 { padding-left: 24px; } @@ -510,6 +501,8 @@ ul.block, .block li { color: var(--sidebar-link-color); } .sidebar .current, +.sidebar .current a, +.sidebar-crate a.logo-container:hover + h2 a, .sidebar a:hover:not(.logo-container) { background-color: var(--sidebar-current-link-background-color); } @@ -524,6 +517,75 @@ ul.block, .block li { overflow: hidden; } +.sidebar-crate { + display: flex; + align-items: center; + justify-content: center; + /* there's a 10px padding at the top of <main>, and a 4px margin at the + top of the search form. To line them up, add them. */ + margin: 14px 32px 1rem; + row-gap: 10px; + column-gap: 32px; + flex-wrap: wrap; +} + +.sidebar-crate h2 { + flex-grow: 1; + /* This setup with the margins and row-gap is designed to make flex-wrap + work the way we want. If they're in the side-by-side lockup, there + should be a 16px margin to the left of the logo (visually the same as + the 24px one on everything else, which are not giant circles) and 8px + between it and the crate's name and version. When they're line wrapped, + the logo needs to have the same margin on both sides of itself (to + center properly) and the crate name and version need 24px on their + left margin. */ + margin: 0 -8px; + /* To align this with the search bar, it should not be centered, even when + the logo is. */ + align-self: start; +} + +.sidebar-crate .logo-container { + /* The logo is expected to have 8px "slop" along its edges, so we can optically + center it. */ + margin: 0 -16px 0 -16px; + text-align: center; +} + +.sidebar-crate h2 a { + display: block; + margin: 0 calc(-24px + 0.25rem) 0 -0.5rem; + /* Align the sidebar crate link with the search bar, which have different + font sizes. + + | | font-size | line-height | total line-height | padding-y | total | + |:-------|----------:|------------:|------------------:|----------:|-------------:| + | crate | 1.375rem | 1.25 | 1.72rem | x | 2x+1.72rem | + | search | 1rem | 1.15 | 1.15rem | 8px | 1.15rem+16px | + + 2x + 1.72rem = 1.15rem + 16px + 2x = 1.15rem + 16px - 1.72rem + 2x = 16px - 0.57rem + x = ( 16px - 0.57rem ) / 2 + */ + padding: calc( ( 16px - 0.57rem ) / 2 ) 0.25rem; + padding-left: 0.5rem; +} + +.sidebar-crate h2 .version { + display: block; + font-weight: normal; + font-size: 1rem; + overflow-wrap: break-word; + /* opposite of the link padding, cut in half again */ + margin-top: calc( ( -16px + 0.57rem ) / 2 ); +} + +.sidebar-crate + .version { + margin-top: -1rem; + margin-bottom: 1rem; +} + .mobile-topbar { display: none; } diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index eb256455b08..2e9897ef82b 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -51,9 +51,14 @@ function setMobileTopbar() { // but with the current code it's hard to get the right information in the right place. const mobileTopbar = document.querySelector(".mobile-topbar"); const locationTitle = document.querySelector(".sidebar h2.location"); - if (mobileTopbar && locationTitle) { + if (mobileTopbar) { const mobileTitle = document.createElement("h2"); - mobileTitle.innerHTML = locationTitle.innerHTML; + mobileTitle.className = "location"; + if (hasClass(document.body, "crate")) { + mobileTitle.innerText = `Crate ${window.currentCrate}`; + } else if (locationTitle) { + mobileTitle.innerHTML = locationTitle.innerHTML; + } mobileTopbar.appendChild(mobileTitle); } } @@ -354,6 +359,34 @@ function preLoadCss(cssUrl) { expandSection(pageId); } } + if (savedHash.startsWith("impl-")) { + // impl-disambiguated links, used by the search engine + // format: impl-X[-for-Y]/method.WHATEVER + // turn this into method.WHATEVER[-NUMBER] + const splitAt = savedHash.indexOf("/"); + if (splitAt !== -1) { + const implId = savedHash.slice(0, splitAt); + const assocId = savedHash.slice(splitAt + 1); + const implElem = document.getElementById(implId); + if (implElem && implElem.parentElement.tagName === "SUMMARY" && + implElem.parentElement.parentElement.tagName === "DETAILS") { + onEachLazy(implElem.parentElement.parentElement.querySelectorAll( + `[id^="${assocId}"]`), + item => { + const numbered = /([^-]+)-([0-9]+)/.exec(item.id); + if (item.id === assocId || (numbered && numbered[1] === assocId)) { + openParentDetails(item); + item.scrollIntoView(); + // Let the section expand itself before trying to highlight + setTimeout(() => { + window.location.replace("#" + item.id); + }, 0); + } + } + ); + } + } + } } function onHashChange(ev) { @@ -452,22 +485,27 @@ function preLoadCss(cssUrl) { return; } + const modpath = hasClass(document.body, "mod") ? "../" : ""; + const h3 = document.createElement("h3"); - h3.innerHTML = `<a href="index.html#${id}">${longty}</a>`; + h3.innerHTML = `<a href="${modpath}index.html#${id}">${longty}</a>`; const ul = document.createElement("ul"); ul.className = "block " + shortty; for (const name of filtered) { let path; if (shortty === "mod") { - path = name + "/index.html"; + path = `${modpath}${name}/index.html`; } else { - path = shortty + "." + name + ".html"; + path = `${modpath}${shortty}.${name}.html`; + } + let current_page = document.location.href.toString(); + if (current_page.endsWith("/")) { + current_page += "index.html"; } - const current_page = document.location.href.split("/").pop(); const link = document.createElement("a"); link.href = path; - if (path === current_page) { + if (link.href === current_page) { link.className = "current"; } link.textContent = name; @@ -480,19 +518,33 @@ function preLoadCss(cssUrl) { } if (sidebar) { + // keep this synchronized with ItemSection::ALL in html/render/mod.rs + // Re-exports aren't shown here, because they don't have child pages + //block("reexport", "reexports", "Re-exports"); block("primitive", "primitives", "Primitive Types"); block("mod", "modules", "Modules"); block("macro", "macros", "Macros"); block("struct", "structs", "Structs"); block("enum", "enums", "Enums"); - block("union", "unions", "Unions"); block("constant", "constants", "Constants"); block("static", "static", "Statics"); block("trait", "traits", "Traits"); block("fn", "functions", "Functions"); block("type", "types", "Type Aliases"); + block("union", "unions", "Unions"); + // No point, because these items don't appear in modules + //block("impl", "impls", "Implementations"); + //block("tymethod", "tymethods", "Type Methods"); + //block("method", "methods", "Methods"); + //block("structfield", "fields", "Fields"); + //block("variant", "variants", "Variants"); + //block("associatedtype", "associated-types", "Associated Types"); + //block("associatedconstant", "associated-consts", "Associated Constants"); block("foreigntype", "foreign-types", "Foreign Types"); block("keyword", "keywords", "Keywords"); + block("opaque", "opaque-types", "Opaque Types"); + block("attr", "attributes", "Attribute Macros"); + block("derive", "derives", "Derive Macros"); block("traitalias", "trait-aliases", "Trait Aliases"); } } diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 7a282a99e9c..48c9a53a283 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1752,6 +1752,7 @@ function initSearch(rawSearchIndex) { type: item.type, is_alias: true, deprecated: item.deprecated, + implDisambiguator: item.implDisambiguator, }; } @@ -2218,7 +2219,7 @@ function initSearch(rawSearchIndex) { href = ROOT_PATH + name + "/index.html"; } else if (item.parent !== undefined) { const myparent = item.parent; - let anchor = "#" + type + "." + name; + let anchor = type + "." + name; const parentType = itemTypes[myparent.ty]; let pageType = parentType; let pageName = myparent.name; @@ -2232,16 +2233,19 @@ function initSearch(rawSearchIndex) { const enumName = item.path.substr(enumNameIdx + 2); path = item.path.substr(0, enumNameIdx); displayPath = path + "::" + enumName + "::" + myparent.name + "::"; - anchor = "#variant." + myparent.name + ".field." + name; + anchor = "variant." + myparent.name + ".field." + name; pageType = "enum"; pageName = enumName; } else { displayPath = path + "::" + myparent.name + "::"; } + if (item.implDisambiguator !== null) { + anchor = item.implDisambiguator + "/" + anchor; + } href = ROOT_PATH + path.replace(/::/g, "/") + "/" + pageType + "." + pageName + - ".html" + anchor; + ".html#" + anchor; } else { displayPath = item.path + "::"; href = ROOT_PATH + item.path.replace(/::/g, "/") + @@ -2727,6 +2731,10 @@ ${item.displayPath}<span class="${type}">${name}</span>\ * Types are also represented as arrays; the first item is an index into the `p` * array, while the second is a list of types representing any generic parameters. * + * b[i] contains an item's impl disambiguator. This is only present if an item + * is defined in an impl block and, the impl block's type has more than one associated + * item with the same name. + * * `a` defines aliases with an Array of pairs: [name, offset], where `offset` * points into the n/t/d/q/i/f arrays. * @@ -2746,6 +2754,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\ * i: Array<Number>, * f: Array<RawFunctionSearchType>, * p: Array<Object>, + * b: Array<[Number, String]>, * c: Array<Number> * }} */ @@ -2766,6 +2775,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\ id: id, normalizedName: crate.indexOf("_") === -1 ? crate : crate.replace(/_/g, ""), deprecated: null, + implDisambiguator: null, }; id += 1; searchIndex.push(crateRow); @@ -2789,6 +2799,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\ const itemFunctionSearchTypes = crateCorpus.f; // an array of (Number) indices for the deprecated items const deprecatedItems = new Set(crateCorpus.c); + // an array of (Number) indices for the deprecated items + const implDisambiguator = new Map(crateCorpus.b); // an array of [(Number) item type, // (String) name] const paths = crateCorpus.p; @@ -2849,6 +2861,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\ id: id, normalizedName: word.indexOf("_") === -1 ? word : word.replace(/_/g, ""), deprecated: deprecatedItems.has(i), + implDisambiguator: implDisambiguator.has(i) ? implDisambiguator.get(i) : null, }; id += 1; searchIndex.push(row); diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 579c782be09..ebf817673bf 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -42,6 +42,8 @@ <script defer src="{{page.root_path|safe}}src-files{{page.resource_suffix}}.js"></script> {# #} {% else if !page.css_class.contains("mod") %} <script defer src="sidebar-items{{page.resource_suffix}}.js"></script> {# #} + {% else if !page.css_class.contains("sys") %} + <script defer src="../sidebar-items{{page.resource_suffix}}.js"></script> {# #} {% endif %} <script defer src="{{static_root_path|safe}}{{files.main_js}}"></script> {# #} {% if layout.scrape_examples_extension %} @@ -77,36 +79,51 @@ {% if page.css_class != "src" %} <nav class="mobile-topbar"> {# #} <button class="sidebar-menu-toggle">☰</button> {# #} - <a class="logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {# #} - {% if !layout.logo.is_empty() %} - <img src="{{layout.logo}}" alt="logo"> {# #} - {% else %} - <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {# #} + {% if !layout.logo.is_empty() || page.rust_logo %} + <a class="logo-container" href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html"> {# #} + {% if page.rust_logo %} + <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt=""> {# #} + {% else if !layout.logo.is_empty() %} + <img src="{{layout.logo}}" alt=""> {# #} {% endif %} </a> {# #} + {% endif %} </nav> {% endif %} <nav class="sidebar"> {# #} {% if page.css_class != "src" %} - <a class="logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {# #} - {% if !layout.logo.is_empty() %} - <img src="{{layout.logo}}" alt="logo"> {# #} - {% else %} - <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {# #} + <div class="sidebar-crate"> + {% if !layout.logo.is_empty() || page.rust_logo %} + <a class="logo-container" href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html"> {# #} + {% if page.rust_logo %} + <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {# #} + {% else if !layout.logo.is_empty() %} + <img src="{{layout.logo}}" alt="logo"> {# #} + {% endif %} + </a> {# #} {% endif %} - </a> {# #} + <h2> {# #} + <a href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html">{{display_krate}}</a> {# #} + {% if !display_krate_version_number.is_empty() %} + <span class="version">{{+ display_krate_version_number}}</span> + {% endif %} + </h2> {# #} + </div> {# #} + {% if !display_krate_version_extra.is_empty() %} + <div class="version">{{+ display_krate_version_extra}}</div> {# #} + {% endif %} {% endif %} {{ sidebar|safe }} </nav> {# #} <main> {# #} {% if page.css_class != "src" %}<div class="width-limiter">{% endif %} <nav class="sub"> {# #} - {% if page.css_class == "src" %} - <a class="sub-logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {# #} - {% if !layout.logo.is_empty() %} - <img src="{{layout.logo}}" alt="logo"> {# #} - {% else %} - <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {# #} + {% if page.css_class == "src" && (!layout.logo.is_empty() || page.rust_logo) %} + <a class="sub-logo-container" href="{{page.root_path|safe}}{{display_krate_with_trailing_slash|safe}}index.html"> {# #} + {% if page.rust_logo %} + <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="{{display_krate}}"> {# #} + {% else if !layout.logo.is_empty() %} + <img src="{{layout.logo}}" alt="{{display_krate}}"> {# #} {% endif %} </a> {# #} {% endif %} diff --git a/src/librustdoc/html/templates/sidebar.html b/src/librustdoc/html/templates/sidebar.html index 01d476ad29f..a99198141e2 100644 --- a/src/librustdoc/html/templates/sidebar.html +++ b/src/librustdoc/html/templates/sidebar.html @@ -6,9 +6,6 @@ <div class="sidebar-elems"> {% if is_crate %} <ul class="block"> - {% if !version.is_empty() %} - <li class="version">Version {{+ version}}</li> - {% endif %} <li><a id="all-types" href="all.html">All Items</a></li> {# #} </ul> {% endif %} @@ -32,6 +29,6 @@ </section> {% endif %} {% if !path.is_empty() %} - <h2><a href="index.html">In {{+ path}}</a></h2> + <h2><a href="{% if is_mod %}../{% endif %}index.html">In {{+ path}}</a></h2> {% endif %} </div> diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index e7f782bb6a6..17e2172a270 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -18,6 +18,7 @@ use rustdoc_json_types::*; use crate::clean::{self, ItemId}; use crate::formats::item_type::ItemType; +use crate::formats::FormatRenderer; use crate::json::JsonRenderer; use crate::passes::collect_intra_doc_links::UrlFragment; @@ -41,7 +42,7 @@ impl JsonRenderer<'_> { }) .collect(); let docs = item.opt_doc_value(); - let attrs = item.attributes(self.tcx, true); + let attrs = item.attributes(self.tcx, self.cache(), true); let span = item.span(self.tcx); let visibility = item.visibility(self.tcx); let clean::Item { name, item_id, .. } = item; @@ -453,7 +454,7 @@ impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind { default: default.map(|x| (*x).into_tcx(tcx)), synthetic, }, - Const { ty, default } => GenericParamDefKind::Const { + Const { ty, default, is_host_effect: _ } => GenericParamDefKind::Const { type_: (*ty).into_tcx(tcx), default: default.map(|x| *x), }, @@ -491,12 +492,14 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate { default: default.map(|ty| (*ty).into_tcx(tcx)), synthetic, }, - clean::GenericParamDefKind::Const { ty, default } => { - GenericParamDefKind::Const { - type_: (*ty).into_tcx(tcx), - default: default.map(|d| *d), - } - } + clean::GenericParamDefKind::Const { + ty, + default, + is_host_effect: _, + } => GenericParamDefKind::Const { + type_: (*ty).into_tcx(tcx), + default: default.map(|d| *d), + }, }; GenericParamDef { name, kind } }) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index fc2acb6eaa3..67f5ea5d98b 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -6,6 +6,7 @@ #![feature(array_methods)] #![feature(assert_matches)] #![feature(box_patterns)] +#![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] #![feature(iter_intersperse)] #![feature(lazy_cell)] diff --git a/src/llvm-project b/src/llvm-project -Subproject d404cba4e39df595710869988ded7cbe1104b52 +Subproject febc39711a7c91560eb0f0980916ae23c343b99 diff --git a/src/stage0.json b/src/stage0.json index 201f9a0c612..32dc8a2f83c 100644 --- a/src/stage0.json +++ b/src/stage0.json @@ -17,381 +17,385 @@ "tool is executed." ], "compiler": { - "date": "2023-08-22", + "date": "2023-10-04", "version": "beta" }, "rustfmt": { - "date": "2023-08-22", + "date": "2023-10-04", "version": "nightly" }, "checksums_sha256": { - "dist/2023-08-22/cargo-beta-aarch64-apple-darwin.tar.gz": "3a683934876a9794ee7ddbcf7cbf5d804d111fe02b324aa0a0321ec9cdfa8cfe", - "dist/2023-08-22/cargo-beta-aarch64-apple-darwin.tar.xz": "6543aef16521f2d7b4b6eb9e69e003dd8adc3f35a3af7d9d35a6fe8580ccc407", - "dist/2023-08-22/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "c8f7ec0b5b796c5218372ffd717728b3d70b56e6ac9002e351ef165c45455f66", - "dist/2023-08-22/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "d6778d5c515222a53a446ced90fe249613a537538ef2cb5aa5bdd807043907ca", - "dist/2023-08-22/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "c077c1851e22ae9b13bb2cb6227602b57427916a7412a63365711c10a8c05df6", - "dist/2023-08-22/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "a33dbbc00ef63ed18e48e42328f25932d1adf62531ed614c650d5e16ba68efac", - "dist/2023-08-22/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "0a68d407c8301f5dadb99cab2583c4e036539b52f46936995fb3ece4ab009551", - "dist/2023-08-22/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "577bb44224b03d5e50f511176a2a28cc900fd39ca581c7ccdd8c098c1ca48e9a", - "dist/2023-08-22/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "5cfea3f60889c5ea51398427fd34166f94c57718a65556abbc942decdf23366b", - "dist/2023-08-22/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "546b0f2b40edfede8176d68ec8278f7908d606f7f22daf3837fcc5beb5a04284", - "dist/2023-08-22/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "362157d5d3d6ccfd7734f2fbc6e3af28b85c7fec7bb1ca7c82fd5cb786c877c2", - "dist/2023-08-22/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "05c51f3d4479a6f5ad562406e13e33cfd1c193a1d48190210fa2cea48da019f9", - "dist/2023-08-22/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "ead8d3d836f57d6dd02a1643446c9d8a34bf20d64e1bc402181ac8e44848c877", - "dist/2023-08-22/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "ee127cafb6411ef6a4f7cacf2ea90b69b86201f488abd9acb3e82d22fbf56dec", - "dist/2023-08-22/cargo-beta-i686-pc-windows-gnu.tar.gz": "141bfa0ab5bac465ff7cdd91adbc2c293e78cabe458f2d425c6c0ae9b2659d66", - "dist/2023-08-22/cargo-beta-i686-pc-windows-gnu.tar.xz": "dc90fcd745217c237fd570a8ada5c45773066cf58e26bcb87476d5775da32906", - "dist/2023-08-22/cargo-beta-i686-pc-windows-msvc.tar.gz": "07fd85b164a96ef666099fddd03add274e70b11d9343344c627adfcd5c5d4d48", - "dist/2023-08-22/cargo-beta-i686-pc-windows-msvc.tar.xz": "96fcc0fca2870cf3d4ee8ca167b059b9e4d09bb81c88517cccdd1a082f5aa233", - "dist/2023-08-22/cargo-beta-i686-unknown-linux-gnu.tar.gz": "cc9f41d9de949b08964c6604eb75fc2fb3b79d939e9134c54698aaf4fb701dc3", - "dist/2023-08-22/cargo-beta-i686-unknown-linux-gnu.tar.xz": "e5c557c9704ccd9d5d39d3dad5537c3ef152d0b997806f9d9ad0bb91a2ef2fd7", - "dist/2023-08-22/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz": "ce2082ae94f4ab525e500374ac57bc13d32f8ec1a7dd9896bcd9c9d9c5e3eaf4", - "dist/2023-08-22/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz": "ff18d5b23fd463be8461c27a0ee4a4662f1be1d57f69358597faf915ae42d92a", - "dist/2023-08-22/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "4eb7ee68f3932b4519c9c4fb55b8e79ec0a1dd0a40b17cfaf2c0685201280e74", - "dist/2023-08-22/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "95aebdc6896767735e6e8b5e9ec31511fae8281bd258757f25cf9b91230e2a61", - "dist/2023-08-22/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "758fd95274033cd40809988da287a72de426267a2fc399d46992a97177f08264", - "dist/2023-08-22/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "c33c0da9d12fcf19ef145d22f5e8046bcf0df344f325932d620c11620e87b880", - "dist/2023-08-22/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "71485becac68eb4c47627152a1958226a8b1815f8c5121ef8e4886109a1da559", - "dist/2023-08-22/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "c03bc6285489d415c5f520c268430edd5edff9aa2c0bd3ceecacf4e916edc4b4", - "dist/2023-08-22/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "a0f18fe47623d2c30008cf9becdc4dc781b397efe3cf163fd6c4459ae824e641", - "dist/2023-08-22/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "8b67e2d9ff285903baa094a23c1a4bd9a959ab6f99193c93a9c1695fcde6ffa8", - "dist/2023-08-22/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "399ecc7f0d6f0efd9ae2c4bf382ea45f0054f4baa87a415e2f4cb9998fee8f24", - "dist/2023-08-22/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "465b456e2c34f9066f9ecae13f8e6608cc8cebe3218036794996ed9643a20c3e", - "dist/2023-08-22/cargo-beta-x86_64-apple-darwin.tar.gz": "297bdd5712507eb14c39e37128a24960cacab0319a885fef205b5b31978f4100", - "dist/2023-08-22/cargo-beta-x86_64-apple-darwin.tar.xz": "5a4bcf28c268bdc7a863e7c89595522ad0b6a6ebb3ed3408adc57670c76b5d21", - "dist/2023-08-22/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "f70ce4727665a4cc5f9d7dba8ae91a50a5ab9b834b88eb525a8b213fec25624f", - "dist/2023-08-22/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "7349e7a7c20fd38332a27119ef72f09b8b54ac3c7bc937547f478c3f2bc619f0", - "dist/2023-08-22/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "de204ef0efe760c974ed2f58a3cee7532a1275bbb146f7a648360cee5548b2fb", - "dist/2023-08-22/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "b1f77cd3deeb33f2cb24a568c4530e3cffd6194c8f1363baad356d12f3aa6899", - "dist/2023-08-22/cargo-beta-x86_64-unknown-freebsd.tar.gz": "56a2770793bb768684a84b4d99d8287bb04365c4017c3c0802d36a37e33281af", - "dist/2023-08-22/cargo-beta-x86_64-unknown-freebsd.tar.xz": "c9ae52f1212ff635f3300befbd33e575c308e14ff13f0ac30d5d97a3797788f1", - "dist/2023-08-22/cargo-beta-x86_64-unknown-illumos.tar.gz": "8e5ad86ea47eb4901cc7efae579c855a1b3eeee889c7e39fa248eea4465ac6fb", - "dist/2023-08-22/cargo-beta-x86_64-unknown-illumos.tar.xz": "56b3d2363c98537bd70d5e54b1caa446446edfd9fbf3efafd1f1e5ed24985c02", - "dist/2023-08-22/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "61bb143b2a7969fecb28755227e258d2018d8344c5325b2709b3d3b34aeb6bd8", - "dist/2023-08-22/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "6a5ff803aa4e57e35175fb62cea3687f26a55e9ec6bb0e9066fce27c4f4df727", - "dist/2023-08-22/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "2af897d7e7a9b09d645dde71b81a1757e5ebdeaa0291d5c50ddc95d3b9fe08eb", - "dist/2023-08-22/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "41fac61a6ca64490400807dfdcb96076926e61174ec295e8c6534b41e5541e71", - "dist/2023-08-22/cargo-beta-x86_64-unknown-netbsd.tar.gz": "29d324fb629b1aadc67d207b9a4e3156674a762970131399b10a7d8a6de152bb", - "dist/2023-08-22/cargo-beta-x86_64-unknown-netbsd.tar.xz": "a1f216345774fa9b812ebe3f8adaa4e0be152d095e73f289fa70d53d04d27fda", - "dist/2023-08-22/rust-std-beta-aarch64-apple-darwin.tar.gz": "0b45d8fba14876a6323c8adc8368916f8581c868d63c10ab65c0e50f4c021a32", - "dist/2023-08-22/rust-std-beta-aarch64-apple-darwin.tar.xz": "f471a9373c16260f8ed8b467c6065847a788864289d979efb406e99976d14dc2", - "dist/2023-08-22/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "3c0e3226b47a8742061587050048db97843e6c96b08930ada010c07fe06c89e6", - "dist/2023-08-22/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "7739c05595dadb2f021881b0e38d16cfbd705b0a5d31ac395b8fabb2244c8050", - "dist/2023-08-22/rust-std-beta-aarch64-apple-ios.tar.gz": "261b76a4f1ba923477163a868b539781911c7d0bc8dc944530d806eeb6634cde", - "dist/2023-08-22/rust-std-beta-aarch64-apple-ios.tar.xz": "c16102bef9f2d4fdf3c970e2f4e8316b4b2540b43855860be7828209b63c8fb3", - "dist/2023-08-22/rust-std-beta-aarch64-linux-android.tar.gz": "2b6e30df92c4b0c6e464ab59a37865ac91b4c4c4863b06f2bc872d50e2799bd1", - "dist/2023-08-22/rust-std-beta-aarch64-linux-android.tar.xz": "dc8e6fd9d6952969c97af01358034c9ea21182fd5061dc92527aae73b4305bff", - "dist/2023-08-22/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "773e9b29d36ea66a79df8cbfe0ea28ec77b31b1b042563584a1830d814eec269", - "dist/2023-08-22/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "e40c8120fc1850818ffbd151d152b317f7d306fc27d8305bfc376cf55d7a5863", - "dist/2023-08-22/rust-std-beta-aarch64-unknown-fuchsia.tar.gz": "c61713b4a7f96a6813f96672811de1d979e732db07c177e7a031bc7a3f22781d", - "dist/2023-08-22/rust-std-beta-aarch64-unknown-fuchsia.tar.xz": "1f54408288a19041e58114766263928ec7bee7815c392d25bb1abb5ba2107b13", - "dist/2023-08-22/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "90be82b6fa985c80ee709113c6fae68c0a6055a6b3b63b84e34d98d1f192dfbd", - "dist/2023-08-22/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "a2367d58c58aab240049fd5819f7a1862365c8ccdbdbe43cb94fc74ec4b424e8", - "dist/2023-08-22/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "2525b581645aeb8c07129a7680f7ef76e87af4633fd533ac991fd4868049b72e", - "dist/2023-08-22/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "6dcca8f5b63968ebc6adc066d76a4ef53112f52dd160f135b0a029832fe25060", - "dist/2023-08-22/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "8f07966490ea30beea51e79dd158c41699cc0cc5a5b3cfe211f3452b2d1265ad", - "dist/2023-08-22/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "9cf5cceb96eb5e2bd6bf05ab663a92db637c7af3c58bb921ea75b61b9075ecab", - "dist/2023-08-22/rust-std-beta-aarch64-unknown-none.tar.gz": "41622341bffd5352c4248535f952f721638ad9e0ebc74b5452f41dd6ee261017", - "dist/2023-08-22/rust-std-beta-aarch64-unknown-none.tar.xz": "cd149fd111b65631e2535ae79dc0fbc4ae69d6ebd25d4f91751f76699be74f2f", - "dist/2023-08-22/rust-std-beta-aarch64-unknown-uefi.tar.gz": "b884565f46a93bd75bbb86a5565d5c6fbba925372d00b8fbb5782f6948f1c6ed", - "dist/2023-08-22/rust-std-beta-aarch64-unknown-uefi.tar.xz": "24c4e88d966a7437a9008a02101c0eb333a78fade9e71113491b586b89d80bbe", - "dist/2023-08-22/rust-std-beta-arm-linux-androideabi.tar.gz": "9b47e40f002a9c8134fa96f3c8566a5ccb5543903804254c59d7102dcde59725", - "dist/2023-08-22/rust-std-beta-arm-linux-androideabi.tar.xz": "96d2b153979301ec03b04b2a35052e2be1edf67693dbef43bdd46eec258604ed", - "dist/2023-08-22/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "4f4b08d6773721b796c8a4928061647285e7b06e5a93472fa3578d7f5f96ac83", - "dist/2023-08-22/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "61b62b29fe465550e07e62eddf786086c3a38a7e98c533cc86a689b657061fd6", - "dist/2023-08-22/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "22091e84c962c9291481454825401693b757ee5cc2332a2a3d8a95c93bb8bd6b", - "dist/2023-08-22/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "48e273442bc827d22b177e8b33b1be897da20389ead5cce2de2bb4c936ebc845", - "dist/2023-08-22/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "74c06121290814a97c82a0dbb8160721d27210d58a3a4b1b5818daca8265fc01", - "dist/2023-08-22/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "e15a6a3372901716856e606b369392d270dff0b3293988e5c621b86b384f3dc1", - "dist/2023-08-22/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "e1acaa191877b3debb6b0b59c3aa47937f0113fc3084dbe193944916fd4e810f", - "dist/2023-08-22/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "e94f16fbd527f39c1b9b3f09b977d7fd07547bdcf00385a2a3a235130c82140b", - "dist/2023-08-22/rust-std-beta-armebv7r-none-eabi.tar.gz": "26fb63d61f57b3ae18d5c014430ed9311cad890d88b8560b1094f2d1f674a394", - "dist/2023-08-22/rust-std-beta-armebv7r-none-eabi.tar.xz": "ff7d3403858c5e77da1da28c7ad81085151dc0c004189a331d3e5f3d8a2d93f9", - "dist/2023-08-22/rust-std-beta-armebv7r-none-eabihf.tar.gz": "f7a2b8e8810a19540186d6c9677c487bdac387a94dc6268cbff778dd93ac1b3a", - "dist/2023-08-22/rust-std-beta-armebv7r-none-eabihf.tar.xz": "b4a7c4b6d47dd3a57b1e05afeabb381d624ba1ebf8e789aa10f00a7efc6b329a", - "dist/2023-08-22/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "ce7810ab026a6dea1732d983238df88d21ca94ef10f78a06ec2e366149a6ed76", - "dist/2023-08-22/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "b31641f975c76f63f8c43402db571edb3b335b5dbae1b95c6362d3515d5d28d1", - "dist/2023-08-22/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "75438e97bf98c48c448ea8b96fba21a5f31c919f2da8c8fe048bd54950964ffe", - "dist/2023-08-22/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "c8e1c0f109722ca0918dcba00544692abf8d04a98f86b586b513f06d77111c4f", - "dist/2023-08-22/rust-std-beta-armv7-linux-androideabi.tar.gz": "fdc3d9960d0ff11c03e9c7d0c997aba7a5e480b860410a422035f69359d12451", - "dist/2023-08-22/rust-std-beta-armv7-linux-androideabi.tar.xz": "a2acf41ea19e582b99fcbf56e37eb35e9a309bc6183553cbaf12b9dff976dab8", - "dist/2023-08-22/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "81d1d1459526343aa5ab66432eab7dc9557d0c07550cbdafbbf5e402be7eb833", - "dist/2023-08-22/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "baa369b9c1df4820f6a8593193bb5376002c79e81dc0681c2329a45ea664a87b", - "dist/2023-08-22/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "b9e06051b2705ce2680723e3209ed0099a05cf2f2c71342e1176c16e485ee66e", - "dist/2023-08-22/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "5633759d31f4b390f2f9b5f63a0dc7f027a2dbe1241fe7089c06931c360a5f46", - "dist/2023-08-22/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "141232d8b440588d181c2d550151879ad6bae9a5af7875e6428bac6e65f6d8e6", - "dist/2023-08-22/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "5a82fe0b4e9476b642134071858288e47137aa26de88bc892580ab777650094b", - "dist/2023-08-22/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "8d9821484c5bbe8c51d7d54859fb8bc475ea6cc2f863fadb29b2973daf3535e7", - "dist/2023-08-22/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "e68834499329dac318fd51c49dd23836c3a6db0eca746869f8dc38d286b5f8ec", - "dist/2023-08-22/rust-std-beta-armv7a-none-eabi.tar.gz": "3353d69ace1f00b7c9d6291144a0ce73edefc5e7498fcb04dcc336edcb3030f4", - "dist/2023-08-22/rust-std-beta-armv7a-none-eabi.tar.xz": "d783d9ab96541426a5cdb2e6e866d0b9b1492e64030011aa3503b6558a4b3acc", - "dist/2023-08-22/rust-std-beta-armv7r-none-eabi.tar.gz": "28b6a82549de0a84323ff7db7104da9f978d2044997681b2ecfd6fbc7e14f806", - "dist/2023-08-22/rust-std-beta-armv7r-none-eabi.tar.xz": "f32aa5def56e3ff083d380de063ff5239f19b2b2ff8648f1f092512a621c8291", - "dist/2023-08-22/rust-std-beta-armv7r-none-eabihf.tar.gz": "f7a57d763304b64e732b46dab90bcf93c712e5e0e5b558ac20033658f4b27e2f", - "dist/2023-08-22/rust-std-beta-armv7r-none-eabihf.tar.xz": "4b74d5e31d3317b0f5519693005ad4c2b3b5093531deae630ab210e177f5b41f", - "dist/2023-08-22/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "691200324336964bb254c98350f6d2c0e545a42d7c6903c76a7812b068cc18b9", - "dist/2023-08-22/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "c2c0ddf54f7dcb60c069117c7139c2c1f57e8f9976447651df2dc9c6507b3ef9", - "dist/2023-08-22/rust-std-beta-i586-pc-windows-msvc.tar.gz": "971a6f1507ac8e47a9e2435f9f0fc5a24f77393c6ae189057bae8cd1ac35d5da", - "dist/2023-08-22/rust-std-beta-i586-pc-windows-msvc.tar.xz": "4af5f8c029f2486073ac4b71725526cc1ef4f3861ba652190cb940273fb2ebbf", - "dist/2023-08-22/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "4676906af1dca83ae3dba5972444ca2b15a755223ae999ec9eb66072125b9d60", - "dist/2023-08-22/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "a2b556a5afe3c69e91eed6d7c6ff31971598eeb35c227b7aca46548b80eff7fa", - "dist/2023-08-22/rust-std-beta-i586-unknown-linux-musl.tar.gz": "e8501702dca37516dd8b567c277b74d19a2e1142ca4c97b881b3428aa3a0bdfd", - "dist/2023-08-22/rust-std-beta-i586-unknown-linux-musl.tar.xz": "a0fd2fcd9a0844fd4063b80189a342d77e6d0c087fb240e28ffbd1b98813ec13", - "dist/2023-08-22/rust-std-beta-i686-linux-android.tar.gz": "ed1445ae201aa69997b850037b98beff658e92a25e860ab525617836de366d72", - "dist/2023-08-22/rust-std-beta-i686-linux-android.tar.xz": "e9be5e895d4e61d3130a502ae3aae8b796028fe8334f161659e90c8feb38d8d0", - "dist/2023-08-22/rust-std-beta-i686-pc-windows-gnu.tar.gz": "41666fb8c03e1403f67f6fb595b1c21c522faac78ed8a9664d476f69825d15ed", - "dist/2023-08-22/rust-std-beta-i686-pc-windows-gnu.tar.xz": "64db89392d6aabdaf39d810f3aa8692a50ad68214db5ae08565462e8ebb1ddde", - "dist/2023-08-22/rust-std-beta-i686-pc-windows-msvc.tar.gz": "cf1e94aa60bd9c273216df658b9cc7c947b3f8b47f1eb4f7df63c07a328ec0a9", - "dist/2023-08-22/rust-std-beta-i686-pc-windows-msvc.tar.xz": "e69ca7df48d927d6fdd40b4de3e5c8d402aac9aa29e7f3cbbd45d3227a4a438d", - "dist/2023-08-22/rust-std-beta-i686-unknown-freebsd.tar.gz": "ec23333c6c7af11adcd8a01c6f722a6103c92a925c197a1f2797780ae1b84c42", - "dist/2023-08-22/rust-std-beta-i686-unknown-freebsd.tar.xz": "301c39d275e3b1d32076364c627cb4953ed200dcf092d4a7925ac662a165ca48", - "dist/2023-08-22/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "722ffca25c78d9a83632773ab0bc36e0b999cea66f767dfd2e15171790c14cc9", - "dist/2023-08-22/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "384ab84d4a8d6fa5429cd5e13a72591a50041e84e846f12105001c1defea08f8", - "dist/2023-08-22/rust-std-beta-i686-unknown-linux-musl.tar.gz": "913a316a08a15b123f6b136335886a4886de0d0cb06f02b14f82b436e34c83f8", - "dist/2023-08-22/rust-std-beta-i686-unknown-linux-musl.tar.xz": "6b440b91f3ba0319d39e73181b173d630098eec1ca76298a13afc69afd156c58", - "dist/2023-08-22/rust-std-beta-i686-unknown-uefi.tar.gz": "a32f3b2e6951316af9c557bc128b95b797586881cefa0f311e6e44779d4c6bd3", - "dist/2023-08-22/rust-std-beta-i686-unknown-uefi.tar.xz": "7deb5fff47eb1ba074f1835f9db54afbc892fce287c0ca2a2590e8bbd6d2168d", - "dist/2023-08-22/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz": "1f825781e403bbfef798a8038c3c4f800b838923b306866b21314902db06701c", - "dist/2023-08-22/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz": "a0b341d9464a8a68c7c395ff051ae384066ce0f97e0a3c50b8adf6ef253ef6d8", - "dist/2023-08-22/rust-std-beta-mips-unknown-linux-musl.tar.gz": "526041c26f3854c25b60969bf45e52d5f3d9e1548f9ea06942c0673434b115bb", - "dist/2023-08-22/rust-std-beta-mips-unknown-linux-musl.tar.xz": "c01d689e540777f8120775d05f93631e31ffcb05bdafcea2d3f1eda8af915f9e", - "dist/2023-08-22/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "f03f3b2767b2775e8f74d190ac1614307f2576c8966eedf710663bf39cf99027", - "dist/2023-08-22/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "9df204a1c45770e72c49e334ccdc47779825b1c0ae979576f40393a6ef05de2a", - "dist/2023-08-22/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "4892c903b692ea7fbd59d9dacf3ddc886fc0eb771d817c3dc906a875238d1f91", - "dist/2023-08-22/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "47cb42fd72f3dc488d30a959447698932fcc9499f50fb78e585fd208465c64c4", - "dist/2023-08-22/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "9d2b04e6ca70c95f157f9e273776bf10979090871307f67b4aed4f8532dd9905", - "dist/2023-08-22/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "70b260a23b6dc2c43041e15167de8a8589d2e33a65feada35a1ea9c3912db93e", - "dist/2023-08-22/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "a5af9e233e3fd518a2976dc75e5e79555fb9722c9b532f6d6a16c2944968f660", - "dist/2023-08-22/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "5d83a2ae7ebe2242f6370febe19fbf606d0282d57ba2dcb08b483c4cf0fb084d", - "dist/2023-08-22/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "9160571a2ec98b1fc91a10134c842c34c8370ac9990adfcf6368e90a259a4b89", - "dist/2023-08-22/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "be22e907234b415684e90af6c0a3a5ebec114511235f223de0ff2393a929cfe8", - "dist/2023-08-22/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "c73d1e7282d6f85097f13931a7ff5b66bfc807605284b35cacf2a94f9fb4ba0a", - "dist/2023-08-22/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "75e7578497fefdf7aae1b1d0a4e20855cfb06ed2f58bcea5cfdb8e71ba224c35", - "dist/2023-08-22/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "b692e3bc1199f3a7687fd8e5d6224696e56280ea989c402d88ef3da3fad2ee2a", - "dist/2023-08-22/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "61e86b7e3a9f8004bfa1a72cef3bd62eee1ee67964c747d6387d62ab8680f237", - "dist/2023-08-22/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "4d5c1935405d66a7e1a7532b165ffcddd4501fab25f346a0c57d06d7d480f370", - "dist/2023-08-22/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "a581a2224049bbeefdf81ed556960fbabe3d762abbd9ea7765425b2d9d0403cc", - "dist/2023-08-22/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "64d1a7bdd061ac16c585ae035e7b1d2f7b4ee4c2a71f491cf4ec39d3a9cf4904", - "dist/2023-08-22/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "528bd7a62c69a53c3aab2488be12de23199fb0a3aa4b117e1b906af7b06233a9", - "dist/2023-08-22/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "6808261b20282eedf3ae11e6300379ff1dafcb4fc22c0fd7eba5fb8e31fe4a97", - "dist/2023-08-22/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "2782284032eda7797d725e8986bcc5104a28f46e13c9774d8c1b115a3e192cb8", - "dist/2023-08-22/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "2e77b3d53304eae6cc8111d627f8114e4e0b759a66a696937632a95cb213302d", - "dist/2023-08-22/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "a8592a9d233085e65f87f7d5c290fb3bd3a88f9fe3492a5bad4afd5f64def27c", - "dist/2023-08-22/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "8d753ca5922d7fe6782a8dcc366447fd0062784a21f90b210c3946e6eeeb0a0e", - "dist/2023-08-22/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "29fc30370d9b08aaf9b5b36a23c463a494f673a3cc9207dd600dce9498b0c6f5", - "dist/2023-08-22/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "587e51be642bd19528ac7942b2026be31086d12dc81dc8a324ff662328b2fb1b", - "dist/2023-08-22/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "38759bbd4ad799e02c9a3c5947ca5637a2b7b716fe51e986788ea424d3dc0310", - "dist/2023-08-22/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "bf702a5aaed572fc753d27d786ccc9f83664d6b66812d9a9e8b3ba63397857de", - "dist/2023-08-22/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "187906dad30dd2da2f608e3713b6cb2ffaaf491c8109f4d381d4ba9b92e5c82d", - "dist/2023-08-22/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "368835053411c9a9ea8a96813f12724989aa6e00b160f7e75628155b038e06a5", - "dist/2023-08-22/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "f85bf85725ab2ba21e83f5d024cc1c9bccb5fe4b90760f0d34383a0cfca000cc", - "dist/2023-08-22/rust-std-beta-sparcv9-sun-solaris.tar.gz": "1f5632a33b2a94354e062821b5ed5a99810ed0d88c8e8370349c08f4541095f3", - "dist/2023-08-22/rust-std-beta-sparcv9-sun-solaris.tar.xz": "dba0efff671c805c9fa1893bc41a9076436bff1a10f8a5bfa59f5cf01e22cfe6", - "dist/2023-08-22/rust-std-beta-thumbv6m-none-eabi.tar.gz": "3d88eb30d86fe6f486f45bd36d53667f1f886636235f16ac197eb1b6287d228b", - "dist/2023-08-22/rust-std-beta-thumbv6m-none-eabi.tar.xz": "69907d0d70f4a70ca5d28cb9ce19824c6cccc85db206b6b993516980dd469a51", - "dist/2023-08-22/rust-std-beta-thumbv7em-none-eabi.tar.gz": "7bedf1b999e78505f61b409dad228877c92def1df273d58347f8379e8496c0f1", - "dist/2023-08-22/rust-std-beta-thumbv7em-none-eabi.tar.xz": "125b71e59a23077ab7b5e618a48022c467d5e9c4d8e069ed101f9d9634a9e2cf", - "dist/2023-08-22/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "6e396659da4b82f5d66168569f9f8d7283b506d56423916a6e506f489557e07a", - "dist/2023-08-22/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "830981defa1a25be5fb9e7367126802a4f3c50f251bc5b77c80693189a02fe2c", - "dist/2023-08-22/rust-std-beta-thumbv7m-none-eabi.tar.gz": "7d457a6697ea4f0786036791b0769fc581ef44c748ce76717e84f93776af4de5", - "dist/2023-08-22/rust-std-beta-thumbv7m-none-eabi.tar.xz": "03551f2cc2ed4337db19c0b6dd9d7e155988dc7a9d8ed0914ee2fdb4a0e83f9b", - "dist/2023-08-22/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "b209802836c48d3ba7b61b31b1192e2b0eaf38333c307541004c4ff2bbc83453", - "dist/2023-08-22/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "6ec3cbe221f47c412b6f45bb8a3ceb039078462be5a64c3f226595c276aa40c1", - "dist/2023-08-22/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "ef40a875465653f636270fd610def70c2b6d1fd0f3cc5622736ea3d9fccfeb1c", - "dist/2023-08-22/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "79060f7930e9e6ffa1aedfb1f5926b96541fccd4b6e861fc2b9452ef5eca77a2", - "dist/2023-08-22/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "2f33509dc88e1033cbb8b3478b1f7c27065eccb12d54b65a4cdbf331be111636", - "dist/2023-08-22/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "2b92276477d70ea1f02befe72d7a18dc65a1c727dcc5e6ca6e13b0e6d6395648", - "dist/2023-08-22/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "d4e70b2edcbbd81bd68635b067f413de2c4fae69227f70cb78d9a3a90c0cae7d", - "dist/2023-08-22/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "c01c168943c37de7b5c76a49ae329327c45e7eedd65419f47523b26a1ab7aae6", - "dist/2023-08-22/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "7cf03fca058895f05cb583248fd25526f8d54d2607cc484aac63581312162ea0", - "dist/2023-08-22/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "18c8bcd69494f91938e51b8b9cc0dac01533be3b380e5c939096eb35ba7cbe34", - "dist/2023-08-22/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "550440258ce3b993180c285ce9ad363a0e604704d92f924018bff5be68a94944", - "dist/2023-08-22/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "0622611a929a752ecf2c15e6590b6a50ec3fdfa0c7b0fc9f927be3a641ef6fee", - "dist/2023-08-22/rust-std-beta-wasm32-unknown-unknown.tar.gz": "338f5bc7db5648b9b578889bf197fdb120c7c1b6be6a6c41b1e1efab2b19d87a", - "dist/2023-08-22/rust-std-beta-wasm32-unknown-unknown.tar.xz": "6fe28fa351a51f48051010aab7399d9a9bc43b7c60fb9ec5dc8a0323f6ebfcea", - "dist/2023-08-22/rust-std-beta-wasm32-wasi-preview1-threads.tar.gz": "b2d3aeba309f689f20902e41058c400f79f28c9fd8b9b03e4bb0562d1ed9e087", - "dist/2023-08-22/rust-std-beta-wasm32-wasi-preview1-threads.tar.xz": "1d1de7bec3f1744082e0805601a6058ecc39d14064456d9910640a4f1f84604a", - "dist/2023-08-22/rust-std-beta-wasm32-wasi.tar.gz": "45ec2a9e021e7d7b521349a69f85efbac748f8b4abda6212bb0c7273f8053d0e", - "dist/2023-08-22/rust-std-beta-wasm32-wasi.tar.xz": "53bb87e58a84e5afa029d66e5dfe85a6e9ca8b5987c5543af6eb039f052b428c", - "dist/2023-08-22/rust-std-beta-x86_64-apple-darwin.tar.gz": "7acc137790fa64ebe1ff5152abd86f42c643ad6d858f130d1b210d80e98893b5", - "dist/2023-08-22/rust-std-beta-x86_64-apple-darwin.tar.xz": "b9da0c71bbe58c152f39a3f3f79308a49fcbc41944211024c097c156e124a56c", - "dist/2023-08-22/rust-std-beta-x86_64-apple-ios.tar.gz": "915831f0eb14aac95e1416fadaff2b6e0ede3f6968fb5b941986004eb389b887", - "dist/2023-08-22/rust-std-beta-x86_64-apple-ios.tar.xz": "2f7df0e1c43eb73232db1f888d42a639deb4d69e6cb09d11581b23687131f6d0", - "dist/2023-08-22/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "89203b4d908fde29b0fe45d0e1665cbcee7c34d40bdfbce6d97e31b7d608136a", - "dist/2023-08-22/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "9d006df537590eb7d1ec8014348103d3a1d91bd2e627ebcc4f179e83737b4915", - "dist/2023-08-22/rust-std-beta-x86_64-linux-android.tar.gz": "0569509106e866b3a06cc814f928481f0a06859d498440196d5994f23591b5cb", - "dist/2023-08-22/rust-std-beta-x86_64-linux-android.tar.xz": "dac7a334e980f4525b126d33e9609edcc3aad12c3fb011d715a0722d68722dd1", - "dist/2023-08-22/rust-std-beta-x86_64-pc-solaris.tar.gz": "1a34ab28dda35646171ef49f0a7274943bdaa8bc73a15261d16decec2ecb64c9", - "dist/2023-08-22/rust-std-beta-x86_64-pc-solaris.tar.xz": "55a1c71616a85144950cfd92fa7f64471396d5e2c8744bc936c3fcc209bead1b", - "dist/2023-08-22/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "d60cfada9d49c518d90dc0b4040bef383f857a15c6dd9e9983b8fdbfe8b24ea6", - "dist/2023-08-22/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "1102177596d61d23b5f9c9a93ec31fe5d9e0f271d7b49edbd47bcd59f4309ed2", - "dist/2023-08-22/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "0383b7094b6c02266c144223c868ead1edaf55517bdab7e94953f8282bc4420e", - "dist/2023-08-22/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "b2933c0d4600cdbcafd22196b70158721c0a16e864ff292fd6b919fad05355d2", - "dist/2023-08-22/rust-std-beta-x86_64-sun-solaris.tar.gz": "a5b0092f5a045601bed31bdb83dd7f15a332f7579a624f073103c67e7a57af7a", - "dist/2023-08-22/rust-std-beta-x86_64-sun-solaris.tar.xz": "1b0111216a66e7d7ae9b7b996567e932dcf7b50e202bba9281d1dfd704e26e3e", - "dist/2023-08-22/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "cc5e94874385ae0ec2a9a8dbb3efafdb88fc5134cb2be4f378298c9e413e18b4", - "dist/2023-08-22/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "9653bf3ea33bf9502eb90b72c0696af0cc90dea54e9d6e5be97783db3e8286bc", - "dist/2023-08-22/rust-std-beta-x86_64-unknown-fuchsia.tar.gz": "6193c991d35a6fc0386b42ff1944f473ffa95012ca2fb43008200d6e5cb78d78", - "dist/2023-08-22/rust-std-beta-x86_64-unknown-fuchsia.tar.xz": "3a6c169f6f09d7bda84aaffa348a1b379cfe221b567b67ad35391b9e5e3e34ca", - "dist/2023-08-22/rust-std-beta-x86_64-unknown-illumos.tar.gz": "6299ee2cf0aaa5da48aab83230f55effeebf47a72ccd7dd27b4649629d5f3b6b", - "dist/2023-08-22/rust-std-beta-x86_64-unknown-illumos.tar.xz": "7fc1c33439be25983b4a02c8fa4b783e3187f94f6109e4f4deaf64cb83e124b5", - "dist/2023-08-22/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "76b1bda97f8c56213d4cc39e8d8cde59f0e6a50e9ac209b70b163dc58e346f52", - "dist/2023-08-22/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "14ef16f6c0e545badc8b49b16a9ead85cb4cc2c5e6f74105fea039866eddf111", - "dist/2023-08-22/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "df96bcc3a4f3c6c028fb7252057bbf8367b73061d6cdeb50c4e28211f96d46b0", - "dist/2023-08-22/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "2fa0fae38e0b8633065313fda983503a74c436798bf7f76e1c58ca76e8767491", - "dist/2023-08-22/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "f3ec6da0eded1e8b042e1d4d8de9161e0e1af7998618315aff462892573302a1", - "dist/2023-08-22/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "34ad894da8a3e315832adf6ae7ea7bef486219bd2c1011f849a47092cde958b4", - "dist/2023-08-22/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "3ec57e0485fa7e30ef93939fecf945a24fd47bef044eb0a91652ce6d8c8e5e50", - "dist/2023-08-22/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "02fb83bd1e43d10fc6afd3113c29fdb917e87bff0f039421ce297eff91351bde", - "dist/2023-08-22/rust-std-beta-x86_64-unknown-none.tar.gz": "97f65c1033980d6746d894d9cdef3793029d80e4820295b9a3128df497acb4ae", - "dist/2023-08-22/rust-std-beta-x86_64-unknown-none.tar.xz": "add0537d2ae67b696896368b7aa94f7357b0b6c313097f9eec00bd8f00395a7d", - "dist/2023-08-22/rust-std-beta-x86_64-unknown-redox.tar.gz": "7149623b9e584e41f0f6233aeb05a5aaff57a118cf13c41306e18eaf23de5929", - "dist/2023-08-22/rust-std-beta-x86_64-unknown-redox.tar.xz": "48be526da0d8a8dadeb4e7418a49a07396e132001034282515b859eba7c64d14", - "dist/2023-08-22/rust-std-beta-x86_64-unknown-uefi.tar.gz": "dc14c0faec4cbfa1572102aa5cb2148a58a9c120b40fcd3f092a839f58007dfc", - "dist/2023-08-22/rust-std-beta-x86_64-unknown-uefi.tar.xz": "ac0f60f26c61dcc659aa061be217d161099f404d38dd158f5a6f214143c308df", - "dist/2023-08-22/rustc-beta-aarch64-apple-darwin.tar.gz": "15b0448e87b74a06cc5f21431beb452884b836fb12ea8ccbbaaaa571bbbcd2d1", - "dist/2023-08-22/rustc-beta-aarch64-apple-darwin.tar.xz": "81044b7c60f619f58e5e21da1ccab36c2ce6da364aced4d7df403718f81f4ed2", - "dist/2023-08-22/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "c9f89bdf460cdfd50d11817aa2096de7a25d23be63f8e2e45de460bc7a221722", - "dist/2023-08-22/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "a484613c8b31462985ec6db77343298111e23b9034143fa528ebeccf00bedef5", - "dist/2023-08-22/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "1de5c389e1b60a8b585d35f44228466e1a6977b34c37067f11649aa7e703e1e4", - "dist/2023-08-22/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "424d6192234aa52a21acf10ee4339a9af293bb07e94c9cede67b4f82e421374d", - "dist/2023-08-22/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "bb7ac313a0d2c02eb59061a2d17672f0a73486cb6045e3ab43fef610fe32eacb", - "dist/2023-08-22/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "246e61b5674c3fdd2a11d033a987ead6dcc02b20301db791cfb1f31fe2bccc67", - "dist/2023-08-22/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "5380406b9921dc72ab29afcda33bb3d7dfab593c54ae3d5b3054d7a4f526befc", - "dist/2023-08-22/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "5834f4ab2100b21dd4c1313d2a58bed761543d60a0df5cc9e9d8ce1d086638f2", - "dist/2023-08-22/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "8a9aa58e47d9463aa71952c4c8e214f230c23f7c5a8c55706da02a84e31120aa", - "dist/2023-08-22/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "f832bd965354c1f6a8b982693ce66037a0a4b5eb242a915ab84a1545e90be598", - "dist/2023-08-22/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "da4fca6be3d3df88383cbd5f10556789e5f3bd16e05b4c09543edb14dcc8ce8b", - "dist/2023-08-22/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "d499d8b50ebc3af595872b359e40a41689adfe2a9ea7c7149cf556956370a5ab", - "dist/2023-08-22/rustc-beta-i686-pc-windows-gnu.tar.gz": "6e841881e0393b438e33f3c16f1d24a7036781844ac4eebf79042a33499f0f3d", - "dist/2023-08-22/rustc-beta-i686-pc-windows-gnu.tar.xz": "fe096f5ed90a3a2cf1d5da74c6b8e081b36dd868c4a1b6ea51e4a2e13cee2794", - "dist/2023-08-22/rustc-beta-i686-pc-windows-msvc.tar.gz": "b2b9485f44a0e25aaa56b3d1f82f1f6f224683800688ee4482d1c4025c337d03", - "dist/2023-08-22/rustc-beta-i686-pc-windows-msvc.tar.xz": "2c0e8c9ed8cae5e37ef60f1c5fc55f4370a260bad70cd675fa79d78737f9ca1f", - "dist/2023-08-22/rustc-beta-i686-unknown-linux-gnu.tar.gz": "27ba8f3457389683db058dbbee48b6844b9be5c0fc23711c00300b28a8b4f17b", - "dist/2023-08-22/rustc-beta-i686-unknown-linux-gnu.tar.xz": "2b45ee2cd1cb093bda5154280d0c81573fcdf512841ac5fbc1d1edb460da7c58", - "dist/2023-08-22/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz": "af5f367d0b97719ef4d3606276881015f069338d002ae3af8ad5be58f0778c2c", - "dist/2023-08-22/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz": "a37e870c5e25e9b4c3de30922461f756306424a7f85ab22da84c88b647c56100", - "dist/2023-08-22/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "7df41c44859a38a2652dd3a23524e75157283b276cb621e2c4dd04185841bd61", - "dist/2023-08-22/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "60ece70118660eff11744f6fde293b2dc27bd18a0b7d0cfd81e22c195a13a828", - "dist/2023-08-22/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "50bb7eec6172dde937dc8f9b3d6d3fcced7f896a19eb7fc82f83685a9745e293", - "dist/2023-08-22/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "23eec58bee6d42200d88b16ff0fa3977ab0223578369fc6a69787b5a52c44c62", - "dist/2023-08-22/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "051b46807d53e72a61ee38c28466620b2a03f9b5ebadde3c1c8b6dcbb35b6b7a", - "dist/2023-08-22/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "60382fa331885257998ea7fa93e55e47dddedaab04e962b21330c90ab61f4714", - "dist/2023-08-22/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "24e89e00a5e10256f41dba5f07009c2b2ea82ffdf54b6a9c3fea6b13daa2891b", - "dist/2023-08-22/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "5468061289f37b2014fcc52699ab8979a33ebeffb1c45e23a78607ec7589b3a2", - "dist/2023-08-22/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "34e892a6f59b53b2c7252045de9eabe437ff9d01accb051c74ce7912ab2fddc3", - "dist/2023-08-22/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "9fce7533f11da73efc00b31f5728ca1201c29915673b966840b2e0228f93aa74", - "dist/2023-08-22/rustc-beta-x86_64-apple-darwin.tar.gz": "41602031cb330fe01bd40e17ebf19a3925875f217604bde070e4c8536e971176", - "dist/2023-08-22/rustc-beta-x86_64-apple-darwin.tar.xz": "f19b3fa42e68810fd70a294206fdd8387dc9364fb5cde34cf87ef1ccd6aa6234", - "dist/2023-08-22/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "bbe52f430c7e9fd369341bc3c2931b79d79ee02c68d6a1a91919f5c09fff4e03", - "dist/2023-08-22/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "3f96c6b646bafb6104ce64eab83fd9c75734bd7e8b53b0b6db143b5a44fc1cb8", - "dist/2023-08-22/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "0a70402149eb92027265d5ea27c08fd14b0837a488c210f8ca7386981eea8f54", - "dist/2023-08-22/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "614228860c1f94fce353d279ee8dcb9ad3a7daa7233341c8c8e51035d6dcaefe", - "dist/2023-08-22/rustc-beta-x86_64-unknown-freebsd.tar.gz": "8a28760c696bda3e79306fc68c3c9a7b05b2a8ddc5008876f27029fdcbbc91dc", - "dist/2023-08-22/rustc-beta-x86_64-unknown-freebsd.tar.xz": "b21b5e26ccb28c2bf8a089a6f62abc4d10d6a4aabadf694aff8273150e6e7673", - "dist/2023-08-22/rustc-beta-x86_64-unknown-illumos.tar.gz": "d46020acb9676fc928c50d1042c2db820f27708e8dd7d708cbbe1056f787583a", - "dist/2023-08-22/rustc-beta-x86_64-unknown-illumos.tar.xz": "e92ded96d7663211d513c5dbefa2367d3c2e7ec3d37ff435884c25a2dc8761b4", - "dist/2023-08-22/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "65e7494ba34014b63d43e95662440b4d70c8ba2f43e6a22ada051f31a83c3620", - "dist/2023-08-22/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "960aef4123b24c63427c6d1bd92dda8417126c589def5213d972057d011caae6", - "dist/2023-08-22/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "4cd355a18503b2a3d081f77d9ac07e6cbc4d273b6cdabf4f9f05aef398cc39d6", - "dist/2023-08-22/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "97b5013d624a203c5906f5eaa82c3a47716e1612534698270082e47a06cc13d5", - "dist/2023-08-22/rustc-beta-x86_64-unknown-netbsd.tar.gz": "59da6428300c6b406da96142ada02d0fa9b3f1b5938c457ded9afc8d52c73046", - "dist/2023-08-22/rustc-beta-x86_64-unknown-netbsd.tar.xz": "c549da0eed22ec875603d42152134780f34acc40e4ba9ddd36f4f31e78a17dfb", - "dist/2023-08-22/rustc-nightly-aarch64-apple-darwin.tar.gz": "e80a43c2bbadff8b7976673d94228d7326a6e871cdf12d802f663b2773c6f187", - "dist/2023-08-22/rustc-nightly-aarch64-apple-darwin.tar.xz": "e90eb430d5485ea4f431952a68e6ceb9de8f6b92ccb64675059970b512ba539f", - "dist/2023-08-22/rustc-nightly-aarch64-pc-windows-msvc.tar.gz": "b21f280c54b5b0820f48767df4c611b7554c3bc5427194a1fe7e632cab7827ac", - "dist/2023-08-22/rustc-nightly-aarch64-pc-windows-msvc.tar.xz": "f2812b599f99858485d91b349a570bacab343db4bc622d8134a9993ce0da7471", - "dist/2023-08-22/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz": "059d6f34def7e471b9970713bdedf4ed3f83fc3d9b6a6f28e510b5e28d3a9413", - "dist/2023-08-22/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz": "95b36f95b1e697922b6dceeaceb74da030d436340cb4ba764101c218c3bcb786", - "dist/2023-08-22/rustc-nightly-aarch64-unknown-linux-musl.tar.gz": "ffdd8605187f7f6696586b7c7ab38300bb3d119e23726205d7f8a0a0bd102e90", - "dist/2023-08-22/rustc-nightly-aarch64-unknown-linux-musl.tar.xz": "7e1df24c13f88a49eae939930a8dceaa6dd6a23c1dbec16e3fa4f18c4bcced15", - "dist/2023-08-22/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz": "1a36c109a723388c322afa3fb7b7f64c9f38423a3894b8ebcd9aced032ba1bdb", - "dist/2023-08-22/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz": "f689a7d295e13a14e379efdf0c9a59f6ee5b8d4ee45e21ff68c684575c26e866", - "dist/2023-08-22/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz": "a60de4bbe5cb6ebb6081ba19d86f586661666cc40c74102a13b54f175930e561", - "dist/2023-08-22/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz": "b57f05ddd91bce96f61b24a93cbf9ce61bdf82d15976c44427797a0692388cc1", - "dist/2023-08-22/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "ce3ea06a26eb6345c98b7bad9943ce70e67e145ae5dc082e4bfde2c897c1aea0", - "dist/2023-08-22/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "5021ab61e2988e3f2f3a1531609621db7a2e1fc72eeae4338e3d16b40043d769", - "dist/2023-08-22/rustc-nightly-i686-pc-windows-gnu.tar.gz": "3bbf47ed743a313ea3d2def98173d323a13959e1bcfc8cd2f07a86997a0c2f51", - "dist/2023-08-22/rustc-nightly-i686-pc-windows-gnu.tar.xz": "578b6d37a9caca822102b3d484fb6bc32338d9ac72c423f4c1479835db446ae9", - "dist/2023-08-22/rustc-nightly-i686-pc-windows-msvc.tar.gz": "22798dc3d624f06a14908cf18658246045fd321566f786e6f75ce7a0d762a4c1", - "dist/2023-08-22/rustc-nightly-i686-pc-windows-msvc.tar.xz": "0c8d2fa9cb8a5cfab2c51792644c8ca436aef7bfc9d0c1950f9976fc4480f402", - "dist/2023-08-22/rustc-nightly-i686-unknown-linux-gnu.tar.gz": "52a7969782803b0f15debd0df1876e033b05e93506e1d9662a98c0aa175c043b", - "dist/2023-08-22/rustc-nightly-i686-unknown-linux-gnu.tar.xz": "69a79df0344f0279848bdbea5e8158d7a45f6d8c8966ecb5a055be064750d5a3", - "dist/2023-08-22/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz": "2fbd751601bd1cb94f064f4ff00ea1c909db059661524aa49b9e56f5ede07a52", - "dist/2023-08-22/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz": "5d51a4ac70e5b34304cd8dd05333d2d5933977e03e386bbe10cf8e43eec2e5c6", - "dist/2023-08-22/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz": "73f57e1a2d6056ae14ce6ab5ec7068241acfe59882bc2521de60d11d2dac3ee7", - "dist/2023-08-22/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz": "82faa86f7d1be9f184eec46a7c135787c37c750bb667f05bd3b872f55fbe2935", - "dist/2023-08-22/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz": "3f5e3ea359e2f7377b1d44d3cfb8516e23725e919deb5ebb32f96e8612ab2e6c", - "dist/2023-08-22/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz": "e156e85b6070a5155331eabb3c3de91279a56628b892a313561ed866b9667c93", - "dist/2023-08-22/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "83a9082d158c1093a98c75fdde9f65c729b245cf40cc06d88731e473a9ec0cba", - "dist/2023-08-22/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "61bbaf76b250a6e292d99a65a95127daa6cf0075cbdedf68033cfccd221bf8bd", - "dist/2023-08-22/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "6574e5cfac1a56cc3ec20352eebe6c6bb0825a1060df48893866909fb7005321", - "dist/2023-08-22/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "ad2240a704fca3320dccaa2bbbbe52a5b2df2556967cae4efa40334c36f66a59", - "dist/2023-08-22/rustc-nightly-s390x-unknown-linux-gnu.tar.gz": "c319fe1d20e9520b1d6c033cfd04f91286d68637caea7d2e43e335f9d9397527", - "dist/2023-08-22/rustc-nightly-s390x-unknown-linux-gnu.tar.xz": "1c52cb26303f89969190c06580206d1f5d511c91c63fccde78e515930f9da4dc", - "dist/2023-08-22/rustc-nightly-x86_64-apple-darwin.tar.gz": "db6e355efddd7aa18f3fec72d87df4b91794c8b8c07236d6d9454d5912c9994b", - "dist/2023-08-22/rustc-nightly-x86_64-apple-darwin.tar.xz": "afbfca7d7c7f8a94575269098f6166729bfb441b657ea77f7de6621e0a9a3f87", - "dist/2023-08-22/rustc-nightly-x86_64-pc-windows-gnu.tar.gz": "7bfcbbbfe4adab954e9c70b8ea6bfb9d52116782dcdeb9b5be147430c4f242e0", - "dist/2023-08-22/rustc-nightly-x86_64-pc-windows-gnu.tar.xz": "05e7e901fa944075ea20d65d81f80986c51699c2ac5c5a2cfa2e5a07c16f4b0d", - "dist/2023-08-22/rustc-nightly-x86_64-pc-windows-msvc.tar.gz": "74d07b4289dd2f382c7ef5881ed24a1f99c44b9805857d15a8d45d0c7fea623e", - "dist/2023-08-22/rustc-nightly-x86_64-pc-windows-msvc.tar.xz": "25bb5590a8107f6525c4987291f8f46360ffdf67dd47f7087a2c9e441e20296f", - "dist/2023-08-22/rustc-nightly-x86_64-unknown-freebsd.tar.gz": "727fcc6ee093e8b105560b6f9644451aa5fb5f88e12e883a270a094ee47aa3bf", - "dist/2023-08-22/rustc-nightly-x86_64-unknown-freebsd.tar.xz": "c33d57fc3783bead4c54352ccfa4b4f129e34e16970efdd872b562fe99e1652d", - "dist/2023-08-22/rustc-nightly-x86_64-unknown-illumos.tar.gz": "c1f4fd00eea1e5fcd64e0eecbf7daec3a39d72822b4792c12c3885bb7d34048d", - "dist/2023-08-22/rustc-nightly-x86_64-unknown-illumos.tar.xz": "ba3783813d65a4be685c3720c865365f03b9124938e02be790c438d212fa1bb1", - "dist/2023-08-22/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz": "7a0365317617af7b18f535f39e2a8da23cd8f1b7ff95be9af1de9b6d4ae461de", - "dist/2023-08-22/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "bdd970bee618fc6299249ec162ab7e38efdf52c77cd431ad9268f327a6f0905d", - "dist/2023-08-22/rustc-nightly-x86_64-unknown-linux-musl.tar.gz": "43f5736c02efbc0170d23124976546b3fc03b2a30582c3685cb53f7417359692", - "dist/2023-08-22/rustc-nightly-x86_64-unknown-linux-musl.tar.xz": "3abf2518323294fcc0decc9e3f01bf610116b8f42b07fa9d34769bd438ae17f9", - "dist/2023-08-22/rustc-nightly-x86_64-unknown-netbsd.tar.gz": "1dc5af741b22db8bf16ef7eb05821ef0d5b3e518244867a2bba484a773a03b9e", - "dist/2023-08-22/rustc-nightly-x86_64-unknown-netbsd.tar.xz": "4c2e5268a6a4537c67795c89c45a414e9b001068017aff0b6ea73c1b2e9d95c2", - "dist/2023-08-22/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "606431eea9341f6ee2079ef919d34e583678f8f1e0bcd66fa73eea9175996a77", - "dist/2023-08-22/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "b122cc0367be4b5433eba7e1b2ca919ec265cd31c5b1766e4853b947d16268b5", - "dist/2023-08-22/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "094456d974c3bff34b4ea47f159a2e12dc41c0c88ab710debfb63ecba102b6f1", - "dist/2023-08-22/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "e777f86c75261bfcc3dcb2c7e91ad4052a7e6263b59dd78d6e5a50a43cb9de1b", - "dist/2023-08-22/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "82b9bd94ef7065587471716fd7848bdfbe0d0938df7832b035d78274e51598fc", - "dist/2023-08-22/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "d8453e40ca7819830e9ef8bb3c3086a4708479cd01aa3434fa878bbdb0e21cc2", - "dist/2023-08-22/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "17e913c782aef22a021c75c204f04d290f6abfc76ac3c2fc899bf3ba2b96e8e5", - "dist/2023-08-22/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "97b145924a76dc1f0e6d2c18c65725d0bd92308ee21d779ff1d1c3a857221ad6", - "dist/2023-08-22/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "aa36dea771d819ba1f4f2997fb8e38fc02d57da7417bba9354e499c15ab56c6b", - "dist/2023-08-22/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "c5b3ab26ec79e479de1bc93ab60e48c95e6a24931bdaf8c2e9a6508fb8d8253f", - "dist/2023-08-22/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "2639378c9e51ec50ddb739bc18d12ed43e98a5dff1a1e5cfd154c0b91f233000", - "dist/2023-08-22/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "c189e78bae3474c17f693401c9f7e13f064370ecf709e69b62a140e94c772e82", - "dist/2023-08-22/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "b7e175569f174d7422756bc3c312a1dcde78b8563cc96330772b2b7ca6458685", - "dist/2023-08-22/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "0fad29a56dea92b2083d46e9a93d186f32d162461da897e2aca1b94cf8ad259a", - "dist/2023-08-22/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "35ba679d27b08bdbb381a7517b189743e1aaaccc0f0ad33fa6397d53005f1bd6", - "dist/2023-08-22/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "37cfd4697506172d2826b1a047cd1d78e24ad32e1334fd89602a6b2dd45fecc3", - "dist/2023-08-22/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "e6dbb37669c307e235b610aa292691e2f767bafc7c90dca5f9c3db70a782914f", - "dist/2023-08-22/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "1df368db6dcf9bc06ef68e5c56e1961f6fef57c07b2edbdb537c5eeccc315d5b", - "dist/2023-08-22/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "bd3694c1b40d86c5729bdafa5516a827da2d741a04a3f91f955f2d1165177324", - "dist/2023-08-22/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "0ffa91610757b4c8fce43cef6d76b0f47a442dea14dc893581134e8a0237b32b", - "dist/2023-08-22/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz": "92ec1025ed12fabd541530124b08498abf54ad14c22a11a6cd9be54fa330b0f7", - "dist/2023-08-22/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz": "850ab1756cf50b9e56dab7b2dbbbdd0dab9146fa792ce3bd59af0ec5a0c1a4fd", - "dist/2023-08-22/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "02cd3b78627002f26007ece8e64808a58c80bd4362333c1150b4901c73ae6b8c", - "dist/2023-08-22/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "f453e12fad664f6a3c76de94e34ecd4a668cc26bdec982079dc8c57c9fa85c7f", - "dist/2023-08-22/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "92d7336a7e4a6a9e06f72e72b8402af0fe60bc6da7616bcee11e810a5217ec8a", - "dist/2023-08-22/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "08a96d8600357882f7b278c7e65c8be95ec153bd7059c14847b47abb4e27a28e", - "dist/2023-08-22/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "7d80dfaaa65c1237813ca8cc8c52a878d5e4dfb99b6e5051cd679bd31ce3a4ae", - "dist/2023-08-22/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "a76b23cbad7fd5838a6297b9234a5a09cf6adf0cb377910180d30caa6de2696e", - "dist/2023-08-22/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "4f74e990e6d6e2eb80c503794e55f80e554dd2b6bfecd902ccdd19841b8e83d4", - "dist/2023-08-22/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "7323dc37bb3a0ec5979e0e0818aef876010422a539971e7fbbbb39e66bbe5a70", - "dist/2023-08-22/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "cc369508a03517983bcab4f17e391d4074b002d9f3b5ec8729375b345df6cf86", - "dist/2023-08-22/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "465d88c1ca8c5e36a579d48334c60f5ce226eb4c5a851849fe76a7d8ad803154", - "dist/2023-08-22/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "d2cb215423c824355d7d450b8d555c3f7390b08911fbf5114474869d9d8d2fb8", - "dist/2023-08-22/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "d5a4e117f8d3f1a7a88dbd1e1e71fe352fafce10770d6dc1f2644eef591bfad5", - "dist/2023-08-22/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "6601080db240890b1a9b7a2af54c576b2ab112b15b504a3475fa77b0b214b309", - "dist/2023-08-22/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "a40ed6b0fcb5bc909dcbdc93b65024f155792df980a48757b71ae391dbb427cc", - "dist/2023-08-22/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "64c4a913fd398fb49823d7687932c9defc3e4d0312967a21c90e57b5a6e2ea66", - "dist/2023-08-22/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "75e814a65ccd1b3721ff6300b83aebfcd8f402f18e02df230586604cc56efb10", - "dist/2023-08-22/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "186928533dc8dc7874c56bb0ce95930d7cd76c9838a9203509c01c3f0d1e88d7", - "dist/2023-08-22/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "4bae607aa830e898d77e20397377cad51108843480a76f6d8f076bdc27a69d7e", - "dist/2023-08-22/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "1610cd254b57537c592f5d9c8d5522d03a25405db4862c18759001ced85169d6", - "dist/2023-08-22/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "2cd850cadef23f7061e88e3aed20cdbcd772badb11792f34110facb681c9846a", - "dist/2023-08-22/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "db5b9f91e2350d337c19c07c4f30419ef1a222cb7f9ad1f95c851ad2a78993fc", - "dist/2023-08-22/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "b7abfba5b3c7c5b33bd64e5caddab8a62fc7d1298e913323a3712a2af80b01da", - "dist/2023-08-22/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "bcaa9389f053f133c1bbf96a50035de0d2c1e4132a9f8deb5edf83da9da75616", - "dist/2023-08-22/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "1e2cec2188e9dcbcb23b81a9a0f22eb70143a207438853b702d5d2d90786a92a", - "dist/2023-08-22/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "afd7e619f99ebdc2095f3a0db4a55684e1919c2cf145ff3d1e18169e6e868742", - "dist/2023-08-22/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "ee05ae0326941d38704abeb44c868a326966f6dbbc3fcc79585a8ca1f84a4b21" + "dist/2023-10-04/cargo-beta-aarch64-apple-darwin.tar.gz": "a684803e2f7a6c5741b89d3cc471544978ca60256e1d9621978eb190c83e6e2a", + "dist/2023-10-04/cargo-beta-aarch64-apple-darwin.tar.xz": "f6b618c037bf5eb84e7e775fb646f1fd37fc175c321faab0c2a5b39eb4553729", + "dist/2023-10-04/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "47178d02b0d92eb0a1ce511a08ced08c5bf21571d2e560d64d7d00f9d7dc8d76", + "dist/2023-10-04/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "4580c08291405a349c384e34f5ccc728956ff169b7c86c528dbb1e4258a08a77", + "dist/2023-10-04/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "31ca3f2a4d11cdae30925f22154d833e1975b622dbc9bfeb73888fa8666d07f0", + "dist/2023-10-04/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "525dc3440d5bc10c29476e5dcf26c82887459b37fa4adb6f0c45d6f955a9b8e0", + "dist/2023-10-04/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "fac19194eb9261b0df166bccc757d77b78f12c015faf4fd02440978a835ac5b4", + "dist/2023-10-04/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "97e9e2970306e3148307f0a90720764bc74a9e161fe9efe09fb3919a6624e22f", + "dist/2023-10-04/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "805d20b6d572cf1fcfa9f036c9af7133284edf5b67c9ac2e635aaf4eae2d07a5", + "dist/2023-10-04/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "b482d11edee594d984c4da214a0d6dd3dd5538eabe6c6a04b8b36ad4d6918b9d", + "dist/2023-10-04/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "f052ee2d6b5f09d63cc43acbc3e13f044d39bc8cd411286b1fd0318802689e3f", + "dist/2023-10-04/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "3a428c893b46f7ef5e893438b48225d633190e2c99e475429a08556e16ed993e", + "dist/2023-10-04/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "cfdf1f990b6bdd43ad0e0b898065637ab422c4ca4489b78f0ed481684bd4c9a4", + "dist/2023-10-04/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "93239e235a34898e959d891f8d70a75e012f35af62f5576d1b2173fce8979d30", + "dist/2023-10-04/cargo-beta-i686-pc-windows-gnu.tar.gz": "a27be9e3c589d8d92a9b4d95fc6684d4f05951f985485cc516359ea600cb9b4d", + "dist/2023-10-04/cargo-beta-i686-pc-windows-gnu.tar.xz": "9339b0ee5395f75ee8ebfeaeb95582e5922e0f3fc268f59d47c2cc110844f269", + "dist/2023-10-04/cargo-beta-i686-pc-windows-msvc.tar.gz": "6bf3edf4612263ed698bb920e946065e964cd4f7fa6e864b029b8593997b1a0e", + "dist/2023-10-04/cargo-beta-i686-pc-windows-msvc.tar.xz": "46cd39b56d8a6d4724a99574907ddb81a6d170ceccca35a9201b8a61bd3e8190", + "dist/2023-10-04/cargo-beta-i686-unknown-linux-gnu.tar.gz": "f99efe464f62d1c11c035c8ee0fe649380522c8fce7273218ff8a818bbc1628d", + "dist/2023-10-04/cargo-beta-i686-unknown-linux-gnu.tar.xz": "32f68b074e6b9ca7bd216d8d924d0b796c3a6ba81b90d8a0ecbd1904a61867c2", + "dist/2023-10-04/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz": "d1b0179d8c8ab0541bfaf7830bafc0d384616785081c0149ebb80d009860261c", + "dist/2023-10-04/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz": "1265182fc1962018c2754359acbc7b7d07860bdd26eb388c8e332786fbbd678a", + "dist/2023-10-04/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "500f736aeea0a5648bd4703b772d9d9077272daf08c334c281d71f9c19150e1d", + "dist/2023-10-04/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "97e40806dfd8921b7c4347d2d6ebadb66dd315c3d30c0ba3e0b30fcc3de9f1d4", + "dist/2023-10-04/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "1bf735bbae45eb55f4156504299d41c169d3d923ca8615e333e181a0e4b744c4", + "dist/2023-10-04/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "2ab0afd75f20e290fac1063ac0ac8cec98f847918360d95326350671d3b0e05d", + "dist/2023-10-04/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "9092667b450f758c39420530a131e87bcf6c911cb3f2b0177ec6fa4dfb7e58fe", + "dist/2023-10-04/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "50417b4be7631069b8059df56f0834fc65951c5057124b681b7a97a00ff774b6", + "dist/2023-10-04/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "cfb8e229f98f43a612bbf0d6d29f42cbfe2ccae4e3ef03fbb0bd7ea4ced10154", + "dist/2023-10-04/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "32059ff422870f3d45f419f7a59de696fff9474aac1bc4ae20a527079b95cf86", + "dist/2023-10-04/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "d14942f7492df24a577464a2929c2251c1493a70d822b7c38b500e559fce18e8", + "dist/2023-10-04/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "f7688d17e33d49f6fe26a0e7d0d24dfa6fa99e3b1703f6b99dddca46f1080c89", + "dist/2023-10-04/cargo-beta-x86_64-apple-darwin.tar.gz": "9da00b7617cf14e3f5f32c6cfc8e0f4b4197747a6864a962dbaa8725279b52a4", + "dist/2023-10-04/cargo-beta-x86_64-apple-darwin.tar.xz": "a3735ff5fd823461eb411d11b1e675fa890907c859e353ec9c239fc85bc5df1e", + "dist/2023-10-04/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "9f98eb4b034acf6ee9315a7067a62668883d25fd95b306c3083feeb56b907ac5", + "dist/2023-10-04/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "93d0653eae1839dda931ba4e26afb32527a59ca3b4502778135cc5d9608bfeb6", + "dist/2023-10-04/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "23f8e3f8abb551e7c71b391b63d5a9514f49e03d89c0bf4877c94bfd9f1f3754", + "dist/2023-10-04/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "1e8c3996be4a94b54df4f1d5d5f514f254963ed479e40885cc943970d9c31ebb", + "dist/2023-10-04/cargo-beta-x86_64-unknown-freebsd.tar.gz": "3761bb7b4fb64fa4791d09b88fac9da690a422d611935f1627ea96dd43b1d229", + "dist/2023-10-04/cargo-beta-x86_64-unknown-freebsd.tar.xz": "d0a2bac9df9073f766ca0ac2a16b17b6ebf870913ca962c063e6cc9967a32ab8", + "dist/2023-10-04/cargo-beta-x86_64-unknown-illumos.tar.gz": "71d42631ac9867750c5ef86061b2ce6ac1fa56dc24eb07fe5fb13a97e2acffa1", + "dist/2023-10-04/cargo-beta-x86_64-unknown-illumos.tar.xz": "72002ff2f148fdd864fbd4a82ec4fe7fb33c6acf7a7186e30ee4a74759f593f9", + "dist/2023-10-04/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "774be8387ae3849a82447cc20b2bd1daf4d42c7a80faaf5090e153f78d96de9f", + "dist/2023-10-04/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "6f6794bf506362614b97d96f10d6d5171676205beedb655636d82e8344a47011", + "dist/2023-10-04/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "c5ef0aa9f422014bf4d1873f09c77818d2de51fd7d6c030b617cd106402a0f21", + "dist/2023-10-04/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "82ece6a6f7eff45d842ba1cd28e3e86ddac0c49fedca3039dac00d01d99a26e7", + "dist/2023-10-04/cargo-beta-x86_64-unknown-netbsd.tar.gz": "42627d918e4dbb692ef45ff162d7eb39e9126dc30f29cb96b787f0029d11e1d2", + "dist/2023-10-04/cargo-beta-x86_64-unknown-netbsd.tar.xz": "de92a4f9f58e728c63d47a39973c2ef396a073a6fa26bdadf0e833cee9722980", + "dist/2023-10-04/rust-std-beta-aarch64-apple-darwin.tar.gz": "150828b9c7e49d7555eaf989dd6fe84b2b30d06145f48b635ad04e893b537311", + "dist/2023-10-04/rust-std-beta-aarch64-apple-darwin.tar.xz": "c1006b9c0c7d0bf104146b52c92f004811988cc8b73474ef690208e78645a348", + "dist/2023-10-04/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "df8cd652323cdf204683789b902f440e8aa614b9950e096837bc3b6a32a58e80", + "dist/2023-10-04/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "f9bdde6063001b69002ad21777eb52b37ce78ea3ce04131cf81b8f40b0e16c84", + "dist/2023-10-04/rust-std-beta-aarch64-apple-ios.tar.gz": "db0362e805a012249fae465b205970035181a43a19a58d87dd475ebdbb986dc2", + "dist/2023-10-04/rust-std-beta-aarch64-apple-ios.tar.xz": "72fd22f528bb211b0d5ac807f590fac72b1698f7d118e1b3507e6994b3896cb0", + "dist/2023-10-04/rust-std-beta-aarch64-linux-android.tar.gz": "f691fd6cf51e9aad3a11c2b613646b06308ef9558fe04f274458b68a742d6efe", + "dist/2023-10-04/rust-std-beta-aarch64-linux-android.tar.xz": "65fc6a17622bcf0039b34699537f233d193b03514c039258395dff2de8ca5197", + "dist/2023-10-04/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "a99e89663dc6ade963dc13b468fc310ad7b8a17e4d417bc210a39feb6413422c", + "dist/2023-10-04/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "120579d0abbd68b692271290ae926f6677f97930ade6861ae71be0033db5437b", + "dist/2023-10-04/rust-std-beta-aarch64-unknown-fuchsia.tar.gz": "7663940abb0a080daac14573199e81b3000d80a27dcfd8f3d8c6d295efa1216a", + "dist/2023-10-04/rust-std-beta-aarch64-unknown-fuchsia.tar.xz": "59d7eef17b6cc40cf6af729abf173ecc43c03bf38516bf59fe27321db384972d", + "dist/2023-10-04/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "69647628d78604fdbdb830d23f661d31f997d77635ea0c123d1ca0017b18460d", + "dist/2023-10-04/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "93e15186a1ddd33f3cd7737ff5da28bccfd5644c9a579691611ee2e1308cdd4d", + "dist/2023-10-04/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "b8ac97fef649854f78a9290054728f40b90e5ce55dcde7cdd128e2a5a09224f0", + "dist/2023-10-04/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "4b0d7b2bf742425ddf024d7103b8651f662993038f66b9db915713ba8f039540", + "dist/2023-10-04/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "37847cacdcf142fc557bafcfd8b3ed3c9c5532757bf6c06e6493d21356e18f04", + "dist/2023-10-04/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "c64925fcbd6b7f97926fac45d789e70734d3895c46cc958c190815f8cd8f4989", + "dist/2023-10-04/rust-std-beta-aarch64-unknown-none.tar.gz": "a566b9c1784c919317f33678f889a15107fd31a403d50f6cf42036ff14ae507f", + "dist/2023-10-04/rust-std-beta-aarch64-unknown-none.tar.xz": "a1267921d98e56f36937e72a1dcd60624f94de6e9948fd86715f83fb152ff52b", + "dist/2023-10-04/rust-std-beta-aarch64-unknown-uefi.tar.gz": "0fd6a5925d5a69ae7c7f277ab503ddeeef9168ea815492b21a77a07d8e49142e", + "dist/2023-10-04/rust-std-beta-aarch64-unknown-uefi.tar.xz": "8477f0f15e1fd594b05e918f1940ee56a9458353eaac83f355d935ff2971df20", + "dist/2023-10-04/rust-std-beta-arm-linux-androideabi.tar.gz": "63ea0d1311b4c7a10a185dad0f13e53cac6f7de0047b96e6f23f872f84243339", + "dist/2023-10-04/rust-std-beta-arm-linux-androideabi.tar.xz": "9b35c8013417cdd08480640c609c3e0384814944b81e6f85f8741f53a768c944", + "dist/2023-10-04/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "290589b2438e6ef92366d86916d33f19504dbbe7adeb3e8b12786e524080fee2", + "dist/2023-10-04/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "ce39b799f490f0f7c8d166177d6a4174641872d2fbbd80d7d94dadfc1603b77e", + "dist/2023-10-04/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "5def5470a2c06adb70ab6373b35abdb2404987a41ea2b324d8852849540ed503", + "dist/2023-10-04/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "dfa329c8da739dab40cd111d9399ae2e38e7db8f8e07fda64117fa146b3d071c", + "dist/2023-10-04/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "94cbc1d6984b6018c373f5e7fd250f0bd2de4b4767f7f0c61a70c660576faf12", + "dist/2023-10-04/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "ec393c418b2ac3d2c97814b712648a0fd318dcdec381b4a49409dbb59079cb33", + "dist/2023-10-04/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "4765d35d61d4bb0a8d7dd9f2e6e1b17a9c27ac27fe24f111a42aca6b2dfe2fcf", + "dist/2023-10-04/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "07ee14b28ceec5e76f411b607d68cccb3bac17ed708e180081837f2e05c7057e", + "dist/2023-10-04/rust-std-beta-armebv7r-none-eabi.tar.gz": "f5f35b007304d6d25a189f000a89a64cebad035e3ab7d2f1d2225c7063575db8", + "dist/2023-10-04/rust-std-beta-armebv7r-none-eabi.tar.xz": "68ede435cb805a0e7d9c3bf172fda8c20486dcb2ab655cabc5ecfa25f8564955", + "dist/2023-10-04/rust-std-beta-armebv7r-none-eabihf.tar.gz": "53f1586ef3640a35e36d2b3b4caf62e444d43da64d744d99323f9b238fd0981d", + "dist/2023-10-04/rust-std-beta-armebv7r-none-eabihf.tar.xz": "404517420148caad58da5c5903d6b64b00aaef728dc9146f1c85d3675b2f7944", + "dist/2023-10-04/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "333a58268238a43864b65f51d5731c76e43f56f6f7c556057307d36d1c47bfd2", + "dist/2023-10-04/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "fe4ac5283e9025f7ec919d324592a3b88cf8ed02bfb6bd077d46a452af1fd723", + "dist/2023-10-04/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "ce2edf3faf28d92d2ecace77207e0a5b68aacbaf0f202e79503fabf913472f17", + "dist/2023-10-04/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "12df2bab8ce8301e3dc6eca8693b19eafe31894c285c013bc4445596cc93e49a", + "dist/2023-10-04/rust-std-beta-armv7-linux-androideabi.tar.gz": "f15088dd162f584123f07d58303e5aef3ed12a479ad6e351ad9c676c9d7953e1", + "dist/2023-10-04/rust-std-beta-armv7-linux-androideabi.tar.xz": "8ac08cc08e29b8aa4425889b5ed7f309ab98a3af51c66f2a40c5a5c62efbef97", + "dist/2023-10-04/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "d4b8fbf3b3d96e893145aa2868f6a470ad70bd946793fc49c435eb6fc921a00e", + "dist/2023-10-04/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "153c726bc061d8cd01f5c6c1786d12d04e699505a927ad5ee0e385ee1ea9ded7", + "dist/2023-10-04/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "4dfe33527e1c54cd0a9ff653e6c81376a01119bd894f5db47fb7c716464fc876", + "dist/2023-10-04/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "42081a3129ffd33ff6d9bbc10a10f214f909b4700255fa57decf82161e095d85", + "dist/2023-10-04/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "c1693a1887633f4c0baef1bb9910c502df5a70f2deaf00ead2a40d7ad210216a", + "dist/2023-10-04/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "a1f0068e719d231a6c1ec12055b883773584d9fba609f01fdc32a0dc856bd516", + "dist/2023-10-04/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "7568f5a3e65a649f13481afe384cccf54789c99fe74e62365b4922e649a36f2a", + "dist/2023-10-04/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "ad2989860396bc23ca4337887cd9865fa8a4e930d648df50f193330011f2e65e", + "dist/2023-10-04/rust-std-beta-armv7a-none-eabi.tar.gz": "0ed22040479e23cbf3e82087636c6ea30d75139af30db9e95b8ea7847be1184a", + "dist/2023-10-04/rust-std-beta-armv7a-none-eabi.tar.xz": "d182765ec6d63e0fbf2c6af1ecf57c475dda93c03676e8f3958da74aa47fa168", + "dist/2023-10-04/rust-std-beta-armv7r-none-eabi.tar.gz": "cdc524d00fbafccc363b456c32cc6410cefe98d9c1d37c1e5a22db986b600e7d", + "dist/2023-10-04/rust-std-beta-armv7r-none-eabi.tar.xz": "8815ae220f5bf7bced09274a1e17dd0f95e81ef5cbe1938b738298835c47001b", + "dist/2023-10-04/rust-std-beta-armv7r-none-eabihf.tar.gz": "c641416a3d67ca2a9b797d4800e5ac12a688a7af9daaeae10465c13d0f8cdeba", + "dist/2023-10-04/rust-std-beta-armv7r-none-eabihf.tar.xz": "3ce3dde8809d41f51534d9e8fd86f1c5f34b5450a2bdfffdc2d72e9e54af6ef0", + "dist/2023-10-04/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "a3700f29bbf1f7508a438ef7ecf4cfa25acef21bc9205285736f34840932388d", + "dist/2023-10-04/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "7a6927e77caad52d111366712697b3a7e6b3fa904e0a50eb4628b70d5a92717b", + "dist/2023-10-04/rust-std-beta-i586-pc-windows-msvc.tar.gz": "97c5d4837a4e4f019293c4dce265f6d09ddf3abdc7d7ab7f08ce0b62e0278b2c", + "dist/2023-10-04/rust-std-beta-i586-pc-windows-msvc.tar.xz": "f566a6b8083d3a1e0f5cff28a5131af4bce33a1519d7a7e6fb14d7ae349e3150", + "dist/2023-10-04/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "7a344a573529887631387d8e2f3e007653216f959a8f7c543e2c2cfb52673615", + "dist/2023-10-04/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "d6543b8eb696596fd35616fdc839af08f9a386412e7a8344ed92e08d840613cf", + "dist/2023-10-04/rust-std-beta-i586-unknown-linux-musl.tar.gz": "e8790ee297ef2661d8cead7875d3fa511d7ec4be5aac858562ddc107257648d7", + "dist/2023-10-04/rust-std-beta-i586-unknown-linux-musl.tar.xz": "8998fc7c0d7ecb5a06fae1799f2aa044cf3680546461ec9033115476f3acd2db", + "dist/2023-10-04/rust-std-beta-i686-linux-android.tar.gz": "f918380c6e01128fb16a047d6adc7a8fd3cb3c14bd18d25690ebc69c9a8f0f22", + "dist/2023-10-04/rust-std-beta-i686-linux-android.tar.xz": "cafedd439975af0f45894e111b89b03adee21136dd43558cb049608914b0a8fb", + "dist/2023-10-04/rust-std-beta-i686-pc-windows-gnu.tar.gz": "442d40afabdd05fbbe8b8570133dc119da6c6f8396a1cd6879a21b58c570dbbd", + "dist/2023-10-04/rust-std-beta-i686-pc-windows-gnu.tar.xz": "31c86d09c30d670a4915412d3fed90e0bc640f6b359ddb88ecc4c75f50b68b41", + "dist/2023-10-04/rust-std-beta-i686-pc-windows-msvc.tar.gz": "e0b23dd8a1a4805a1d13275e29edef5b5cfd34b271029262b943eda877c074c5", + "dist/2023-10-04/rust-std-beta-i686-pc-windows-msvc.tar.xz": "a954096bc423910cda8816093bcff11a3996d55239c19c3f9285f584057fdcde", + "dist/2023-10-04/rust-std-beta-i686-unknown-freebsd.tar.gz": "84c060e799148378223c56742d9bfef40b15252204f91bd49677083f48fff722", + "dist/2023-10-04/rust-std-beta-i686-unknown-freebsd.tar.xz": "faa471809786a5cef68807de3da9c0c9e0943b7f92014e232ab6693e1b081a9f", + "dist/2023-10-04/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "43ce123cd3f014b33444c853dc91a9921ba9af0b8d52e65c56386b7e300fa595", + "dist/2023-10-04/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "4792bc927d4dc0af996a47c4e82ab37244d0d28052b56abef6dfda60d8e58ac4", + "dist/2023-10-04/rust-std-beta-i686-unknown-linux-musl.tar.gz": "e609884e147deaa8265cd3f9150384d45d43689ba68cfe6e2ca003773d4f31f3", + "dist/2023-10-04/rust-std-beta-i686-unknown-linux-musl.tar.xz": "c27b005cc23453bc2ec9401515fc792d589619119f8f1006d8c9444f1592c1a7", + "dist/2023-10-04/rust-std-beta-i686-unknown-uefi.tar.gz": "e4fb77aefbc3ae63b81019eacfd35b6cee6f801ac2ff397a598d2ddaf84989dc", + "dist/2023-10-04/rust-std-beta-i686-unknown-uefi.tar.xz": "890d607b35053df912d0f3925f8c7af17ef3a66c267f31eadb8aada9b4491b3d", + "dist/2023-10-04/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz": "c07d08b9a17aebf127d01715259f5be3fc8e67d1e4a114a5f7eb9489c36ec529", + "dist/2023-10-04/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz": "27bffe29093dc3ad55cce741607a354035c8a2d40f8480b131c9608fbd9a86d9", + "dist/2023-10-04/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz": "ce7ebda42e41ad68924f2194c1dbb17f2487d2d6426669835e8dca3dc3f0f623", + "dist/2023-10-04/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz": "3564c11a5540b25f6c3ef24f47e64bf88d76aefacab01e0b28b0a48e4c0e9d73", + "dist/2023-10-04/rust-std-beta-loongarch64-unknown-none.tar.gz": "2aa6dfa17a120b2ef4e7899ed32a04e472725404b205739c12bff1829c05c7a9", + "dist/2023-10-04/rust-std-beta-loongarch64-unknown-none.tar.xz": "37cd947a8cc912e9c3fe07fd4b3ed310255cb45321ac48753cb8cbeee8b56fd4", + "dist/2023-10-04/rust-std-beta-mips-unknown-linux-musl.tar.gz": "5dc9a8b4a421a1be0fd4aff1256d98d76aa13ec38b10b0ba7fbb7ae7d0633354", + "dist/2023-10-04/rust-std-beta-mips-unknown-linux-musl.tar.xz": "c4762f98a836bd93c68fbac17c99e443bd05cae9897f3d1d3f6f39388659bfff", + "dist/2023-10-04/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "b1cb089447954c3a9d5244e2f08367db5fbd569eb986dc437cfa70f0dc5a9a6b", + "dist/2023-10-04/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "9d245bcfd07a430725c274504f5c8f80ea71027ca63f4442cdf4e950bb49683a", + "dist/2023-10-04/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "4bc42a59bb123188ea2cf143b169b5c5c25b1c10e6b9aaaa00fd5292e2cb4e1c", + "dist/2023-10-04/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "d58b61471e5bf9279b31b6dd15970efac0a7efef95478d46504bb79643641edf", + "dist/2023-10-04/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "d7982143a43ae7d2de013747558b808cdf5acf146eaadd32ee1f5baf3354b7dd", + "dist/2023-10-04/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "e48fd58c266991b24012eccf24212bcaa9f2ca76b93cae50b3b48efdb1c3b715", + "dist/2023-10-04/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "918d45e2212b240c975986d6db96b92bba1f51b2d66ec265c3b87dfd338bc548", + "dist/2023-10-04/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "311aed63bdb7316627a362a9606cd5ca680c4f77bbb9abc74998fea09e2b057b", + "dist/2023-10-04/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "6787ea0c089880a7fdbddb8565847597c4a25a19cc54fa7186e0468a377ee75e", + "dist/2023-10-04/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "20b812085cbf0b92cb0b0ac16cf6f3ef21a2b8d43e4185f4170850138361c944", + "dist/2023-10-04/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "41067f3710f1727c5e2410731f15cc72e15633921bc13295bb28096aae9feaae", + "dist/2023-10-04/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "8e771dcb137daf00ed15bf4d33418bc238da1f7352fc2ba3dee941e3af3635a2", + "dist/2023-10-04/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "bd69748bc81f972fb41d1ac5816cab38d810619692e9b2b762bdc346f2c84771", + "dist/2023-10-04/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "90d79aa923e15aee4e9aaed6721db1288712f473263cff3780dc66d7d7cf7b57", + "dist/2023-10-04/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "a1396acdfd52c857969db1ed6dbb3c29cf76f9744e39ee86eda25f7c3b6fb140", + "dist/2023-10-04/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "93fd04c8c70b30dae02c690c1326edf00090b5f22332dcecbfb0130b4288e795", + "dist/2023-10-04/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "a0592ab2d956ed79049548010c21d1043306502df200873ee0ab82185699da8d", + "dist/2023-10-04/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "a304cff2944d1c317940851980a55033f1918c8d4dd52636bc20fb93c0131927", + "dist/2023-10-04/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "46adfdd25bdcd3c8a9fd60cba9cb1c699b49a5c77b4e4d5aa1020c0985f7c6b2", + "dist/2023-10-04/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "c78bf8bc612d14ae2d619aeeba6ce10031113793bdce9ee2554d17fea74cf5ca", + "dist/2023-10-04/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "018d34e11a065100d45b7c529a3de5ddc5912affb74e4978bede24b6995bd394", + "dist/2023-10-04/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "d3d9062f44c575705ebe2a6d1f176a79fb6f0baf7095cd620184cfe69ff57ab7", + "dist/2023-10-04/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "a3edcf33b7241e9e06466c24c6325a1c7b7f2c0ef2107042827154480532ea05", + "dist/2023-10-04/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "d34eabbd010d9c30fb5c07d3bc854d13d629270a679d033a10d5359a3cf14423", + "dist/2023-10-04/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "1efd3a8cc38d94fec1b2f69fc286a5eb25b50eddf8bf2ded9d236456dc8af4f0", + "dist/2023-10-04/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "df58f0a2d80a6580c1f39d8dc59e785d624730a265c107dc35b264f20a6cbb75", + "dist/2023-10-04/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "d139f332dd3a40dae7689a673fc66997f318d690eb0a2b0704344fc2f5c3ed2a", + "dist/2023-10-04/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "fd46fd9ffd848d00ebf11002c40698b443c9ee9e056d342c8ebb28ce9f397d08", + "dist/2023-10-04/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "fd681ec7011de04cf347465594a65fef58882f298e527f22461fb9afc05d353e", + "dist/2023-10-04/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "5400c302976234fb4b952b7fa159ab2ec5fd19c8c7657b41dd7bcf925b59e769", + "dist/2023-10-04/rust-std-beta-sparcv9-sun-solaris.tar.gz": "93208b2ba15339c0d95434bb04e37ec98fc8a13ef9f92cf92fe0ea55b69e15fa", + "dist/2023-10-04/rust-std-beta-sparcv9-sun-solaris.tar.xz": "3a96871a781637bd885b374a30460196eb9cd064d31b269909c155537085e4e2", + "dist/2023-10-04/rust-std-beta-thumbv6m-none-eabi.tar.gz": "2367449493235e192851f8f7f891be6a4c6fa7663fceb04fa6d160380190159f", + "dist/2023-10-04/rust-std-beta-thumbv6m-none-eabi.tar.xz": "71592f9e4cb8f25ba7034fb797b1fb1cdd3cb9d44d12a8dcc0d450e125e89cd0", + "dist/2023-10-04/rust-std-beta-thumbv7em-none-eabi.tar.gz": "53bc65c17358c3645003068b0d9f231e543f7229e6c389b78aa95d32ded4eecc", + "dist/2023-10-04/rust-std-beta-thumbv7em-none-eabi.tar.xz": "0325e27cdfa9d1adcdf6be09515c3b71f8700a06c87579d314a56dd92ecdd82b", + "dist/2023-10-04/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "0810093364e500892abfc716e9ea44c51bb4f3e0d554fb6a5ccc5aa51bbe003a", + "dist/2023-10-04/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "21d2b3ec401dece48893c011e791c04f1233c9f579762ce6ed8ec665aa1747d2", + "dist/2023-10-04/rust-std-beta-thumbv7m-none-eabi.tar.gz": "76912f5ccc8582048be7a8e4800e2068fc395c85a28ba99f7ffd103f4a8cf98e", + "dist/2023-10-04/rust-std-beta-thumbv7m-none-eabi.tar.xz": "85282a5e52b22501b1aa805da1bb41805591d2a9c4aaabf62a2fc2096469dac2", + "dist/2023-10-04/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "0e0ec736578012bb05f6f4c3a2156af0255097d74a31586390d4ba9a64d73021", + "dist/2023-10-04/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "fbf578e9ed1903a14f10231d1d149b9efe701f9fb7ffe96231dfebab6e2de123", + "dist/2023-10-04/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "8f25cce159bc95b8e4678840fc9c0c4d0f6be50c70c54afc8324756e92da0e03", + "dist/2023-10-04/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "72226d027daef70c7b6dc7cacf2cb118e99cf4fa5c9cb7affe2214ae79eff6ac", + "dist/2023-10-04/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "5101557cafc2ae9c7acd05f62259618835bb852802863a268784bcc091fca31d", + "dist/2023-10-04/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "f68fd847bea42413ed67d9160926e25174e9e45037d7bca016d86bcceb40c779", + "dist/2023-10-04/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "abcd1dd5293ff16d4ccebfccbd2ef9954389554eacfa7d80c64a67e1bb550c83", + "dist/2023-10-04/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "24ef9d6f0a7f43c22ece67c6ea52a7df1a704e386d867d8f563f9ab0b1f4fbe6", + "dist/2023-10-04/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "ad415b127acce0ab1ece6b21d12b3bde7b98b0185c8bff9cdad967430081eacb", + "dist/2023-10-04/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "69be4cf95dcf1ca7d2de6f9ce6580a9a30d033839d3629d371b640325fb7a852", + "dist/2023-10-04/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "9d04e4d8314594175458d1cd8ee1fa93e0289fa0b94ab3280224d4b5bcb4ebae", + "dist/2023-10-04/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "cd4292ce22cdc5553e28ad53ed130408de0c7f1f5af0ad2d1e8c06fd74aa3de8", + "dist/2023-10-04/rust-std-beta-wasm32-unknown-unknown.tar.gz": "a7d5382ac87dca13292b816164aae7ecd5b1221d672f2c03b7d236937ab66e3b", + "dist/2023-10-04/rust-std-beta-wasm32-unknown-unknown.tar.xz": "4f165c1f17ebc81875d6d310619c880581a5bfbaeecfa89743f9771894046214", + "dist/2023-10-04/rust-std-beta-wasm32-wasi-preview1-threads.tar.gz": "4ce6dcb79a483cc1c298d19386fe3782429371c7d3a6bfa4f614cceed8f5dc5e", + "dist/2023-10-04/rust-std-beta-wasm32-wasi-preview1-threads.tar.xz": "2b98636f16a3b988ee27cae0915906593e34d4a6475b37370ca541d53aff1ff3", + "dist/2023-10-04/rust-std-beta-wasm32-wasi.tar.gz": "02b684cc228945097c7ba2340fe7c6ca37ad01ad2c4385b70f0c49aa8d6fcc07", + "dist/2023-10-04/rust-std-beta-wasm32-wasi.tar.xz": "68addf98d1fa241ebe10fc9c3d4fdc00f694c5c603dacd6f306cac07802043bb", + "dist/2023-10-04/rust-std-beta-x86_64-apple-darwin.tar.gz": "f49920ef48466960edf9f21bb7c5374bd9edbbc8c5f6c47eb068e5081e3adaf7", + "dist/2023-10-04/rust-std-beta-x86_64-apple-darwin.tar.xz": "b20cffe93d14408618e149c922114061aedadcdb59e65c72bbbb06e378381ac7", + "dist/2023-10-04/rust-std-beta-x86_64-apple-ios.tar.gz": "22cb46613453e6c5a6cffcda03d7a0337b978b64209afec29d4132b121a7b13d", + "dist/2023-10-04/rust-std-beta-x86_64-apple-ios.tar.xz": "bc65c441d62c0d3fe2432a265cacc8f5e871ee9e894b5572f2e1511c4398c173", + "dist/2023-10-04/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "18c6e2495d8be9598e515229e4ea683c1ea2866f9a299dde52ebfbb3d0e1df4d", + "dist/2023-10-04/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "b9f57cd15a15701e0dc77c4b7de1f02444318a338bc176abd7737219746c840e", + "dist/2023-10-04/rust-std-beta-x86_64-linux-android.tar.gz": "b7299cf0a98d7eb7a28ecd57fbdc4fdc8bc6cde32cdaab27e9c5b4e323647908", + "dist/2023-10-04/rust-std-beta-x86_64-linux-android.tar.xz": "ff3190da0a9f11e43bd53b795bea384481026c5d426ac91768e0818a4c35c0ca", + "dist/2023-10-04/rust-std-beta-x86_64-pc-solaris.tar.gz": "2e602b85e49de5efbcc425c33c64bb85dd40cd7fe7b740a8e2953aa193bc4884", + "dist/2023-10-04/rust-std-beta-x86_64-pc-solaris.tar.xz": "e3120a09217977bd0fca8c10909319f1d5b2cf1c3a14d1a0bfa894a25c1dd30d", + "dist/2023-10-04/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "84508811863e1da5bb903fdbc1fe8335e15455469f58f243052b1d8e3885f3d1", + "dist/2023-10-04/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "105de75121b217dafb5b3432bbfcaee0432fc84d17bbfe0d8f6d27a7c9e3ad6c", + "dist/2023-10-04/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "559f9d676c36a236131a73776879103f68b7782ecfbacb7207bc443de44457e7", + "dist/2023-10-04/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "7baa8e4a543211d2235965d681f6d92127f2adc0a51c25d2fbb123715fb512c1", + "dist/2023-10-04/rust-std-beta-x86_64-sun-solaris.tar.gz": "ac20916902c464c9a9ee037b53f90e3b0cd3ec4c7b642deae88dc5f60bf98a8e", + "dist/2023-10-04/rust-std-beta-x86_64-sun-solaris.tar.xz": "c25d29435a43a607ff21204fb109675496229b975fbe879ce88bbb0c290f6cdf", + "dist/2023-10-04/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "8aae13ca12a349bcc0a2eae61543122095266e1fff1e6abd2d53e6f4609574ab", + "dist/2023-10-04/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "c94ec8fc50a4e003b4e4cd3ac3106b9cea0709dcd9d7729f72499744d875fa10", + "dist/2023-10-04/rust-std-beta-x86_64-unknown-fuchsia.tar.gz": "e8cf05fa4f01186b6e1810c0e5f8c3f6e5c7efe88cbf2efb6e9d6e4fed2692d9", + "dist/2023-10-04/rust-std-beta-x86_64-unknown-fuchsia.tar.xz": "70688ef9098dda4c2c0acb06a4edcf7457ccf5f6ae509edcad89ce1eb9b33fe6", + "dist/2023-10-04/rust-std-beta-x86_64-unknown-illumos.tar.gz": "4ee1f9699c22200beb40523976617b32e097c443bae1201fc64ad3235c8f58ea", + "dist/2023-10-04/rust-std-beta-x86_64-unknown-illumos.tar.xz": "988079564d076c2c49f8eae77069a0636945a980389ae06ed09a90326ddf9f76", + "dist/2023-10-04/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "0897b02e38e01b0c47075c9f2ebe1e8d127193890be499acec84c56e7a04c036", + "dist/2023-10-04/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "746317cab5b1c8676191287077e4a93877c545fbde577c3cc96149aaaec80afb", + "dist/2023-10-04/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "8130a54368f699c26108314690745dc69bcdc572ccedfcb5799728fb902b2ec7", + "dist/2023-10-04/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "c7493f1d747cbd893195a548f23ec9e713694057a15caa86d121fd981cf50ab6", + "dist/2023-10-04/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "6eec43a326e3c26a5f64c0aea25bcef1f890bbd4ec7bdfe9e32ea47641fb5820", + "dist/2023-10-04/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "1bca9c3dafa477ce34e2f58f6625bd3b461ae188468759921db591ec065cd3f6", + "dist/2023-10-04/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "bbb87aabd230f4209df5f63fdb88fb9f7a2f6d0b4e9cd9f9770e2a60881d4442", + "dist/2023-10-04/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "b235872c8041c38321d3e9d9ff3b4fce3ace96493c61af46e47b531bfab0eade", + "dist/2023-10-04/rust-std-beta-x86_64-unknown-none.tar.gz": "d20e50343834f77e39043ab23fe5591bff07bf913bbffcfbc9e618a920fb2043", + "dist/2023-10-04/rust-std-beta-x86_64-unknown-none.tar.xz": "495a4e236f92d2c9ec0ffaee4792e356ee15de447093538f9a34e85c94fd3ddf", + "dist/2023-10-04/rust-std-beta-x86_64-unknown-redox.tar.gz": "de46554c25acc2b3571063da2d63d32337a5c60f71afff96ead0339dedcb7f3d", + "dist/2023-10-04/rust-std-beta-x86_64-unknown-redox.tar.xz": "dea31f24ddd5c5bac73c6bc731f5356232be331fc8cdff80f4fa460266f1f5b5", + "dist/2023-10-04/rust-std-beta-x86_64-unknown-uefi.tar.gz": "7a1f61d37a132fe288652e7679f78c8f36d51a0724102ae39ccf81f0bc9e88bd", + "dist/2023-10-04/rust-std-beta-x86_64-unknown-uefi.tar.xz": "c452f747af508bfa76f27a3ecfdd333c50e9168ced7738fda38ea4e7f1ea904e", + "dist/2023-10-04/rustc-beta-aarch64-apple-darwin.tar.gz": "68aa57ce1a40d955bbc110bbcf1a9a433ef8492d91961658f163eea0f1917de6", + "dist/2023-10-04/rustc-beta-aarch64-apple-darwin.tar.xz": "30063d4818173bd302eecbe204942fc7c7a908a4294cfd3b5670de6a91c5937c", + "dist/2023-10-04/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "e91ae34b35404fd9466b3c4210c4859489b726df6bd1c6b5deda2f54f8243662", + "dist/2023-10-04/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "f5f62ccb98f5340a02ce4ad73cf370692eafb722d89a7dc18d411216dc62d082", + "dist/2023-10-04/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "b9dd02920bcd80f7bf58e5545ec8cfed0763eea657c2903cd21526b6f9ad3891", + "dist/2023-10-04/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "9ac274cd2078ddba5c856e3258862d45b61375f98d326a32505267c4856fa21f", + "dist/2023-10-04/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "ca1accabfd224bcefc1e9726cbb19066e42b3f5eff349c1be837e6adc4b4c63f", + "dist/2023-10-04/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "cd53dd9d96dff348f45ba28ffe68dcdb0fa90b372acc18e3edff9748e0ef6bed", + "dist/2023-10-04/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "3ca0229603110cb4492c2c399da2b57e5084791d8ec84b4cf9557498134362ce", + "dist/2023-10-04/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "f7950c38c09c37a8fb3d521b62185316e85cefcee13ecf6cf86238c03854aec9", + "dist/2023-10-04/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "332e1f2d816e878bcef183485ededaca830f72265c676af2df92e359df608fcc", + "dist/2023-10-04/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "0b88d3083b62f3e212bb2c823c7c2f5491eaed0baed99a031220f6ca115d4b17", + "dist/2023-10-04/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "0b4854c6290e97b4539f55973ccc9f9a4941a07c5b559f94b79490635913cf0f", + "dist/2023-10-04/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "fac86fc193852246947b648e2c725a4e9973d67a8129e66e9df88a91e7403ffa", + "dist/2023-10-04/rustc-beta-i686-pc-windows-gnu.tar.gz": "1ab3eecffe819ee2b4057a06998fce122931f1989dfab260272fc238f5672592", + "dist/2023-10-04/rustc-beta-i686-pc-windows-gnu.tar.xz": "8af88f78bbe66d35013a9b51606c570ade03c10c3e01115340ac62a99ad28ef8", + "dist/2023-10-04/rustc-beta-i686-pc-windows-msvc.tar.gz": "1d9c70146764cce221cc3e8144395541fc0f3b4af1cc4178342cc6c54e9adb6f", + "dist/2023-10-04/rustc-beta-i686-pc-windows-msvc.tar.xz": "5599aec7ac269dd2a03f5c549a50eca656a309cfe4178e097b64f6357f1d38e5", + "dist/2023-10-04/rustc-beta-i686-unknown-linux-gnu.tar.gz": "7b2b59a9e5acaa56d614c68fbe3b9f0e792f75a32e5f7c27b1ffb6d74508a433", + "dist/2023-10-04/rustc-beta-i686-unknown-linux-gnu.tar.xz": "2ed53af655d58300f88bae54967f964959c01f7d39e7198b14ad835392826dae", + "dist/2023-10-04/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz": "720e53352f5388ce0880b3f51b9941c4d7db86a549ae4c624238808438b02ecf", + "dist/2023-10-04/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz": "9fe3dc9d520284e4004c712fd328d86b6e4601283efe0bf519c3386906dd460f", + "dist/2023-10-04/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "d479a5254d2707ddf725b7400ae04c8c68c138a54aa65861ee5f8e6ef107c4a9", + "dist/2023-10-04/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "bf1756fc7b439b338defd1cbdcc1127c364a5ce4248c73f9a5881c39dd6a7bff", + "dist/2023-10-04/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "691e59ad96392bd1b61538fe2bcd8665470d9243a09c372bad93c115092aa5b7", + "dist/2023-10-04/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "3597d20828b23e94934ea8bbd4aafc51e06bd006ff993e95d1106822131403b7", + "dist/2023-10-04/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "24d283898ca2ce98b2ba38a9ac2fd2fb039da21badbe7c2e0c15660cd622a7e4", + "dist/2023-10-04/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "5c927ce64da0e898c03b56677047f087f88eab5c0777b6f07fb5356fb7dfd913", + "dist/2023-10-04/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "e10ef3fafa1dd6bf2c935853bb9289e1fbf85cfb092683b99107f986a2ba0b9c", + "dist/2023-10-04/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "d0fa4adb60babd26da08c8e141f1ce472c0c3111b1c361bb1a28cc65cd83afa7", + "dist/2023-10-04/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "65020cdd2b30795f3a8771fe41176e747bd13f3b948860aefed5675b89c55257", + "dist/2023-10-04/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "233890aaf235832448dbf05f7ac547cc74c53490fd6c9818d7ea673bb6391d35", + "dist/2023-10-04/rustc-beta-x86_64-apple-darwin.tar.gz": "745e29cf4127d5f67c1a663e47755a8cb200a14cbb44a33e5da6d25e11c145a3", + "dist/2023-10-04/rustc-beta-x86_64-apple-darwin.tar.xz": "609f55c6c784caf6978c176ddfe1b2675bd7f23a4ce4ebff98147f0ce58c0cac", + "dist/2023-10-04/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "78e37a161d41f1012896efb345b1e53febc11943e003c3e848106828e2b9337c", + "dist/2023-10-04/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "58baad93c3fd4a9c25472bfb10cea890efc94cc7c7b131d8dbca727bae79491e", + "dist/2023-10-04/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "3e5497aa975297ad9abae5913ab7ffe8a77a40a37cf26d7fbf18410993731ddf", + "dist/2023-10-04/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "157877278bb6b5af2676a61377e4a2b637470c89971e649b3476ec33d2f84987", + "dist/2023-10-04/rustc-beta-x86_64-unknown-freebsd.tar.gz": "923235f207f5477e455e82c1f516fcb1f9281f67c2f4fefdcb8b4a64b651d7eb", + "dist/2023-10-04/rustc-beta-x86_64-unknown-freebsd.tar.xz": "8e298f4524ee23f9f9b7ca00ce8c45c9e1a16d85c19acb4897fcf24ae1e40d8a", + "dist/2023-10-04/rustc-beta-x86_64-unknown-illumos.tar.gz": "e443cd9be3b531b645ad8ef32bb7f91f25fd17bdbd9439f1f77cd8345c13cc03", + "dist/2023-10-04/rustc-beta-x86_64-unknown-illumos.tar.xz": "682f11962582237689f9b8bc75c5a42b7492a26957909d15e919e0871b33b030", + "dist/2023-10-04/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "60faf9e993a2e2ebec1922a485fa63a47a1c4ad9e282928be8c21dd6397efe9e", + "dist/2023-10-04/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "e0a5cee0346f2ec96d14c5aa6b9d26d8d6d8ac80ea852b2df89d2df999c965e9", + "dist/2023-10-04/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "62ad39e3d0ee9eee3d88f3e2e0b151fc9eed8475e2e4b601dea37b8c6990a9c6", + "dist/2023-10-04/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "8946e23ee7e0eec9b519c0a7c0428592c30a605efb6b58109936300b59ac3074", + "dist/2023-10-04/rustc-beta-x86_64-unknown-netbsd.tar.gz": "651b08daca5f9de5c24ff465ee8f93beaa77477b6b54af8f7929d54876ca08e2", + "dist/2023-10-04/rustc-beta-x86_64-unknown-netbsd.tar.xz": "443bc94ae5274c8f42961bd2a297a32ee1d543ee1014d0f6cfce45febfc19c18", + "dist/2023-10-04/rustc-nightly-aarch64-apple-darwin.tar.gz": "2932fbd7dbe55d1bdfe33788d9aae9e40e42e5fc81841b605873cd118a769947", + "dist/2023-10-04/rustc-nightly-aarch64-apple-darwin.tar.xz": "c9bb124d9b5433d0a5fbfe8728fe4db5314b07f6f38617e6c8fa0b263f02b813", + "dist/2023-10-04/rustc-nightly-aarch64-pc-windows-msvc.tar.gz": "8b9a4eea2d57230d6dcc867b0564ac7c5b557e4eadfe8198ac253c523e72c00a", + "dist/2023-10-04/rustc-nightly-aarch64-pc-windows-msvc.tar.xz": "993f2afb93e5736973eba557ff5e14cebf4836ec02cfbdf2b652f06fce39cce5", + "dist/2023-10-04/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz": "0e10e13a02462859451cddcb429af9453ac3ba11dbe896d49b008905ec3b0fec", + "dist/2023-10-04/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz": "be81aa143335be4d36c01ca557128cbff380cdcea72d9df20260ac6d91ac79fe", + "dist/2023-10-04/rustc-nightly-aarch64-unknown-linux-musl.tar.gz": "f4300af316cc86ea85fb9775ad488e22e1f36fc10a2c40a55bea26fd1d180359", + "dist/2023-10-04/rustc-nightly-aarch64-unknown-linux-musl.tar.xz": "8579fdaf0c89dc6dfb69ef6f9c1c650476c4aa3d6f2664776a453028516366d3", + "dist/2023-10-04/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz": "bf6cb4c51f515a63e0ab92904c364238dcb889f21148ceffce0c2110238a7fca", + "dist/2023-10-04/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz": "359a9a8ca14829ef6f530631d8b88eda2fbfd9a7d01a3b9c8e98b121c8470056", + "dist/2023-10-04/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz": "9508938031c9333accd01cffad43b5ff1c552843cb4d5f5a0f767a3ccf908c01", + "dist/2023-10-04/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz": "e5d7638eab37ee18b58d50848398cef79d241939e1330796a7678399d395d1c8", + "dist/2023-10-04/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "196c7e12591a22f5c354045bb1f8ad18e8f069191b5d234fac3490d4c0782839", + "dist/2023-10-04/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "d01560008ec3c254b5ec1c4f9b4b707b7e60d4c7eb1560a2e95efd9fd681a63f", + "dist/2023-10-04/rustc-nightly-i686-pc-windows-gnu.tar.gz": "13987991229171f65295f901451bc735d5b38737c012150c7d912a9dbb627136", + "dist/2023-10-04/rustc-nightly-i686-pc-windows-gnu.tar.xz": "de3b82265e5157b0fe36ba0686b4dfaf9b697594ba50c0697d1d261812bddd30", + "dist/2023-10-04/rustc-nightly-i686-pc-windows-msvc.tar.gz": "aa2292fbcd0ea65407e5cf47924616a90762ca4750535c3e980b9057623bd896", + "dist/2023-10-04/rustc-nightly-i686-pc-windows-msvc.tar.xz": "063fcf503b76f1ae1ed7278a01c61e12bef4aa6d5e69ddec751986dfc7038b27", + "dist/2023-10-04/rustc-nightly-i686-unknown-linux-gnu.tar.gz": "cb0a6e9cfbf7a2869818fe16c853127e4d7cafb69cda01d7737d30476f7d9b49", + "dist/2023-10-04/rustc-nightly-i686-unknown-linux-gnu.tar.xz": "0057ecebc5d9e12f6ef8d0c0ea737b7694507b9c7a8ce0e6e0d323acd0a39b3e", + "dist/2023-10-04/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz": "b38717c03d77eb019262ea3a82e7d91f620170bcb1f05717f8e5dadfac1df483", + "dist/2023-10-04/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz": "4e6a0e9d35101983388772f77ac0fc0714f3025d670c649e6050fb50ca031738", + "dist/2023-10-04/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz": "1ea0bd0e5070fa590dc2301b6f41a54b9895b0fd688d9c6f37d77d0b6bbef8ee", + "dist/2023-10-04/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz": "6666cc6e04743127cd63ec7c8fe1e9fb7882222778471ea1368bbab4adce903a", + "dist/2023-10-04/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz": "60c4c413d85f86de2709e4b9ab4c0e25bb6e99da3e10cc68eb2b3864a5d60e18", + "dist/2023-10-04/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz": "8569bba6344da9ceb87d53c3d5664d442a1251621625f7b332c4a6f4cb93643a", + "dist/2023-10-04/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "016f8daba0a904e185075840c55f477bab7c91a8b6ca1aee936074f01adb2b44", + "dist/2023-10-04/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "573286e527de43850a25b2c03b61d89fc97437ceacc9f5b3be3a313c9175027e", + "dist/2023-10-04/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "d03339ef02057584100232a6def4a9b80f13b9d242fe57fa47c0b18e84f3c56f", + "dist/2023-10-04/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "2e5ceb85b2612164e1727471a775d5ca1924f92327deddce0d1509c5a87e4bb9", + "dist/2023-10-04/rustc-nightly-s390x-unknown-linux-gnu.tar.gz": "b991507575a08b993508ee4c7ac065f3f1983278a457c141ffbfb15b46ae25c2", + "dist/2023-10-04/rustc-nightly-s390x-unknown-linux-gnu.tar.xz": "155a4e360eeae301379200415820a6f9c53d3923943d791a3e802ef8083494c4", + "dist/2023-10-04/rustc-nightly-x86_64-apple-darwin.tar.gz": "0ae7a68d86c72f42e3a98737abe466ad88a6be92cb17994b26fc2a495abacd2e", + "dist/2023-10-04/rustc-nightly-x86_64-apple-darwin.tar.xz": "5e2b0a191b34e133ca9e0d883714bea46dc0f6381c9e5ee145851bba799bf7db", + "dist/2023-10-04/rustc-nightly-x86_64-pc-windows-gnu.tar.gz": "62e5b0dae1aa25488dab73869da8ed2425114b778adc55db6c6c6b9f77c67d7e", + "dist/2023-10-04/rustc-nightly-x86_64-pc-windows-gnu.tar.xz": "5494b11d55bb36ae0536b534796870a0ad8e2a427f64a21418d5bcc2d0f27ab9", + "dist/2023-10-04/rustc-nightly-x86_64-pc-windows-msvc.tar.gz": "38b8add3755f62016c40ac84ad3b7085b6058e40768b40e2df672ea4c5d3e91d", + "dist/2023-10-04/rustc-nightly-x86_64-pc-windows-msvc.tar.xz": "e511c5e3adfffd33e6dd3cd9525409366f3b54ebb1b3a7f2c09cb7444e678006", + "dist/2023-10-04/rustc-nightly-x86_64-unknown-freebsd.tar.gz": "54190bb432f9dbc4fb414ff40a5e8a5668b8aa343599b4e4b28f7a2e9fc0fa3b", + "dist/2023-10-04/rustc-nightly-x86_64-unknown-freebsd.tar.xz": "7c260043c68b31484f3d415d43ad8bd702f642cfc5050e09ea6b9bb7fa108020", + "dist/2023-10-04/rustc-nightly-x86_64-unknown-illumos.tar.gz": "7cc87c2a5f801a1023688cc6bbecfa0c4c072108b4edcf4afea5df059ef1c2cc", + "dist/2023-10-04/rustc-nightly-x86_64-unknown-illumos.tar.xz": "b21f227d6b8c4c8847db2e3299613a86b13c95bff4f17c7055e1c0d46721fbc6", + "dist/2023-10-04/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz": "52b372926f5f72a711c36da67a09dfd8d4c9e819b76917053865cce5bc603732", + "dist/2023-10-04/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "499a3aa2baff90e710e2aa9d6be421569119ac90b484093ec38717da1fea3142", + "dist/2023-10-04/rustc-nightly-x86_64-unknown-linux-musl.tar.gz": "dc43a1ff5639479cef66778baf3a61ccee67b1aba57dc24a81a0d2f35b24b3ad", + "dist/2023-10-04/rustc-nightly-x86_64-unknown-linux-musl.tar.xz": "0f953831e44c7084c86f393cfa3a3b3a0ea8aa2de3a0f7701094683f491c4a6b", + "dist/2023-10-04/rustc-nightly-x86_64-unknown-netbsd.tar.gz": "e636cdb58be6fc3d97387121c404d02772c5a7519f0f001f1c9ff282acdaead4", + "dist/2023-10-04/rustc-nightly-x86_64-unknown-netbsd.tar.xz": "79db9632154590294cd0a9f1229b95ec82163a278b3011e25f2fb86c8af6d894", + "dist/2023-10-04/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "0cde181bc0e9af1eb2813aea3ada3333974eaa85227eab12eaeffe026fe7f31b", + "dist/2023-10-04/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "0aa47b92b78591f522c5d5b4109b1a0fcb4489ceeb3a9014d3f71dc76bc00a6e", + "dist/2023-10-04/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "30ac919cb1eec11a22d96ab32debddf9ee91e776d0edac25fd2c71421145d77c", + "dist/2023-10-04/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "55d800eab787c0bb1d41def853b1a48ab54c2e6cfd6b118e905ec283cc1814eb", + "dist/2023-10-04/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "9e3ae2cbc37307c47c78c953cb2703daddd46b6df44cc61c2b3cf43921c5b03c", + "dist/2023-10-04/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "6812bf2f1ff86bce8bc82cf2ea2f29171fced04b9ca89cfc43121824c4d15eda", + "dist/2023-10-04/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "99ee18898dde1821751cc06eead4d53208d66d98c7f95e8122c7a1161924aaea", + "dist/2023-10-04/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "f65c4577aad313101a6b22f55d777a76db31f21c6467f25eb1d8775a484256ba", + "dist/2023-10-04/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "94b76e626d2460f6701d5c16dc91d633a8c88b0f2583f4996b1173709c29c8cb", + "dist/2023-10-04/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "d63186fe9980b884f375f8ea44ea2e4e8493529047a7035c49c9007261310d8d", + "dist/2023-10-04/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "04e20827f34cab6f259686decdec4df335a8bfa2846a46fc83bee1d65b39ee15", + "dist/2023-10-04/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "f46798ddac7d5b3cafaba54b0fa561ff618f7b931cba4b59eaf2f38e5a60b720", + "dist/2023-10-04/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "3d2b5974f820e976c890300755efbcebb4b14558bd9824bc66d9ebf1dc33de7d", + "dist/2023-10-04/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "ce148b424ce7122fb2330c9911fdb134a67b7365dbd10fff182bd70517ea39e1", + "dist/2023-10-04/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "369278645833248dad11a65a886791134880e26bf0a35ff9462913a355fffb90", + "dist/2023-10-04/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "995727a9213386e7e02d27a3d2f99f5beda5fc0469fccc5736b92ecb4e317ba6", + "dist/2023-10-04/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "92da2162ef18033e68593617613ac11d9ba16bda81a0a685a89fcbd80a815994", + "dist/2023-10-04/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "abca8c7e31afc80ea515c92a7e12a8d6d0af6d41d5f18caeba74a1cd5372876c", + "dist/2023-10-04/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "e755ab5413fa52013cc00df1d8cda68c5b3ef1e99d1d964259d5b002f293e8b2", + "dist/2023-10-04/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "1100241ea39bc177140c458a12174b54af5d569000f59c9791ee8c6497fd4fe6", + "dist/2023-10-04/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz": "5ac4fe7bb0f596cd8565d1edef6f1696043c698c90f5562f5d4a94fca26021a6", + "dist/2023-10-04/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz": "9ecf3bac557d64bd467f9213959e8b1a361041e5a98552a448936fd2903b334d", + "dist/2023-10-04/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "71bbdb6c608d2cdc60619dc2acd7bc7e35e9a20e5e02a633b224b124438a7cb6", + "dist/2023-10-04/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "2d3af87b5c6e0ea524cde039a6deb0b014ca103e4183602b47aedb5bfb97ff9d", + "dist/2023-10-04/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "e3678dc35f3dede5d6fc5e75eec6f19990e4a8b034163c4ef79eb522e654f6f3", + "dist/2023-10-04/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "da9ed66ae0021c2cc16d70a29151963149a433fd4a2a299a45d7cd23556fc58f", + "dist/2023-10-04/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "8a08e5a3d5eea3f414e7b8ed939793ce02f843a60dadf0e4d6eb62e8265fa20c", + "dist/2023-10-04/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "68441252ba1e058023cd480e431e04d755309c1acd7330d49a20c0aeefb1ceac", + "dist/2023-10-04/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "305f24d9813129ce07117dff8cf0de42aff539c7a89df58c2a11f7056594a702", + "dist/2023-10-04/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "beca739e374e20d15a3a16240a801662c42ef135eea5311d8bae7335bf27634c", + "dist/2023-10-04/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "c33dc1b858ad79f2ef89159f40b893d071bd54b1891868064bd210fa2ab1c917", + "dist/2023-10-04/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "0929169a91b4d66058e251ebf7c8bbeb73e3859600158afeb9fcdedd4de84168", + "dist/2023-10-04/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "13684516018f9c56c504793b4d110610f6f8c4a2a1624c63630a12927a9b5b29", + "dist/2023-10-04/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "50686ab2eeeb73d51830b8f19c76a615eec1b17df8f34ddbcbee6458fc51832d", + "dist/2023-10-04/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "315a87aa3fbbc7594d64b4771d105961144f9937c9c1b33991de4ff33c186bd6", + "dist/2023-10-04/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "289c99380cfb2933d5c85b20f7f38e4a61de2c3ce3640ca45a81eb68a7005b72", + "dist/2023-10-04/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "81f689344b8d0d2312790109c18e206849906bcee5bb167c9a07632c1ba71eaa", + "dist/2023-10-04/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "6f17e1e8327cb470c00e58acb8f4b076aa8989c98bcbb0c55867dd6ba1f436ae", + "dist/2023-10-04/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "93e0ccbe7484ee679c4cefa80e46d76c0adfe93f0b52b34ba80cefbde69845b9", + "dist/2023-10-04/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "4c9fde270df24fbca4286d42577d454fab9aa3cc7abec2f8eb4fce359162d8ad", + "dist/2023-10-04/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "e6d4e9b727c7c61a28dbfead22492c7503c4b5d05b41e2991eb9e3551365d440", + "dist/2023-10-04/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "30db9362b5f7eb09ba8ac2050cb98599fb352b332bf3e5c94ad6bc182fe9f294", + "dist/2023-10-04/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "348b94f9020c65fec79a36c6044857a7e897164f1b2a4250e807f258efe99e1b", + "dist/2023-10-04/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "2914983968c484e4e74cee620764aeb476445b1e324253c5087354dbb95a0132", + "dist/2023-10-04/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "0ab0a77a8fadc6cc4e21238cb9487bf5e3b6085663351b2b3c429038621ad83d", + "dist/2023-10-04/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "a992de62c67d56889e11dc7c5401729d8658c3e50365037b4bd975624122dec5", + "dist/2023-10-04/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "e9ab091b5bf9d307164b8c774f98912a0a8282f98e6d9528569acb2dcf29a10d", + "dist/2023-10-04/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "d9421dbbb9b995b6df1144cebf0d6b10fc4a91414b97d66b28335e78b8859d5b" } } diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 794d0a82547f3081044c0aca7b6083733ce5134 +Subproject 8eb8acbb116e7923ea2ce33a50109933ed5ab37 diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 14877385646..5134cf66050 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -701,7 +701,7 @@ fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool { fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool { if let Some(parent) = get_parent_expr(cx, e) - && parent.span.ctxt() == e.span.ctxt() + && parent.span.eq_ctxt(e.span) { match parent.kind { ExprKind::Call(child, _) | ExprKind::MethodCall(_, child, _, _) | ExprKind::Index(child, _, _) diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index 6197b5b19eb..70a467dde61 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -241,7 +241,7 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio }, ], _, - ) if key_span.ctxt() == expr.span.ctxt() => { + ) if key_span.eq_ctxt(expr.span) => { let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; let expr = ContainsExpr { negated, diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs index d03480c2108..4ebf0e9667d 100644 --- a/src/tools/clippy/clippy_lints/src/formatting.rs +++ b/src/tools/clippy/clippy_lints/src/formatting.rs @@ -274,7 +274,7 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) { for element in array { if_chain! { if let ExprKind::Binary(ref op, ref lhs, _) = element.kind; - if has_unary_equivalent(op.node) && lhs.span.ctxt() == op.span.ctxt(); + if has_unary_equivalent(op.node) && lhs.span.eq_ctxt(op.span); let space_span = lhs.span.between(op.span); if let Some(space_snippet) = snippet_opt(cx, space_span); let lint_span = lhs.span.with_lo(lhs.span.hi()); diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs index 4e9d77ea156..79d728a021c 100644 --- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs @@ -31,7 +31,7 @@ impl LateLintPass<'_> for UnderscoreTyped { if !in_external_macro(cx.tcx.sess, local.span); if let Some(ty) = local.ty; // Ensure that it has a type defined if let TyKind::Infer = &ty.kind; // that type is '_' - if local.span.ctxt() == ty.span.ctxt(); + if local.span.eq_ctxt(ty.span); then { // NOTE: Using `is_from_proc_macro` on `init` will require that it's initialized, // this doesn't. Alternatively, `WithSearchPat` can be implemented for `Ty` diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs index 2117308cd40..86bbdb4ea19 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -59,7 +59,7 @@ impl<'tcx> QuestionMark { let Some(init) = local.init && local.els.is_none() && local.ty.is_none() && - init.span.ctxt() == stmt.span.ctxt() && + init.span.eq_ctxt(stmt.span) && let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init) { match if_let_or_match { diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs index 33a052c41a3..29b935fb61a 100644 --- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs @@ -57,7 +57,7 @@ fn check_arm<'tcx>( } }, }; - if outer_pat.span.ctxt() == inner_scrutinee.span.ctxt(); + if outer_pat.span.eq_ctxt(inner_scrutinee.span); // match expression must be a local binding // match <local> { .. } if let Some(binding_id) = path_to_local(peel_ref_operators(cx, inner_scrutinee)); diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs index 6b611f567ae..781ee138c76 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs @@ -119,7 +119,7 @@ where // it's being passed by value. let scrutinee = peel_hir_expr_refs(scrutinee).0; let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app); - let scrutinee_str = if scrutinee.span.ctxt() == expr.span.ctxt() && scrutinee.precedence().order() < PREC_POSTFIX { + let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && scrutinee.precedence().order() < PREC_POSTFIX { format!("({scrutinee_str})") } else { scrutinee_str.into() @@ -130,7 +130,7 @@ where if_chain! { if !some_expr.needs_unsafe_block; if let Some(func) = can_pass_as_func(cx, id, some_expr.expr); - if func.span.ctxt() == some_expr.expr.span.ctxt(); + if func.span.eq_ctxt(some_expr.expr.span); then { snippet_with_applicability(cx, func.span, "..", &mut app).into_owned() } else { diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs index de911f7a028..a2903e52ae0 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs @@ -19,7 +19,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<' if is_type_diagnostic_item(cx, ex_ty, sym::Result) { for arm in arms { if let PatKind::TupleStruct(ref path, inner, _) = arm.pat.kind { - let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)); + let path_str = rustc_hir_pretty::qpath_to_string(path); if path_str == "Err" { let mut matching_wild = inner.iter().any(is_wild); let mut ident_bind_name = kw::Underscore; diff --git a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs index 5464e455dea..e70a1bc9879 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs @@ -56,7 +56,7 @@ pub(super) fn check<'tcx>( // lint, with note if neither arg is > 1 line and both map() and // unwrap_or_else() have the same span let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1; - let same_span = map_arg.span.ctxt() == unwrap_arg.span.ctxt(); + let same_span = map_arg.span.eq_ctxt(unwrap_arg.span); if same_span && !multiline { let var_snippet = snippet(cx, recv.span, ".."); span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs index e53e146ec5d..01b850cdb11 100644 --- a/src/tools/clippy/clippy_lints/src/mut_reference.rs +++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs @@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { cx, arguments.iter().collect(), cx.typeck_results().expr_ty(fn_expr), - &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)), + &rustc_hir_pretty::qpath_to_string(path), "function", ); } diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index 7b0f7eaf1f0..0e834fb3ac7 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -125,7 +125,7 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar(_)) = &arg.kind; if let ExprKind::Call(called, [inner_expr]) = &inner_expr_with_q.kind; if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, ..)) = &called.kind; - if expr.span.ctxt() == inner_expr.span.ctxt(); + if expr.span.eq_ctxt(inner_expr.span); let expr_ty = cx.typeck_results().expr_ty(expr); let inner_ty = cx.typeck_results().expr_ty(inner_expr); if expr_ty == inner_ty; diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs index d47728f190a..e94e4589966 100644 --- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs +++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs @@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { || (path.ident.name == sym!(set_mode) && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did())); if let ExprKind::Lit(_) = param.kind; - if param.span.ctxt() == expr.span.ctxt(); + if param.span.eq_ctxt(expr.span); then { let Some(snip) = snippet_opt(cx, param.span) else { @@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE); if let ExprKind::Lit(_) = param.kind; - if param.span.ctxt() == expr.span.ctxt(); + if param.span.eq_ctxt(expr.span); if let Some(snip) = snippet_opt(cx, param.span); if !snip.starts_with("0o"); then { diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs index 534b2762ba7..8193057a6eb 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs @@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { let Some(body_expr) = desugar_async_block(cx, expr) && let Some(expr) = desugar_await(peel_blocks(body_expr)) && // The await prefix must not come from a macro as its content could change in the future. - expr.span.ctxt() == body_expr.span.ctxt() && + expr.span.eq_ctxt(body_expr.span) && // An async block does not have immediate side-effects from a `.await` point-of-view. (!expr.can_have_side_effects() || desugar_async_block(cx, expr).is_some()) && let Some(shortened_span) = walk_span_to_context(expr.span, span.ctxt()) diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs index db870ec4c5b..12da29f1108 100644 --- a/src/tools/clippy/clippy_lints/src/reference.rs +++ b/src/tools/clippy/clippy_lints/src/reference.rs @@ -50,7 +50,7 @@ impl EarlyLintPass for DerefAddrOf { if_chain! { if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind; if let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind; - if deref_target.span.ctxt() == e.span.ctxt(); + if deref_target.span.eq_ctxt(e.span); if !addrof_target.span.from_expansion(); then { let mut applicability = Applicability::MachineApplicable; diff --git a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs index 8e156b8829b..39cd289b67a 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs @@ -33,7 +33,7 @@ impl LateLintPass<'_> for ConfusingXorAndPow { if !in_external_macro(cx.sess(), expr.span) && let ExprKind::Binary(op, left, right) = &expr.kind && op.node == BinOpKind::BitXor - && left.span.ctxt() == right.span.ctxt() + && left.span.eq_ctxt(right.span) && let ExprKind::Lit(lit_left) = &left.kind && let ExprKind::Lit(lit_right) = &right.kind && matches!(lit_right.node, LitKind::Int(..) | LitKind::Float(..)) diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs index eaf590f6ad7..46ce4ffdce5 100644 --- a/src/tools/clippy/clippy_utils/src/macros.rs +++ b/src/tools/clippy/clippy_utils/src/macros.rs @@ -245,7 +245,7 @@ impl<'a> PanicExpn<'a> { return None; }; let result = match name { - "panic" if arg.span.ctxt() == expr.span.ctxt() => Self::Empty, + "panic" if arg.span.eq_ctxt(expr.span) => Self::Empty, "panic" | "panic_str" => Self::Str(arg), "panic_display" | "panic_cold_display" => { let ExprKind::AddrOf(_, _, e) = &arg.kind else { diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 2d305a63eca..673b259523e 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -1133,7 +1133,7 @@ pub fn make_projection<'tcx>( #[cfg(debug_assertions)] assert_generic_args_match(tcx, assoc_item.def_id, args); - Some(tcx.mk_alias_ty(assoc_item.def_id, args)) + Some(ty::AliasTy::new(tcx, assoc_item.def_id, args)) } helper( tcx, diff --git a/src/tools/clippy/tests/ui/implied_bounds_in_impls.fixed b/src/tools/clippy/tests/ui/implied_bounds_in_impls.fixed index a50fa0ccf6e..fa117aaddcd 100644 --- a/src/tools/clippy/tests/ui/implied_bounds_in_impls.fixed +++ b/src/tools/clippy/tests/ui/implied_bounds_in_impls.fixed @@ -1,6 +1,5 @@ #![warn(clippy::implied_bounds_in_impls)] #![allow(dead_code)] -#![feature(return_position_impl_trait_in_trait)] use std::ops::{Deref, DerefMut}; diff --git a/src/tools/clippy/tests/ui/implied_bounds_in_impls.rs b/src/tools/clippy/tests/ui/implied_bounds_in_impls.rs index e74ed4425b8..c96aac151a7 100644 --- a/src/tools/clippy/tests/ui/implied_bounds_in_impls.rs +++ b/src/tools/clippy/tests/ui/implied_bounds_in_impls.rs @@ -1,6 +1,5 @@ #![warn(clippy::implied_bounds_in_impls)] #![allow(dead_code)] -#![feature(return_position_impl_trait_in_trait)] use std::ops::{Deref, DerefMut}; diff --git a/src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr b/src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr index 72dc2a183a3..fb44f2aba17 100644 --- a/src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr +++ b/src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr @@ -1,5 +1,5 @@ error: this bound is already specified as the supertrait of `DerefMut<Target = T>` - --> $DIR/implied_bounds_in_impls.rs:13:36 + --> $DIR/implied_bounds_in_impls.rs:12:36 | LL | fn deref_derefmut<T>(x: T) -> impl Deref<Target = T> + DerefMut<Target = T> { | ^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + fn deref_derefmut<T>(x: T) -> impl DerefMut<Target = T> { | error: this bound is already specified as the supertrait of `GenericSubtrait<U, W, U>` - --> $DIR/implied_bounds_in_impls.rs:30:37 + --> $DIR/implied_bounds_in_impls.rs:29:37 | LL | fn generics_implied<U, W>() -> impl GenericTrait<W> + GenericSubtrait<U, W, U> | ^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + fn generics_implied<U, W>() -> impl GenericSubtrait<U, W, U> | error: this bound is already specified as the supertrait of `GenericSubtrait<(), i32, V>` - --> $DIR/implied_bounds_in_impls.rs:36:40 + --> $DIR/implied_bounds_in_impls.rs:35:40 | LL | fn generics_implied_multi<V>() -> impl GenericTrait<i32> + GenericTrait2<V> + GenericSubtrait<(), i32, V> {} | ^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + fn generics_implied_multi<V>() -> impl GenericTrait2<V> + GenericSubtrait<( | error: this bound is already specified as the supertrait of `GenericSubtrait<(), i32, V>` - --> $DIR/implied_bounds_in_impls.rs:36:60 + --> $DIR/implied_bounds_in_impls.rs:35:60 | LL | fn generics_implied_multi<V>() -> impl GenericTrait<i32> + GenericTrait2<V> + GenericSubtrait<(), i32, V> {} | ^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + fn generics_implied_multi<V>() -> impl GenericTrait<i32> + GenericSubtrait< | error: this bound is already specified as the supertrait of `GenericSubtrait<(), T, V>` - --> $DIR/implied_bounds_in_impls.rs:38:44 + --> $DIR/implied_bounds_in_impls.rs:37:44 | LL | fn generics_implied_multi2<T, V>() -> impl GenericTrait<T> + GenericTrait2<V> + GenericSubtrait<(), T, V> | ^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + fn generics_implied_multi2<T, V>() -> impl GenericTrait2<V> + GenericSubtra | error: this bound is already specified as the supertrait of `GenericSubtrait<(), T, V>` - --> $DIR/implied_bounds_in_impls.rs:38:62 + --> $DIR/implied_bounds_in_impls.rs:37:62 | LL | fn generics_implied_multi2<T, V>() -> impl GenericTrait<T> + GenericTrait2<V> + GenericSubtrait<(), T, V> | ^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + fn generics_implied_multi2<T, V>() -> impl GenericTrait<T> + GenericSubtrai | error: this bound is already specified as the supertrait of `GenericSubtrait<(), i32, ()>` - --> $DIR/implied_bounds_in_impls.rs:48:28 + --> $DIR/implied_bounds_in_impls.rs:47:28 | LL | fn generics_same() -> impl GenericTrait<i32> + GenericSubtrait<(), i32, ()> {} | ^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + fn generics_same() -> impl GenericSubtrait<(), i32, ()> {} | error: this bound is already specified as the supertrait of `DerefMut<Target = u8>` - --> $DIR/implied_bounds_in_impls.rs:52:20 + --> $DIR/implied_bounds_in_impls.rs:51:20 | LL | fn f() -> impl Deref + DerefMut<Target = u8>; | ^^^^^ @@ -97,7 +97,7 @@ LL + fn f() -> impl DerefMut<Target = u8>; | error: this bound is already specified as the supertrait of `DerefMut<Target = u8>` - --> $DIR/implied_bounds_in_impls.rs:57:20 + --> $DIR/implied_bounds_in_impls.rs:56:20 | LL | fn f() -> impl Deref + DerefMut<Target = u8> { | ^^^^^ @@ -109,7 +109,7 @@ LL + fn f() -> impl DerefMut<Target = u8> { | error: this bound is already specified as the supertrait of `DerefMut<Target = u8>` - --> $DIR/implied_bounds_in_impls.rs:63:20 + --> $DIR/implied_bounds_in_impls.rs:62:20 | LL | fn f() -> impl Deref + DerefMut<Target = u8> { | ^^^^^ @@ -121,7 +121,7 @@ LL + fn f() -> impl DerefMut<Target = u8> { | error: this bound is already specified as the supertrait of `PartialOrd` - --> $DIR/implied_bounds_in_impls.rs:74:41 + --> $DIR/implied_bounds_in_impls.rs:73:41 | LL | fn default_generic_param1() -> impl PartialEq + PartialOrd + Debug {} | ^^^^^^^^^ @@ -133,7 +133,7 @@ LL + fn default_generic_param1() -> impl PartialOrd + Debug {} | error: this bound is already specified as the supertrait of `PartialOrd` - --> $DIR/implied_bounds_in_impls.rs:75:54 + --> $DIR/implied_bounds_in_impls.rs:74:54 | LL | fn default_generic_param2() -> impl PartialOrd + PartialEq + Debug {} | ^^^^^^^^^ @@ -145,7 +145,7 @@ LL + fn default_generic_param2() -> impl PartialOrd + Debug {} | error: this bound is already specified as the supertrait of `DoubleEndedIterator` - --> $DIR/implied_bounds_in_impls.rs:88:26 + --> $DIR/implied_bounds_in_impls.rs:87:26 | LL | fn my_iter() -> impl Iterator<Item = u32> + DoubleEndedIterator { | ^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL + fn my_iter() -> impl DoubleEndedIterator<Item = u32> { | error: this bound is already specified as the supertrait of `Copy` - --> $DIR/implied_bounds_in_impls.rs:93:27 + --> $DIR/implied_bounds_in_impls.rs:92:27 | LL | fn f() -> impl Copy + Clone { | ^^^^^ @@ -169,7 +169,7 @@ LL + fn f() -> impl Copy { | error: this bound is already specified as the supertrait of `Trait2<i32>` - --> $DIR/implied_bounds_in_impls.rs:107:21 + --> $DIR/implied_bounds_in_impls.rs:106:21 | LL | fn f2() -> impl Trait1<i32, U = i64> + Trait2<i32> {} | ^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + fn f2() -> impl Trait2<i32, U = i64> {} | error: this bound is already specified as the supertrait of `Trait4<i8, X = i32>` - --> $DIR/implied_bounds_in_impls.rs:122:21 + --> $DIR/implied_bounds_in_impls.rs:121:21 | LL | fn f3() -> impl Trait3<i8, i16, i64, X = i32, Y = i128> + Trait4<i8, X = i32> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unused_async.rs b/src/tools/clippy/tests/ui/unused_async.rs index 71722e9afd0..7ec8a3adb4c 100644 --- a/src/tools/clippy/tests/ui/unused_async.rs +++ b/src/tools/clippy/tests/ui/unused_async.rs @@ -1,5 +1,4 @@ #![warn(clippy::unused_async)] -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] use std::future::Future; diff --git a/src/tools/clippy/tests/ui/unused_async.stderr b/src/tools/clippy/tests/ui/unused_async.stderr index 077e8cacce1..c97a76a55cb 100644 --- a/src/tools/clippy/tests/ui/unused_async.stderr +++ b/src/tools/clippy/tests/ui/unused_async.stderr @@ -1,5 +1,5 @@ error: unused `async` for function with no await statements - --> $DIR/unused_async.rs:13:5 + --> $DIR/unused_async.rs:12:5 | LL | / async fn async_block_await() { LL | | @@ -11,7 +11,7 @@ LL | | } | = help: consider removing the `async` from this function note: `await` used in an async block, which does not require the enclosing function to be `async` - --> $DIR/unused_async.rs:16:23 + --> $DIR/unused_async.rs:15:23 | LL | ready(()).await; | ^^^^^ @@ -19,7 +19,7 @@ LL | ready(()).await; = help: to override `-D warnings` add `#[allow(clippy::unused_async)]` error: unused `async` for function with no await statements - --> $DIR/unused_async.rs:46:5 + --> $DIR/unused_async.rs:45:5 | LL | async fn f3() {} | ^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | async fn f3() {} = help: consider removing the `async` from this function error: unused `async` for function with no await statements - --> $DIR/unused_async.rs:59:1 + --> $DIR/unused_async.rs:58:1 | LL | / async fn foo() -> i32 { LL | | @@ -38,7 +38,7 @@ LL | | } = help: consider removing the `async` from this function error: unused `async` for function with no await statements - --> $DIR/unused_async.rs:71:5 + --> $DIR/unused_async.rs:70:5 | LL | / async fn unused(&self) -> i32 { LL | | diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index bb1fa6e9237..31c6353e675 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -11,6 +11,7 @@ colored = "2" diff = "0.1.10" unified-diff = "0.2.1" getopts = "0.2" +indexmap = "2.0.0" miropt-test-tools = { path = "../miropt-test-tools" } build_helper = { path = "../build_helper" } tracing = "0.1" diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 269d9384376..948439d6e79 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -322,7 +322,15 @@ impl TestProps { ); if let Some(flags) = config.parse_name_value_directive(ln, COMPILE_FLAGS) { - self.compile_flags.extend(flags.split_whitespace().map(|s| s.to_owned())); + self.compile_flags.extend( + flags + .split("'") + .enumerate() + .flat_map(|(i, f)| { + if i % 2 == 1 { vec![f] } else { f.split_whitespace().collect() } + }) + .map(|s| s.to_owned()), + ); } if config.parse_name_value_directive(ln, INCORRECT_COMPILER_FLAGS).is_some() { panic!("`compiler-flags` directive should be spelled `compile-flags`"); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 657d074b380..875671c64e0 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2335,17 +2335,14 @@ impl<'test> TestCx<'test> { rustc.arg("-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX"); rustc.arg("-Ztranslate-remapped-path-to-local-path=no"); - // #[cfg(not(bootstrap))]: After beta bump, this should **always** run. - if !(self.config.stage_id.starts_with("stage1-") && self.config.suite == "ui-fulldeps") { - // Hide Cargo dependency sources from ui tests to make sure the error message doesn't - // change depending on whether $CARGO_HOME is remapped or not. If this is not present, - // when $CARGO_HOME is remapped the source won't be shown, and when it's not remapped the - // source will be shown, causing a blessing hell. - rustc.arg("-Z").arg(format!( - "ignore-directory-in-diagnostics-source-blocks={}", - home::cargo_home().expect("failed to find cargo home").to_str().unwrap() - )); - } + // Hide Cargo dependency sources from ui tests to make sure the error message doesn't + // change depending on whether $CARGO_HOME is remapped or not. If this is not present, + // when $CARGO_HOME is remapped the source won't be shown, and when it's not remapped the + // source will be shown, causing a blessing hell. + rustc.arg("-Z").arg(format!( + "ignore-directory-in-diagnostics-source-blocks={}", + home::cargo_home().expect("failed to find cargo home").to_str().unwrap() + )); // Optionally prevent default --sysroot if specified in test compile-flags. if !self.props.compile_flags.iter().any(|flag| flag.starts_with("--sysroot")) @@ -4261,6 +4258,39 @@ impl<'test> TestCx<'test> { V0_BACK_REF_RE.replace_all(&normalized, V0_BACK_REF_PLACEHOLDER).into_owned(); } + // AllocId are numbered globally in a compilation session. This can lead to changes + // depending on the exact compilation flags and host architecture. Meanwhile, we want + // to keep them numbered, to see if the same id appears multiple times. + // So we remap to deterministic numbers that only depend on the subset of allocations + // that actually appear in the output. + // We use uppercase ALLOC to distinguish from the non-normalized version. + { + let mut seen_allocs = indexmap::IndexSet::new(); + + // The alloc-id appears in pretty-printed allocations. + let re = Regex::new(r"╾─*a(lloc)?([0-9]+)(\+0x[0-9]+)?─*╼").unwrap(); + normalized = re + .replace_all(&normalized, |caps: &Captures<'_>| { + // Renumber the captured index. + let index = caps.get(2).unwrap().as_str().to_string(); + let (index, _) = seen_allocs.insert_full(index); + let offset = caps.get(3).map_or("", |c| c.as_str()); + // Do not bother keeping it pretty, just make it deterministic. + format!("╾ALLOC{index}{offset}╼") + }) + .into_owned(); + + // The alloc-id appears in a sentence. + let re = Regex::new(r"\balloc([0-9]+)\b").unwrap(); + normalized = re + .replace_all(&normalized, |caps: &Captures<'_>| { + let index = caps.get(1).unwrap().as_str().to_string(); + let (index, _) = seen_allocs.insert_full(index); + format!("ALLOC{index}") + }) + .into_owned(); + } + // Custom normalization rules for rule in custom_rules { let re = Regex::new(&rule.0).expect("bad regex in custom normalization rule"); diff --git a/src/tools/miri/ci.sh b/src/tools/miri/ci.sh index 1b3ed796c66..eda1ceb4084 100755 --- a/src/tools/miri/ci.sh +++ b/src/tools/miri/ci.sh @@ -110,8 +110,8 @@ case $HOST_TARGET in MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic data_race env/var MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic - MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings - MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings + MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings wasm + MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings wasm MIRI_TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std # no_std embedded architecture MIRI_TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std # JSON target file ;; diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 66b729fb166..a74c69d52f2 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -14,7 +14,7 @@ use log::trace; use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir::{Mutability, RetagKind}; use rustc_middle::ty::{self, layout::HasParamEnv, Ty}; -use rustc_target::abi::{Abi, Align, Size}; +use rustc_target::abi::{Abi, Size}; use crate::borrow_tracker::{ stacked_borrows::diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder}, @@ -616,7 +616,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<' ) -> InterpResult<'tcx, Option<Provenance>> { let this = self.eval_context_mut(); // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). - this.check_ptr_access_align(place.ptr(), size, Align::ONE, CheckInAllocMsg::InboundsTest)?; + this.check_ptr_access(place.ptr(), size, CheckInAllocMsg::InboundsTest)?; // It is crucial that this gets called on all code paths, to ensure we track tag creation. let log_creation = |this: &MiriInterpCx<'mir, 'tcx>, diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index 6d4c573a35c..32d4d96b069 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -1,6 +1,6 @@ use log::trace; -use rustc_target::abi::{Abi, Align, Size}; +use rustc_target::abi::{Abi, Size}; use crate::borrow_tracker::{ AccessKind, GlobalState, GlobalStateInner, ProtectorKind, RetagFields, @@ -206,10 +206,9 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<' // Make sure the new permission makes sense as the initial permission of a fresh tag. assert!(new_perm.initial_state.is_initial()); // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). - this.check_ptr_access_align( + this.check_ptr_access( place.ptr(), ptr_size, - Align::ONE, CheckInAllocMsg::InboundsTest, )?; diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 24b9fa0776f..f3a8f1c25d7 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -1017,11 +1017,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> { // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( + this.check_ptr_align( place.ptr(), - place.layout.size, align, - CheckInAllocMsg::MemoryAccessTest, )?; // Ensure the allocation is mutable. Even failing (read-only) compare_exchange need mutable // memory on many targets (i.e., they segfault if taht memory is mapped read-only), and diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 4146a9b41ae..0dc472bc486 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -697,27 +697,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { let this = self.eval_context_ref(); let ptr = this.read_pointer(op)?; - - let mplace = MPlaceTy::from_aligned_ptr(ptr, layout); - - this.check_mplace(&mplace)?; - - Ok(mplace) - } - - /// Deref' a pointer *without* checking that the place is dereferenceable. - fn deref_pointer_unchecked( - &self, - val: &ImmTy<'tcx, Provenance>, - layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { - let this = self.eval_context_ref(); - let mut mplace = this.ref_to_mplace(val)?; - - mplace.layout = layout; - mplace.align = layout.align.abi; - - Ok(mplace) + Ok(this.ptr_to_mplace(ptr, layout)) } /// Calculates the MPlaceTy given the offset and layout of an access on an operand @@ -805,7 +785,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { loop { // FIXME: We are re-getting the allocation each time around the loop. // Would be nice if we could somehow "extend" an existing AllocRange. - let alloc = this.get_ptr_alloc(ptr.offset(len, this)?, size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result + let alloc = this.get_ptr_alloc(ptr.offset(len, this)?, size1)?.unwrap(); // not a ZST, so we will get a result let byte = alloc.read_integer(alloc_range(Size::ZERO, size1))?.to_u8()?; if byte == 0 { break; @@ -845,13 +825,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { fn read_wide_str(&self, mut ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx, Vec<u16>> { let this = self.eval_context_ref(); let size2 = Size::from_bytes(2); - let align2 = Align::from_bytes(2).unwrap(); + this.check_ptr_align(ptr, Align::from_bytes(2).unwrap())?; let mut wchars = Vec::new(); loop { // FIXME: We are re-getting the allocation each time around the loop. // Would be nice if we could somehow "extend" an existing AllocRange. - let alloc = this.get_ptr_alloc(ptr, size2, align2)?.unwrap(); // not a ZST, so we will get a result + let alloc = this.get_ptr_alloc(ptr, size2)?.unwrap(); // not a ZST, so we will get a result let wchar = alloc.read_integer(alloc_range(Size::ZERO, size2))?.to_u16()?; if wchar == 0 { break; @@ -887,8 +867,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Store the UTF-16 string. let size2 = Size::from_bytes(2); let this = self.eval_context_mut(); + this.check_ptr_align(ptr, Align::from_bytes(2).unwrap())?; let mut alloc = this - .get_ptr_alloc_mut(ptr, size2 * string_length, Align::from_bytes(2).unwrap())? + .get_ptr_alloc_mut(ptr, size2 * string_length)? .unwrap(); // not a ZST, so we will get a result for (offset, wchar) in wide_str.iter().copied().chain(iter::once(0x0000)).enumerate() { let offset = u64::try_from(offset).unwrap(); diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 930fa053d20..7241c243d8a 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -12,7 +12,6 @@ use rand::rngs::StdRng; use rand::SeedableRng; use rustc_ast::ast::Mutability; -use rustc_const_eval::const_eval::CheckAlignment; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; #[allow(unused)] use rustc_data_structures::static_assert_size; @@ -885,12 +884,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { const PANIC_ON_ALLOC_FAIL: bool = false; #[inline(always)] - fn enforce_alignment(ecx: &MiriInterpCx<'mir, 'tcx>) -> CheckAlignment { - if ecx.machine.check_alignment == AlignmentCheck::None { - CheckAlignment::No - } else { - CheckAlignment::Error - } + fn enforce_alignment(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool { + ecx.machine.check_alignment != AlignmentCheck::None } #[inline(always)] @@ -898,15 +893,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { ecx.machine.check_alignment == AlignmentCheck::Int } - fn alignment_check_failed( - _ecx: &InterpCx<'mir, 'tcx, Self>, - has: Align, - required: Align, - _check: CheckAlignment, - ) -> InterpResult<'tcx, ()> { - throw_ub!(AlignmentCheckFailed { has, required }) - } - #[inline(always)] fn enforce_validity(ecx: &MiriInterpCx<'mir, 'tcx>, _layout: TyAndLayout<'tcx>) -> bool { ecx.machine.validate @@ -1001,6 +987,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { ecx.binary_ptr_op(bin_op, left, right) } + #[inline(always)] + fn generate_nan<F1: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F2>, F2: rustc_apfloat::Float>( + ecx: &InterpCx<'mir, 'tcx, Self>, + inputs: &[F1], + ) -> F2 { + ecx.generate_nan(inputs) + } + fn thread_local_static_base_pointer( ecx: &mut MiriInterpCx<'mir, 'tcx>, def_id: DefId, @@ -1291,6 +1285,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { // We do need to write `uninit` so that even after the call ends, the former contents of // this place cannot be observed any more. We do the write after retagging so that for // Tree Borrows, this is considered to activate the new tag. + // Conveniently this also ensures that the place actually points to suitable memory. ecx.write_uninit(&protected_place)?; // Now we throw away the protected place, ensuring its tag is never used again. Ok(()) diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs index 1faf8f9fc12..e5a437f95f0 100644 --- a/src/tools/miri/src/operator.rs +++ b/src/tools/miri/src/operator.rs @@ -1,20 +1,16 @@ +use std::iter; + use log::trace; +use rand::{seq::IteratorRandom, Rng}; +use rustc_apfloat::{Float, FloatConvert}; use rustc_middle::mir; use rustc_target::abi::Size; use crate::*; -pub trait EvalContextExt<'tcx> { - fn binary_ptr_op( - &self, - bin_op: mir::BinOp, - left: &ImmTy<'tcx, Provenance>, - right: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, (ImmTy<'tcx, Provenance>, bool)>; -} - -impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> { +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { fn binary_ptr_op( &self, bin_op: mir::BinOp, @@ -23,12 +19,13 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> { ) -> InterpResult<'tcx, (ImmTy<'tcx, Provenance>, bool)> { use rustc_middle::mir::BinOp::*; + let this = self.eval_context_ref(); trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); Ok(match bin_op { Eq | Ne | Lt | Le | Gt | Ge => { assert_eq!(left.layout.abi, right.layout.abi); // types an differ, e.g. fn ptrs with different `for` - let size = self.pointer_size(); + let size = this.pointer_size(); // Just compare the bits. ScalarPairs are compared lexicographically. // We thus always compare pairs and simply fill scalars up with 0. let left = match **left { @@ -50,7 +47,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> { Ge => left >= right, _ => bug!(), }; - (ImmTy::from_bool(res, *self.tcx), false) + (ImmTy::from_bool(res, *this.tcx), false) } // Some more operations are possible with atomics. @@ -58,26 +55,67 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> { Add | Sub | BitOr | BitAnd | BitXor => { assert!(left.layout.ty.is_unsafe_ptr()); assert!(right.layout.ty.is_unsafe_ptr()); - let ptr = left.to_scalar().to_pointer(self)?; + let ptr = left.to_scalar().to_pointer(this)?; // We do the actual operation with usize-typed scalars. - let left = ImmTy::from_uint(ptr.addr().bytes(), self.machine.layouts.usize); + let left = ImmTy::from_uint(ptr.addr().bytes(), this.machine.layouts.usize); let right = ImmTy::from_uint( - right.to_scalar().to_target_usize(self)?, - self.machine.layouts.usize, + right.to_scalar().to_target_usize(this)?, + this.machine.layouts.usize, ); - let (result, overflowing) = self.overflowing_binary_op(bin_op, &left, &right)?; + let (result, overflowing) = this.overflowing_binary_op(bin_op, &left, &right)?; // Construct a new pointer with the provenance of `ptr` (the LHS). let result_ptr = Pointer::new( ptr.provenance, - Size::from_bytes(result.to_scalar().to_target_usize(self)?), + Size::from_bytes(result.to_scalar().to_target_usize(this)?), ); ( - ImmTy::from_scalar(Scalar::from_maybe_pointer(result_ptr, self), left.layout), + ImmTy::from_scalar(Scalar::from_maybe_pointer(result_ptr, this), left.layout), overflowing, ) } - _ => span_bug!(self.cur_span(), "Invalid operator on pointers: {:?}", bin_op), + _ => span_bug!(this.cur_span(), "Invalid operator on pointers: {:?}", bin_op), }) } + + fn generate_nan<F1: Float + FloatConvert<F2>, F2: Float>(&self, inputs: &[F1]) -> F2 { + /// Make the given NaN a signaling NaN. + /// Returns `None` if this would not result in a NaN. + fn make_signaling<F: Float>(f: F) -> Option<F> { + // The quiet/signaling bit is the leftmost bit in the mantissa. + // That's position `PRECISION-1`, since `PRECISION` includes the fixed leading 1 bit, + // and then we subtract 1 more since this is 0-indexed. + let quiet_bit_mask = 1 << (F::PRECISION - 2); + // Unset the bit. Double-check that this wasn't the last bit set in the payload. + // (which would turn the NaN into an infinity). + let f = F::from_bits(f.to_bits() & !quiet_bit_mask); + if f.is_nan() { Some(f) } else { None } + } + + let this = self.eval_context_ref(); + let mut rand = this.machine.rng.borrow_mut(); + // Assemble an iterator of possible NaNs: preferred, quieting propagation, unchanged propagation. + // On some targets there are more possibilities; for now we just generate those options that + // are possible everywhere. + let preferred_nan = F2::qnan(Some(0)); + let nans = iter::once(preferred_nan) + .chain(inputs.iter().filter(|f| f.is_nan()).map(|&f| { + // Regular apfloat cast is quieting. + f.convert(&mut false).value + })) + .chain(inputs.iter().filter(|f| f.is_signaling()).filter_map(|&f| { + let f: F2 = f.convert(&mut false).value; + // We have to de-quiet this again for unchanged propagation. + make_signaling(f) + })); + // Pick one of the NaNs. + let nan = nans.choose(&mut *rand).unwrap(); + // Non-deterministically flip the sign. + if rand.gen() { + // This will properly flip even for NaN. + -nan + } else { + nan + } + } } diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 3462f03c30f..0f4be5e154a 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -807,9 +807,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.mem_copy( ptr_src, - Align::ONE, ptr_dest, - Align::ONE, Size::from_bytes(n), true, )?; @@ -830,9 +828,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let n = this.read_c_str(ptr_src)?.len().checked_add(1).unwrap(); this.mem_copy( ptr_src, - Align::ONE, ptr_dest, - Align::ONE, Size::from_bytes(n), true, )?; diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 1014a61b75e..b0592b68a9e 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -13,7 +13,7 @@ use log::trace; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::TyCtxt; -use rustc_target::abi::{Align, Size}; +use rustc_target::abi::Size; use crate::shims::os_str::bytes_to_os_str; use crate::*; @@ -756,10 +756,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { trace!("Reading from FD {}, size {}", fd, count); // Check that the *entire* buffer is actually valid memory. - this.check_ptr_access_align( + this.check_ptr_access( buf, Size::from_bytes(count), - Align::ONE, CheckInAllocMsg::MemoryAccessTest, )?; @@ -810,10 +809,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Isolation check is done via `FileDescriptor` trait. // Check that the *entire* buffer is actually valid memory. - this.check_ptr_access_align( + this.check_ptr_access( buf, Size::from_bytes(count), - Align::ONE, CheckInAllocMsg::MemoryAccessTest, )?; @@ -1370,7 +1368,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ("d_reclen", size.into()), ("d_type", file_type.into()), ], - &MPlaceTy::from_aligned_ptr(entry, dirent64_layout), + &this.ptr_to_mplace(entry, dirent64_layout), )?; let name_ptr = entry.offset(Size::from_bytes(d_name_offset), this)?; diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs index 7d15abfbfb2..17803b52baf 100644 --- a/src/tools/miri/src/shims/unix/linux/sync.rs +++ b/src/tools/miri/src/shims/unix/linux/sync.rs @@ -34,7 +34,7 @@ pub fn futex<'tcx>( let thread = this.get_active_thread(); // This is a vararg function so we have to bring our own type for this pointer. - let addr = MPlaceTy::from_aligned_ptr(addr, this.machine.layouts.i32); + let addr = this.ptr_to_mplace(addr, this.machine.layouts.i32); let addr_usize = addr.ptr().addr().bytes(); let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG"); @@ -85,9 +85,8 @@ pub fn futex<'tcx>( return Ok(()); } - // `read_timespec` will check the place when it is not null. - let timeout = this.deref_pointer_unchecked( - &this.read_immediate(&args[3])?, + let timeout = this.deref_pointer_as( + &args[3], this.libc_ty_layout("timespec"), )?; let timeout_time = if this.ptr_is_null(timeout.ptr())? { diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs index c8c8173aa51..5e46404e7f1 100644 --- a/src/tools/miri/src/shims/windows/sync.rs +++ b/src/tools/miri/src/shims/windows/sync.rs @@ -322,8 +322,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let layout = this.machine.layouts.uint(size).unwrap(); let futex_val = this - .read_scalar_atomic(&MPlaceTy::from_aligned_ptr(ptr, layout), AtomicReadOrd::Relaxed)?; - let compare_val = this.read_scalar(&MPlaceTy::from_aligned_ptr(compare, layout))?; + .read_scalar_atomic(&this.ptr_to_mplace(ptr, layout), AtomicReadOrd::Relaxed)?; + let compare_val = this.read_scalar(&this.ptr_to_mplace(compare, layout))?; if futex_val == compare_val { // If the values are the same, we have to block. diff --git a/src/tools/miri/src/shims/x86/sse3.rs b/src/tools/miri/src/shims/x86/sse3.rs index a41de5dbf7e..252384a0aa9 100644 --- a/src/tools/miri/src/shims/x86/sse3.rs +++ b/src/tools/miri/src/shims/x86/sse3.rs @@ -1,6 +1,5 @@ use rustc_middle::mir; use rustc_span::Symbol; -use rustc_target::abi::Align; use rustc_target::spec::abi::Abi; use super::horizontal_bin_op; @@ -76,9 +75,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: this.mem_copy( src_ptr, - Align::ONE, dest.ptr(), - Align::ONE, dest.layout.size, /*nonoverlapping*/ true, )?; diff --git a/src/tools/miri/tests/compiletest.rs b/src/tools/miri/tests/compiletest.rs index c2dccf81377..dbf559631ea 100644 --- a/src/tools/miri/tests/compiletest.rs +++ b/src/tools/miri/tests/compiletest.rs @@ -181,6 +181,7 @@ regexes! { r"0x[0-9a-fA-F]+[0-9a-fA-F]{2,2}" => "$$HEX", // erase specific alignments "alignment [0-9]+" => "alignment ALIGN", + "[0-9]+ byte alignment but found [0-9]+" => "ALIGN byte alignment but found ALIGN", // erase thread caller ids r"call [0-9]+" => "call ID", // erase platform module paths diff --git a/src/tools/miri/tests/fail-dep/shims/mmap_use_after_munmap.stderr b/src/tools/miri/tests/fail-dep/shims/mmap_use_after_munmap.stderr index 44e122330bc..35d26972839 100644 --- a/src/tools/miri/tests/fail-dep/shims/mmap_use_after_munmap.stderr +++ b/src/tools/miri/tests/fail-dep/shims/mmap_use_after_munmap.stderr @@ -13,11 +13,11 @@ LL | libc::munmap(ptr, 4096); = note: BACKTRACE: = note: inside `main` at $DIR/mmap_use_after_munmap.rs:LL:CC -error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling --> $DIR/mmap_use_after_munmap.rs:LL:CC | LL | let _x = *(ptr as *mut u8); - | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling + | ^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/alloc/reallocate-change-alloc.stderr b/src/tools/miri/tests/fail/alloc/reallocate-change-alloc.stderr index ff4cb399157..d4e907bd067 100644 --- a/src/tools/miri/tests/fail/alloc/reallocate-change-alloc.stderr +++ b/src/tools/miri/tests/fail/alloc/reallocate-change-alloc.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling --> $DIR/reallocate-change-alloc.rs:LL:CC | LL | let _z = *x; - | ^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling + | ^^ memory access failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/concurrency/thread_local_static_dealloc.stderr b/src/tools/miri/tests/fail/concurrency/thread_local_static_dealloc.stderr index 0cb8aa29001..7069e8cccfe 100644 --- a/src/tools/miri/tests/fail/concurrency/thread_local_static_dealloc.stderr +++ b/src/tools/miri/tests/fail/concurrency/thread_local_static_dealloc.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling --> $DIR/thread_local_static_dealloc.rs:LL:CC | LL | let _val = *dangling_ptr.0; - | ^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling + | ^^^^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/const-ub-checks.stderr b/src/tools/miri/tests/fail/const-ub-checks.stderr index d2b9018cd4b..29acc642c14 100644 --- a/src/tools/miri/tests/fail/const-ub-checks.stderr +++ b/src/tools/miri/tests/fail/const-ub-checks.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-ub-checks.rs:LL:CC | LL | ptr.read(); - | ^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^^^^^^^^^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required note: erroneous constant encountered --> $DIR/const-ub-checks.rs:LL:CC diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs deleted file mode 100644 index 49f3ae306a0..00000000000 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs +++ /dev/null @@ -1,12 +0,0 @@ -// Make sure we find these even with many checks disabled. -//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation -use std::ptr; - -fn main() { - let p = { - let b = Box::new(42); - &*b as *const i32 - }; - let x = unsafe { ptr::addr_of!(*p) }; //~ ERROR: has been freed - panic!("this should never print: {:?}", x); -} diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr deleted file mode 100644 index 6a3efbdd3dd..00000000000 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling - --> $DIR/dangling_pointer_addr_of.rs:LL:CC - | -LL | let x = unsafe { ptr::addr_of!(*p) }; - | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling - | - = 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 -help: ALLOC was allocated here: - --> $DIR/dangling_pointer_addr_of.rs:LL:CC - | -LL | let b = Box::new(42); - | ^^^^^^^^^^^^ -help: ALLOC was deallocated here: - --> $DIR/dangling_pointer_addr_of.rs:LL:CC - | -LL | }; - | ^ - = note: BACKTRACE (of the first span): - = note: inside `main` at RUSTLIB/core/src/ptr/mod.rs:LL:CC - = note: this error originates in the macro `ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref.stderr index fad4b4be28c..33d640759fd 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_deref.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling --> $DIR/dangling_pointer_deref.rs:LL:CC | LL | let x = unsafe { *p }; - | ^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling + | ^^ memory access failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore.rs index 4c641243950..22a5ce8ea74 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore.rs @@ -4,10 +4,9 @@ fn main() { let p = { let b = Box::new(42); - &*b as *const i32 + &*b as *const i32 as *const (u8, u8, u8, u8) }; unsafe { - let _ = *p; //~ ERROR: has been freed + let _ = (*p).1; //~ ERROR: out-of-bounds pointer arithmetic } - panic!("this should never print"); } diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore.stderr index 1de6465802b..20f3a25a0b1 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling --> $DIR/dangling_pointer_project_underscore.rs:LL:CC | -LL | let _ = *p; - | ^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling +LL | let _ = (*p).1; + | ^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_primitive.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_primitive.stderr index bdc9c31db40..c2a73bfbcb2 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_primitive.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_primitive.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling --> $DIR/dangling_primitive.rs:LL:CC | LL | dbg!(*ptr); - | ^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling + | ^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_zst_deref.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_zst_deref.stderr index bf6ee775e94..d8cb691e553 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_zst_deref.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_zst_deref.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling --> $DIR/dangling_zst_deref.rs:LL:CC | LL | let _x = unsafe { *p }; - | ^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling + | ^^ memory access failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr b/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr index 3e2c3903b7e..f11863b5067 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: 0x10[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: out-of-bounds pointer use: 0x10[noalloc] is a dangling pointer (it has no provenance) --> $DIR/deref-invalid-ptr.rs:LL:CC | LL | let _y = unsafe { &*x as *const u32 }; - | ^^^ dereferencing pointer failed: 0x10[noalloc] is a dangling pointer (it has no provenance) + | ^^^ out-of-bounds pointer use: 0x10[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/deref-partially-dangling.rs b/src/tools/miri/tests/fail/dangling_pointers/deref-partially-dangling.rs deleted file mode 100644 index 27040c26dc2..00000000000 --- a/src/tools/miri/tests/fail/dangling_pointers/deref-partially-dangling.rs +++ /dev/null @@ -1,8 +0,0 @@ -// Deref a raw ptr to access a field of a large struct, where the field -// is allocated but not the entire struct is. -fn main() { - let x = (1, 13); - let xptr = &x as *const _ as *const (i32, i32, i32); - let val = unsafe { (*xptr).1 }; //~ ERROR: pointer to 12 bytes starting at offset 0 is out-of-bounds - assert_eq!(val, 13); -} diff --git a/src/tools/miri/tests/fail/dangling_pointers/deref-partially-dangling.stderr b/src/tools/miri/tests/fail/dangling_pointers/deref-partially-dangling.stderr deleted file mode 100644 index 92b1fcb1145..00000000000 --- a/src/tools/miri/tests/fail/dangling_pointers/deref-partially-dangling.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 8, so pointer to 12 bytes starting at offset 0 is out-of-bounds - --> $DIR/deref-partially-dangling.rs:LL:CC - | -LL | let val = unsafe { (*xptr).1 }; - | ^^^^^^^^^ dereferencing pointer failed: ALLOC has size 8, so pointer to 12 bytes starting at offset 0 is out-of-bounds - | - = 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 -help: ALLOC was allocated here: - --> $DIR/deref-partially-dangling.rs:LL:CC - | -LL | let x = (1, 13); - | ^ - = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/deref-partially-dangling.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_box.rs b/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_box.rs new file mode 100644 index 00000000000..0d4506115c7 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_box.rs @@ -0,0 +1,16 @@ +// Should be caught even without retagging +//@compile-flags: -Zmiri-disable-stacked-borrows +#![feature(strict_provenance)] +use std::ptr::{addr_of_mut, self}; + +// Deref'ing a dangling raw pointer is fine, but for a dangling box it is not. +// We do this behind a pointer indirection to potentially fool validity checking. +// (This test relies on the `deref_copy` pass that lowers `**ptr` to materialize the intermediate pointer.) + +fn main() { + let mut inner = ptr::invalid::<i32>(24); + let outer = addr_of_mut!(inner).cast::<Box<i32>>(); + // Now `outer` is a pointer to a dangling reference. + // Deref'ing that should be UB. + let _val = unsafe { addr_of_mut!(**outer) }; //~ERROR: dangling box +} diff --git a/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_box.stderr b/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_box.stderr new file mode 100644 index 00000000000..64d6d36c2c0 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_box.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: constructing invalid value: encountered a dangling box (0x18[noalloc] has no provenance) + --> $DIR/deref_dangling_box.rs:LL:CC + | +LL | let _val = unsafe { addr_of_mut!(**outer) }; + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (0x18[noalloc] has no provenance) + | + = 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 RUSTLIB/core/src/ptr/mod.rs:LL:CC + = note: this error originates in the macro `addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_ref.rs b/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_ref.rs new file mode 100644 index 00000000000..37da2e96758 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_ref.rs @@ -0,0 +1,16 @@ +// Should be caught even without retagging +//@compile-flags: -Zmiri-disable-stacked-borrows +#![feature(strict_provenance)] +use std::ptr::{addr_of_mut, self}; + +// Deref'ing a dangling raw pointer is fine, but for a dangling reference it is not. +// We do this behind a pointer indirection to potentially fool validity checking. +// (This test relies on the `deref_copy` pass that lowers `**ptr` to materialize the intermediate pointer.) + +fn main() { + let mut inner = ptr::invalid::<i32>(24); + let outer = addr_of_mut!(inner).cast::<&'static mut i32>(); + // Now `outer` is a pointer to a dangling reference. + // Deref'ing that should be UB. + let _val = unsafe { addr_of_mut!(**outer) }; //~ERROR: dangling reference +} diff --git a/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_ref.stderr b/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_ref.stderr new file mode 100644 index 00000000000..244e3f4b659 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/deref_dangling_ref.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: constructing invalid value: encountered a dangling reference (0x18[noalloc] has no provenance) + --> $DIR/deref_dangling_ref.rs:LL:CC + | +LL | let _val = unsafe { addr_of_mut!(**outer) }; + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (0x18[noalloc] has no provenance) + | + = 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 RUSTLIB/core/src/ptr/mod.rs:LL:CC + = note: this error originates in the macro `addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/dangling_pointers/dyn_size.rs b/src/tools/miri/tests/fail/dangling_pointers/dyn_size.rs index 87ca8a6077c..fa01bbc19c9 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dyn_size.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/dyn_size.rs @@ -1,13 +1,13 @@ -// should find the bug even without these -//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +// should find the bug even without retagging +//@compile-flags: -Zmiri-disable-stacked-borrows struct SliceWithHead(u8, [u8]); fn main() { let buf = [0u32; 1]; // We craft a wide pointer `*const SliceWithHead` such that the unsized tail is only partially allocated. - // That should be UB, as the reference is not fully dereferencable. + // That should lead to UB, as the reference is not fully dereferenceable. let ptr: *const SliceWithHead = unsafe { std::mem::transmute((&buf, 4usize)) }; // Re-borrow that. This should be UB. - let _ptr = unsafe { &*ptr }; //~ ERROR: pointer to 5 bytes starting at offset 0 is out-of-bounds + let _ptr = unsafe { &*ptr }; //~ ERROR: encountered a dangling reference (going beyond the bounds of its allocation) } diff --git a/src/tools/miri/tests/fail/dangling_pointers/dyn_size.stderr b/src/tools/miri/tests/fail/dangling_pointers/dyn_size.stderr index 95a50bc8750..4d45630e1ba 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dyn_size.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dyn_size.stderr @@ -1,17 +1,12 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds +error: Undefined Behavior: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) --> $DIR/dyn_size.rs:LL:CC | LL | let _ptr = unsafe { &*ptr }; - | ^^^^^ dereferencing pointer failed: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds + | ^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information -help: ALLOC was allocated here: - --> $DIR/dyn_size.rs:LL:CC - | -LL | let buf = [0u32; 1]; - | ^^^ - = note: BACKTRACE (of the first span): + = note: BACKTRACE: = note: inside `main` at $DIR/dyn_size.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/dangling_pointers/maybe_null_pointer_deref_zst.stderr b/src/tools/miri/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr index 3e492a170c8..895d4c7fce2 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds +error: Undefined Behavior: memory access failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds --> $DIR/maybe_null_pointer_deref_zst.rs:LL:CC | LL | let _x: () = unsafe { *ptr }; - | ^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds + | ^^^^ memory access failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr b/src/tools/miri/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr index c41c20aaf4a..6cc05758b7e 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds +error: Undefined Behavior: memory access failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds --> $DIR/maybe_null_pointer_write_zst.rs:LL:CC | LL | unsafe { *ptr = zst_val }; - | ^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds + | ^^^^^^^^^^^^^^ memory access failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr index 64dcaa45484..727c724552d 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance) --> $DIR/null_pointer_deref.rs:LL:CC | LL | let x: i32 = unsafe { *std::ptr::null() }; - | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref_zst.rs b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref_zst.rs index 4cb805db095..f8af43ff352 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref_zst.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref_zst.rs @@ -1,5 +1,5 @@ #[allow(deref_nullptr)] fn main() { - let x: () = unsafe { *std::ptr::null() }; //~ ERROR: dereferencing pointer failed: null pointer is a dangling pointer + let x: () = unsafe { *std::ptr::null() }; //~ ERROR: memory access failed: null pointer is a dangling pointer panic!("this should never print: {:?}", x); } diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr index 301578a4f5f..9f93a0e18a2 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance) --> $DIR/null_pointer_deref_zst.rs:LL:CC | LL | let x: () = unsafe { *std::ptr::null() }; - | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr index 0e5858a96f9..6974b997725 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance) --> $DIR/null_pointer_write.rs:LL:CC | LL | unsafe { *std::ptr::null_mut() = 0i32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write_zst.rs b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write_zst.rs index ec34c631a46..edd6c8fadce 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write_zst.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write_zst.rs @@ -4,5 +4,5 @@ fn main() { // Also not assigning directly as that's array initialization, not assignment. let zst_val = [1u8; 0]; unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) }; - //~^ERROR: dereferencing pointer failed: null pointer is a dangling pointer + //~^ERROR: memory access failed: null pointer is a dangling pointer } diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write_zst.stderr b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write_zst.stderr index a4e0ebe38f6..2953d85c25f 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write_zst.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write_zst.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance) --> $DIR/null_pointer_write_zst.rs:LL:CC | LL | unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.rs new file mode 100644 index 00000000000..b596ba428ae --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.rs @@ -0,0 +1,12 @@ +// Make sure we find these even with many checks disabled. +//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +use std::ptr::addr_of; + +fn main() { + let v = 0u32; + let ptr = addr_of!(v).cast::<(u32, u32, u32)>(); + unsafe { + let _field = addr_of!((*ptr).1); // still just in-bounds + let _field = addr_of!((*ptr).2); //~ ERROR: out-of-bounds pointer arithmetic + } +} diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr new file mode 100644 index 00000000000..1c105991015 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr @@ -0,0 +1,21 @@ +error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds + --> $DIR/out_of_bounds_project.rs:LL:CC + | +LL | let _field = addr_of!((*ptr).2); + | ^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds + | + = 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 +help: ALLOC was allocated here: + --> $DIR/out_of_bounds_project.rs:LL:CC + | +LL | let v = 0u32; + | ^ + = note: BACKTRACE (of the first span): + = note: inside `main` at RUSTLIB/core/src/ptr/mod.rs:LL:CC + = note: this error originates in the macro `addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs new file mode 100644 index 00000000000..f6b8a1ad55b --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs @@ -0,0 +1,8 @@ +#![feature(pointer_byte_offsets)] + +fn main() { + let v: Vec<u16> = vec![1, 2]; + // This read is also misaligned. We make sure that the OOB message has priority. + let x = unsafe { *v.as_ptr().wrapping_byte_add(5) }; //~ ERROR: out-of-bounds + panic!("this should never print: {}", x); +} diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read1.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr index 7d2aed371bd..38d691f4c01 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read1.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr @@ -1,18 +1,18 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 2, so pointer to 1 byte starting at offset 5 is out-of-bounds - --> $DIR/out_of_bounds_read1.rs:LL:CC +error: Undefined Behavior: memory access failed: ALLOC has size 4, so pointer to 2 bytes starting at offset 5 is out-of-bounds + --> $DIR/out_of_bounds_read.rs:LL:CC | -LL | let x = unsafe { *v.as_ptr().wrapping_offset(5) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 2, so pointer to 1 byte starting at offset 5 is out-of-bounds +LL | let x = unsafe { *v.as_ptr().wrapping_byte_add(5) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has size 4, so pointer to 2 bytes starting at offset 5 is out-of-bounds | = 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 help: ALLOC was allocated here: - --> $DIR/out_of_bounds_read1.rs:LL:CC + --> $DIR/out_of_bounds_read.rs:LL:CC | -LL | let v: Vec<u8> = vec![1, 2]; - | ^^^^^^^^^^ +LL | let v: Vec<u16> = vec![1, 2]; + | ^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/out_of_bounds_read1.rs:LL:CC + = note: inside `main` at $DIR/out_of_bounds_read.rs:LL:CC = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read1.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read1.rs deleted file mode 100644 index 58a64eecace..00000000000 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read1.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - let v: Vec<u8> = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR: out-of-bounds - panic!("this should never print: {}", x); -} diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read2.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read2.rs deleted file mode 100644 index 58a64eecace..00000000000 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read2.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - let v: Vec<u8> = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR: out-of-bounds - panic!("this should never print: {}", x); -} diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs new file mode 100644 index 00000000000..4ead91744c8 --- /dev/null +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs @@ -0,0 +1,7 @@ +#![feature(pointer_byte_offsets)] + +fn main() { + let mut v: Vec<u16> = vec![1, 2]; + // This read is also misaligned. We make sure that the OOB message has priority. + unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 }; //~ ERROR: out-of-bounds +} diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read2.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr index 69a8498f097..9669614d47f 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read2.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr @@ -1,18 +1,18 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 2, so pointer to 1 byte starting at offset 5 is out-of-bounds - --> $DIR/out_of_bounds_read2.rs:LL:CC +error: Undefined Behavior: memory access failed: ALLOC has size 4, so pointer to 2 bytes starting at offset 5 is out-of-bounds + --> $DIR/out_of_bounds_write.rs:LL:CC | -LL | let x = unsafe { *v.as_ptr().wrapping_offset(5) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 2, so pointer to 1 byte starting at offset 5 is out-of-bounds +LL | unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has size 4, so pointer to 2 bytes starting at offset 5 is out-of-bounds | = 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 help: ALLOC was allocated here: - --> $DIR/out_of_bounds_read2.rs:LL:CC + --> $DIR/out_of_bounds_write.rs:LL:CC | -LL | let v: Vec<u8> = vec![1, 2]; - | ^^^^^^^^^^ +LL | let mut v: Vec<u16> = vec![1, 2]; + | ^^^^^^^^^^ = note: BACKTRACE (of the first span): - = note: inside `main` at $DIR/out_of_bounds_read2.rs:LL:CC + = note: inside `main` at $DIR/out_of_bounds_write.rs:LL:CC = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/dangling_pointers/stack_temporary.stderr b/src/tools/miri/tests/fail/dangling_pointers/stack_temporary.stderr index 4d2dfe28aed..28a9207cff3 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/stack_temporary.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/stack_temporary.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling --> $DIR/stack_temporary.rs:LL:CC | LL | let val = *x; - | ^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling + | ^^ memory access failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr index 6c41add60ef..9b47655a047 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: out-of-bounds pointer use: $HEX[noalloc] is a dangling pointer (it has no provenance) --> $DIR/storage_dead_dangling.rs:LL:CC | LL | let _ = unsafe { &mut *(LEAK as *mut i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr b/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr index 658fb228174..802995aea50 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: 0x2c[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: 0x2c[noalloc] is a dangling pointer (it has no provenance) --> $DIR/wild_pointer_deref.rs:LL:CC | LL | let x = unsafe { *p }; - | ^^ dereferencing pointer failed: 0x2c[noalloc] is a dangling pointer (it has no provenance) + | ^^ memory access failed: 0x2c[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr index 810e48d59c6..792faf8f5d1 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling --> $DIR/dealloc_read_race2.rs:LL:CC | LL | *ptr.0 - | ^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling + | ^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr index 7d672cd4d62..64f654402d7 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling --> $DIR/dealloc_write_race2.rs:LL:CC | LL | *ptr.0 = 2; - | ^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling + | ^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/environ-gets-deallocated.stderr b/src/tools/miri/tests/fail/environ-gets-deallocated.stderr index 6332846d5d8..dd7420906d3 100644 --- a/src/tools/miri/tests/fail/environ-gets-deallocated.stderr +++ b/src/tools/miri/tests/fail/environ-gets-deallocated.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling --> $DIR/environ-gets-deallocated.rs:LL:CC | LL | let _y = unsafe { *pointer }; - | ^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling + | ^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/function_pointers/deref_fn_ptr.rs b/src/tools/miri/tests/fail/function_pointers/deref_fn_ptr.rs index f071b63902f..3510f41361a 100644 --- a/src/tools/miri/tests/fail/function_pointers/deref_fn_ptr.rs +++ b/src/tools/miri/tests/fail/function_pointers/deref_fn_ptr.rs @@ -2,7 +2,7 @@ fn f() {} fn main() { let x: u8 = unsafe { - *std::mem::transmute::<fn(), *const u8>(f) //~ ERROR: out-of-bounds + *std::mem::transmute::<fn(), *const u8>(f) //~ ERROR: contains a function }; panic!("this should never print: {}", x); } diff --git a/src/tools/miri/tests/fail/function_pointers/deref_fn_ptr.stderr b/src/tools/miri/tests/fail/function_pointers/deref_fn_ptr.stderr index 7ce0b08695e..954bb8721e7 100644 --- a/src/tools/miri/tests/fail/function_pointers/deref_fn_ptr.stderr +++ b/src/tools/miri/tests/fail/function_pointers/deref_fn_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds +error: Undefined Behavior: accessing ALLOC which contains a function --> $DIR/deref_fn_ptr.rs:LL:CC | LL | *std::mem::transmute::<fn(), *const u8>(f) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing ALLOC which contains a function | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/generator-pinned-moved.stderr b/src/tools/miri/tests/fail/generator-pinned-moved.stderr index 4cb8450c6d5..8ad0ce8cc32 100644 --- a/src/tools/miri/tests/fail/generator-pinned-moved.stderr +++ b/src/tools/miri/tests/fail/generator-pinned-moved.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling --> $DIR/generator-pinned-moved.rs:LL:CC | LL | *num += 1; - | ^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling + | ^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr b/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr index f82b30a9633..f3bd275b027 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds +error: Undefined Behavior: memory access failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds --> $DIR/simd-gather.rs:LL:CC | LL | let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr b/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr index 5beee034db2..1720a24aa13 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds +error: Undefined Behavior: memory access failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds --> $DIR/simd-scatter.rs:LL:CC | LL | / Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked( @@ -7,7 +7,7 @@ LL | | &mut vec, LL | | Mask::splat(true), LL | | idxs, LL | | ); - | |_________^ dereferencing pointer failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds + | |_________^ memory access failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr b/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr index 06e5ede8c77..8fafc7e82c9 100644 --- a/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr +++ b/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance) --> $DIR/pointer_partial_overwrite.rs:LL:CC | LL | let x = *p; - | ^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) + | ^^ memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/provenance_transmute.rs b/src/tools/miri/tests/fail/provenance/provenance_transmute.rs index abcfc060e52..bc5dd53dcf5 100644 --- a/src/tools/miri/tests/fail/provenance/provenance_transmute.rs +++ b/src/tools/miri/tests/fail/provenance/provenance_transmute.rs @@ -13,7 +13,7 @@ unsafe fn deref(left: *const u8, right: *const u8) { // The compiler is allowed to replace `left_int` by `right_int` here... let left_ptr: *const u8 = mem::transmute(left_int); // ...which however means here it could be dereferencing the wrong pointer. - let _val = *left_ptr; //~ERROR: dereferencing pointer failed + let _val = *left_ptr; //~ERROR: dangling pointer } } diff --git a/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr b/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr index 042d8cd4afe..319517d062b 100644 --- a/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr +++ b/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance) --> $DIR/provenance_transmute.rs:LL:CC | LL | let _val = *left_ptr; - | ^^^^^^^^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^ memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr b/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr index 4ad885ddabd..9ebabfb129c 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr +++ b/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance) --> $DIR/ptr_int_unexposed.rs:LL:CC | LL | assert_eq!(unsafe { *ptr }, 3); - | ^^^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) + | ^^^^ memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr b/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr index ef9dcad97cb..50ceae7cfda 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr +++ b/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance) --> $DIR/ptr_invalid.rs:LL:CC | LL | let _val = unsafe { *xptr_invalid }; - | ^^^^^^^^^^^^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^ memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/rc_as_ptr.stderr b/src/tools/miri/tests/fail/rc_as_ptr.stderr index 460ed977137..eb522b2bc0c 100644 --- a/src/tools/miri/tests/fail/rc_as_ptr.stderr +++ b/src/tools/miri/tests/fail/rc_as_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: out-of-bounds pointer use: ALLOC has been freed, so this pointer is dangling --> $DIR/rc_as_ptr.rs:LL:CC | LL | assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/reading_half_a_pointer.stderr b/src/tools/miri/tests/fail/reading_half_a_pointer.stderr index 61a7161a98b..df4adb5ead7 100644 --- a/src/tools/miri/tests/fail/reading_half_a_pointer.stderr +++ b/src/tools/miri/tests/fail/reading_half_a_pointer.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance) --> $DIR/reading_half_a_pointer.rs:LL:CC | LL | let _val = *x; - | ^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) + | ^^ memory access failed: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/unaligned_pointers/alignment.stderr b/src/tools/miri/tests/fail/unaligned_pointers/alignment.stderr index bbebe3b89fd..5fdec1dc74c 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/alignment.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/alignment.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required --> $DIR/alignment.rs:LL:CC | LL | *(x_ptr as *mut u32) = 42; *(x_ptr.add(1) as *mut u32) = 42; - | ^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.rs b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.rs index d8cab68ac5d..d71d5954a40 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.rs +++ b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.rs @@ -13,7 +13,7 @@ struct PartialDrop { b: u8, } -//@error-in-other-file: /alignment 2 is required/ +//@error-in-other-file: /required 2 byte alignment/ fn main() { unsafe { // Create an unaligned pointer diff --git a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr index ef20b43c118..db35a20ee22 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) --> RUSTLIB/core/src/ptr/mod.rs:LL:CC | LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.stderr b/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.stderr index 503721b9551..cfb43ae891f 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required 256 byte alignment but found $ALIGN) +error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) --> $DIR/dyn_alignment.rs:LL:CC | LL | let _ptr = &*ptr; - | ^^^^^ constructing invalid value: encountered an unaligned reference (required 256 byte alignment but found $ALIGN) + | ^^^^^ constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.rs b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.rs index fa1812adc29..114ab5479b4 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.rs +++ b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.rs @@ -8,7 +8,7 @@ pub struct S { } unsafe fn foo(x: *const S) -> u8 { - unsafe { (*x).x } //~ERROR: accessing memory with alignment 1, but alignment 4 is required + unsafe { (*x).x } //~ERROR: based on pointer with alignment 1, but alignment 4 is required } fn main() { diff --git a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.stderr b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.stderr index 0f030a6e27c..2ffbc2a434e 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required --> $DIR/field_requires_parent_struct_alignment.rs:LL:CC | LL | unsafe { (*x).x } - | ^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^^^^^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs new file mode 100644 index 00000000000..8459c64ed2d --- /dev/null +++ b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.rs @@ -0,0 +1,30 @@ +/// This tests that when a field sits at a well-aligned offset, accessing the field +/// requires high alignment even if the field type has lower alignment requirements. + +#[repr(C, align(16))] +#[derive(Default, Copy, Clone)] +pub struct Aligned { + _pad: [u8; 11], + packed: Packed, +} +#[repr(packed)] +#[derive(Default, Copy, Clone)] +pub struct Packed { + _pad: [u8; 5], + x: u8, +} + +unsafe fn foo(x: *const Aligned) -> u8 { + unsafe { (*x).packed.x } //~ERROR: based on pointer with alignment 1, but alignment 16 is required +} + +fn main() { + unsafe { + let mem = [Aligned::default(); 16]; + let odd_ptr = std::ptr::addr_of!(mem).cast::<u8>().add(1); + // `odd_ptr` is now not aligned enough for `Aligned`. + // If accessing the nested field `packed.x` can exploit that it is at offset 16 + // in a 16-aligned struct, this has to be UB. + foo(odd_ptr.cast()); + } +} diff --git a/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr new file mode 100644 index 00000000000..6d96c62545a --- /dev/null +++ b/src/tools/miri/tests/fail/unaligned_pointers/field_requires_parent_struct_alignment2.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required + --> $DIR/field_requires_parent_struct_alignment2.rs:LL:CC + | +LL | unsafe { (*x).packed.x } + | ^^^^^^^^^^^^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required + | + = 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 `foo` at $DIR/field_requires_parent_struct_alignment2.rs:LL:CC +note: inside `main` + --> $DIR/field_requires_parent_struct_alignment2.rs:LL:CC + | +LL | foo(odd_ptr.cast()); + | ^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs b/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs index ed43e552506..11f63839122 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -12,6 +12,6 @@ fn main() { // Manually make sure the pointer is properly aligned. let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr + 1 }; let u16_ptr = base_addr_aligned as *mut u16; - unsafe { *u16_ptr = 2 }; //~ERROR: memory with alignment 1, but alignment 2 is required + unsafe { *u16_ptr = 2 }; //~ERROR: with alignment 1, but alignment 2 is required println!("{:?}", x); } diff --git a/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr b/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr index 392495a386d..9342b269993 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required --> $DIR/intptrcast_alignment_check.rs:LL:CC | LL | unsafe { *u16_ptr = 2 }; - | ^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^^^^^^^^^^^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required | = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives diff --git a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs index 4a8cf405ae2..b9d29d775ab 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs +++ b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs @@ -1,5 +1,5 @@ -// This should fail even without validation/SB -//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Cdebug-assertions=no +// This should fail even without SB +//@compile-flags: -Zmiri-disable-stacked-borrows -Cdebug-assertions=no #![allow(dead_code, unused_variables)] @@ -12,15 +12,14 @@ struct Foo { } unsafe fn raw_to_ref<'a, T>(x: *const T) -> &'a T { - mem::transmute(x) + mem::transmute(x) //~ERROR: required 4 byte alignment } fn main() { // Try many times as this might work by chance. for _ in 0..20 { let foo = Foo { x: 42, y: 99 }; - // There seem to be implicit reborrows, which make the error already appear here - let p: &i32 = unsafe { raw_to_ref(ptr::addr_of!(foo.x)) }; //~ERROR: alignment 4 is required + let p: &i32 = unsafe { raw_to_ref(ptr::addr_of!(foo.x)) }; let i = *p; } } diff --git a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr index 7c246706dba..fb588854b2a 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.stderr @@ -1,13 +1,18 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) --> $DIR/reference_to_packed.rs:LL:CC | -LL | let p: &i32 = unsafe { raw_to_ref(ptr::addr_of!(foo.x)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required +LL | mem::transmute(x) + | ^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) | = 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/reference_to_packed.rs:LL:CC + = note: inside `raw_to_ref::<'_, i32>` at $DIR/reference_to_packed.rs:LL:CC +note: inside `main` + --> $DIR/reference_to_packed.rs:LL:CC + | +LL | let p: &i32 = unsafe { raw_to_ref(ptr::addr_of!(foo.x)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.rs b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.rs index 921bcd6ce24..9c72781ee05 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.rs +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.rs @@ -7,6 +7,6 @@ fn main() { let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. - let _x = unsafe { *x }; //~ERROR: memory with alignment 2, but alignment 4 is required + let _x = unsafe { *x }; //~ERROR: with alignment 2, but alignment 4 is required } } diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.stderr index 49292be9cd1..daebabf4557 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required --> $DIR/unaligned_ptr1.rs:LL:CC | LL | let _x = unsafe { *x }; - | ^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.rs b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.rs index 8f597659f73..ac3062773de 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.rs +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.rs @@ -8,5 +8,5 @@ fn main() { let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32; // This must fail because alignment is violated: the offset is not sufficiently aligned. // Also make the offset not a power of 2, that used to ICE. - let _x = unsafe { *x }; //~ERROR: memory with alignment 1, but alignment 4 is required + let _x = unsafe { *x }; //~ERROR: with alignment 1, but alignment 4 is required } diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.stderr index e75482f723b..38902e693dc 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required --> $DIR/unaligned_ptr2.rs:LL:CC | LL | let _x = unsafe { *x }; - | ^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr3.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr3.stderr index 50dd4fdfc89..36a13b63319 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr3.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr3.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required --> $DIR/unaligned_ptr3.rs:LL:CC | LL | let _x = unsafe { *x }; - | ^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr4.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr4.stderr index 182f3e0f876..8d7a62c3850 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr4.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr4.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required --> $DIR/unaligned_ptr4.rs:LL:CC | LL | let _val = unsafe { *ptr }; - | ^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^^^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs deleted file mode 100644 index b414b905472..00000000000 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs +++ /dev/null @@ -1,14 +0,0 @@ -// This should fail even without validation or Stacked Borrows. -//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Cdebug-assertions=no -use std::ptr; - -fn main() { - // Try many times as this might work by chance. - for _ in 0..20 { - let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. - let x = &x[0] as *const _ as *const u32; - // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. - // The deref is UB even if we just put the result into a raw pointer. - let _x = unsafe { ptr::addr_of!(*x) }; //~ ERROR: memory with alignment 2, but alignment 4 is required - } -} diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr deleted file mode 100644 index 2d8b1bf7450..00000000000 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required - --> $DIR/unaligned_ptr_addr_of.rs:LL:CC - | -LL | let _x = unsafe { ptr::addr_of!(*x) }; - | ^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required - | - = 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 RUSTLIB/core/src/ptr/mod.rs:LL:CC - = note: this error originates in the macro `ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr index aa0cbe1623b..7481179f26a 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required +error: Undefined Behavior: accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required --> $DIR/unaligned_ptr_zst.rs:LL:CC | LL | let _x = unsafe { *x }; - | ^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | ^^ accessing memory based on pointer with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.rs b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.rs new file mode 100644 index 00000000000..470420acd50 --- /dev/null +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.rs @@ -0,0 +1,12 @@ +// This should fail even without Stacked Borrows. +//@compile-flags: -Zmiri-disable-stacked-borrows -Cdebug-assertions=no + +fn main() { + // Try many times as this might work by chance. + for _ in 0..20 { + let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. + let x = &x[0] as *const _ as *const u32; + // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. + let _x = unsafe { &*x }; //~ ERROR: required 4 byte alignment + } +} diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.stderr b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.stderr new file mode 100644 index 00000000000..e47226ecdc7 --- /dev/null +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) + --> $DIR/unaligned_ref_addr_of.rs:LL:CC + | +LL | let _x = unsafe { &*x }; + | ^^^ constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN) + | + = 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/unaligned_ref_addr_of.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/src/tools/miri/tests/fail/zst1.stderr b/src/tools/miri/tests/fail/zst1.stderr index b89f06af958..07bf048ab6e 100644 --- a/src/tools/miri/tests/fail/zst1.stderr +++ b/src/tools/miri/tests/fail/zst1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds +error: Undefined Behavior: memory access failed: ALLOC has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds --> $DIR/zst1.rs:LL:CC | LL | let _val = unsafe { *x }; - | ^^ dereferencing pointer failed: ALLOC has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds + | ^^ memory access failed: ALLOC has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/zst2.stderr b/src/tools/miri/tests/fail/zst2.stderr index 49954b1fd14..f42fb07edcd 100644 --- a/src/tools/miri/tests/fail/zst2.stderr +++ b/src/tools/miri/tests/fail/zst2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling --> $DIR/zst2.rs:LL:CC | LL | unsafe { *x = zst_val }; - | ^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling + | ^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/zst3.stderr b/src/tools/miri/tests/fail/zst3.stderr index b62aef675d2..f8b416ec348 100644 --- a/src/tools/miri/tests/fail/zst3.stderr +++ b/src/tools/miri/tests/fail/zst3.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds +error: Undefined Behavior: memory access failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds --> $DIR/zst3.rs:LL:CC | LL | unsafe { *(x as *mut [u8; 0]) = zst_val }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/pass/float_nan.rs b/src/tools/miri/tests/pass/float_nan.rs new file mode 100644 index 00000000000..698aa447e26 --- /dev/null +++ b/src/tools/miri/tests/pass/float_nan.rs @@ -0,0 +1,414 @@ +use std::collections::HashSet; +use std::fmt; +use std::hash::Hash; +use std::hint::black_box; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum Sign { + Neg = 1, + Pos = 0, +} +use Sign::*; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum NaNKind { + Quiet = 1, + Signaling = 0, +} +use NaNKind::*; + +#[track_caller] +fn check_all_outcomes<T: Eq + Hash + fmt::Display>(expected: HashSet<T>, generate: impl Fn() -> T) { + let mut seen = HashSet::new(); + // Let's give it 8x as many tries as we are expecting values. + let tries = expected.len() * 8; + for _ in 0..tries { + let val = generate(); + assert!(expected.contains(&val), "got an unexpected value: {val}"); + seen.insert(val); + } + // Let's see if we saw them all. + for val in expected { + if !seen.contains(&val) { + panic!("did not get value that should be possible: {val}"); + } + } +} + +// -- f32 support +#[repr(C)] +#[derive(Copy, Clone, Eq, PartialEq, Hash)] +struct F32(u32); + +impl From<f32> for F32 { + fn from(x: f32) -> Self { + F32(x.to_bits()) + } +} + +/// Returns a value that is `ones` many 1-bits. +fn u32_ones(ones: u32) -> u32 { + assert!(ones <= 32); + if ones == 0 { + // `>>` by 32 doesn't actually shift. So inconsistent :( + return 0; + } + u32::MAX >> (32 - ones) +} + +const F32_SIGN_BIT: u32 = 32 - 1; // position of the sign bit +const F32_EXP: u32 = 8; // 8 bits of exponent +const F32_MANTISSA: u32 = F32_SIGN_BIT - F32_EXP; +const F32_NAN_PAYLOAD: u32 = F32_MANTISSA - 1; + +impl fmt::Display for F32 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Alaways show raw bits. + write!(f, "0x{:08x} ", self.0)?; + // Also show nice version. + let val = self.0; + let sign = val >> F32_SIGN_BIT; + let val = val & u32_ones(F32_SIGN_BIT); // mask away sign + let exp = val >> F32_MANTISSA; + let mantissa = val & u32_ones(F32_MANTISSA); + if exp == u32_ones(F32_EXP) { + // A NaN! Special printing. + let sign = if sign != 0 { Neg } else { Pos }; + let quiet = if (mantissa >> F32_NAN_PAYLOAD) != 0 { Quiet } else { Signaling }; + let payload = mantissa & u32_ones(F32_NAN_PAYLOAD); + write!(f, "(NaN: {:?}, {:?}, payload = {:#x})", sign, quiet, payload) + } else { + // Normal float value. + write!(f, "({})", f32::from_bits(self.0)) + } + } +} + +impl F32 { + fn nan(sign: Sign, kind: NaNKind, payload: u32) -> Self { + // Either the quiet bit must be set of the payload must be non-0; + // otherwise this is not a NaN but an infinity. + assert!(kind == Quiet || payload != 0); + // Payload must fit in 22 bits. + assert!(payload < (1 << F32_NAN_PAYLOAD)); + // Concatenate the bits (with a 22bit payload). + // Pattern: [negative] ++ [1]^8 ++ [quiet] ++ [payload] + let val = ((sign as u32) << F32_SIGN_BIT) + | (u32_ones(F32_EXP) << F32_MANTISSA) + | ((kind as u32) << F32_NAN_PAYLOAD) + | payload; + // Sanity check. + assert!(f32::from_bits(val).is_nan()); + // Done! + F32(val) + } + + fn as_f32(self) -> f32 { + black_box(f32::from_bits(self.0)) + } +} + +// -- f64 support +#[repr(C)] +#[derive(Copy, Clone, Eq, PartialEq, Hash)] +struct F64(u64); + +impl From<f64> for F64 { + fn from(x: f64) -> Self { + F64(x.to_bits()) + } +} + +/// Returns a value that is `ones` many 1-bits. +fn u64_ones(ones: u32) -> u64 { + assert!(ones <= 64); + if ones == 0 { + // `>>` by 32 doesn't actually shift. So inconsistent :( + return 0; + } + u64::MAX >> (64 - ones) +} + +const F64_SIGN_BIT: u32 = 64 - 1; // position of the sign bit +const F64_EXP: u32 = 11; // 11 bits of exponent +const F64_MANTISSA: u32 = F64_SIGN_BIT - F64_EXP; +const F64_NAN_PAYLOAD: u32 = F64_MANTISSA - 1; + +impl fmt::Display for F64 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Alaways show raw bits. + write!(f, "0x{:08x} ", self.0)?; + // Also show nice version. + let val = self.0; + let sign = val >> F64_SIGN_BIT; + let val = val & u64_ones(F64_SIGN_BIT); // mask away sign + let exp = val >> F64_MANTISSA; + let mantissa = val & u64_ones(F64_MANTISSA); + if exp == u64_ones(F64_EXP) { + // A NaN! Special printing. + let sign = if sign != 0 { Neg } else { Pos }; + let quiet = if (mantissa >> F64_NAN_PAYLOAD) != 0 { Quiet } else { Signaling }; + let payload = mantissa & u64_ones(F64_NAN_PAYLOAD); + write!(f, "(NaN: {:?}, {:?}, payload = {:#x})", sign, quiet, payload) + } else { + // Normal float value. + write!(f, "({})", f64::from_bits(self.0)) + } + } +} + +impl F64 { + fn nan(sign: Sign, kind: NaNKind, payload: u64) -> Self { + // Either the quiet bit must be set of the payload must be non-0; + // otherwise this is not a NaN but an infinity. + assert!(kind == Quiet || payload != 0); + // Payload must fit in 52 bits. + assert!(payload < (1 << F64_NAN_PAYLOAD)); + // Concatenate the bits (with a 52bit payload). + // Pattern: [negative] ++ [1]^11 ++ [quiet] ++ [payload] + let val = ((sign as u64) << F64_SIGN_BIT) + | (u64_ones(F64_EXP) << F64_MANTISSA) + | ((kind as u64) << F64_NAN_PAYLOAD) + | payload; + // Sanity check. + assert!(f64::from_bits(val).is_nan()); + // Done! + F64(val) + } + + fn as_f64(self) -> f64 { + black_box(f64::from_bits(self.0)) + } +} + +// -- actual tests + +fn test_f32() { + // Freshly generated NaNs can have either sign. + check_all_outcomes( + HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), + || F32::from(0.0 / black_box(0.0)), + ); + // When there are NaN inputs, their payload can be propagated, with any sign. + let all1_payload = u32_ones(22); + let all1 = F32::nan(Pos, Quiet, all1_payload).as_f32(); + check_all_outcomes( + HashSet::from_iter([ + F32::nan(Pos, Quiet, 0), + F32::nan(Neg, Quiet, 0), + F32::nan(Pos, Quiet, all1_payload), + F32::nan(Neg, Quiet, all1_payload), + ]), + || F32::from(0.0 + all1), + ); + // When there are two NaN inputs, the output can be either one, or the preferred NaN. + let just1 = F32::nan(Neg, Quiet, 1).as_f32(); + check_all_outcomes( + HashSet::from_iter([ + F32::nan(Pos, Quiet, 0), + F32::nan(Neg, Quiet, 0), + F32::nan(Pos, Quiet, 1), + F32::nan(Neg, Quiet, 1), + F32::nan(Pos, Quiet, all1_payload), + F32::nan(Neg, Quiet, all1_payload), + ]), + || F32::from(just1 - all1), + ); + // When there are *signaling* NaN inputs, they might be quieted or not. + let all1_snan = F32::nan(Pos, Signaling, all1_payload).as_f32(); + check_all_outcomes( + HashSet::from_iter([ + F32::nan(Pos, Quiet, 0), + F32::nan(Neg, Quiet, 0), + F32::nan(Pos, Quiet, all1_payload), + F32::nan(Neg, Quiet, all1_payload), + F32::nan(Pos, Signaling, all1_payload), + F32::nan(Neg, Signaling, all1_payload), + ]), + || F32::from(0.0 * all1_snan), + ); + // Mix signaling and non-signaling NaN. + check_all_outcomes( + HashSet::from_iter([ + F32::nan(Pos, Quiet, 0), + F32::nan(Neg, Quiet, 0), + F32::nan(Pos, Quiet, 1), + F32::nan(Neg, Quiet, 1), + F32::nan(Pos, Quiet, all1_payload), + F32::nan(Neg, Quiet, all1_payload), + F32::nan(Pos, Signaling, all1_payload), + F32::nan(Neg, Signaling, all1_payload), + ]), + || F32::from(just1 % all1_snan), + ); + + // Unary `-` must preserve payloads exactly. + check_all_outcomes(HashSet::from_iter([F32::nan(Neg, Quiet, all1_payload)]), || { + F32::from(-all1) + }); + check_all_outcomes(HashSet::from_iter([F32::nan(Neg, Signaling, all1_payload)]), || { + F32::from(-all1_snan) + }); +} + +fn test_f64() { + // Freshly generated NaNs can have either sign. + check_all_outcomes( + HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), + || F64::from(0.0 / black_box(0.0)), + ); + // When there are NaN inputs, their payload can be propagated, with any sign. + let all1_payload = u64_ones(51); + let all1 = F64::nan(Pos, Quiet, all1_payload).as_f64(); + check_all_outcomes( + HashSet::from_iter([ + F64::nan(Pos, Quiet, 0), + F64::nan(Neg, Quiet, 0), + F64::nan(Pos, Quiet, all1_payload), + F64::nan(Neg, Quiet, all1_payload), + ]), + || F64::from(0.0 + all1), + ); + // When there are two NaN inputs, the output can be either one, or the preferred NaN. + let just1 = F64::nan(Neg, Quiet, 1).as_f64(); + check_all_outcomes( + HashSet::from_iter([ + F64::nan(Pos, Quiet, 0), + F64::nan(Neg, Quiet, 0), + F64::nan(Pos, Quiet, 1), + F64::nan(Neg, Quiet, 1), + F64::nan(Pos, Quiet, all1_payload), + F64::nan(Neg, Quiet, all1_payload), + ]), + || F64::from(just1 - all1), + ); + // When there are *signaling* NaN inputs, they might be quieted or not. + let all1_snan = F64::nan(Pos, Signaling, all1_payload).as_f64(); + check_all_outcomes( + HashSet::from_iter([ + F64::nan(Pos, Quiet, 0), + F64::nan(Neg, Quiet, 0), + F64::nan(Pos, Quiet, all1_payload), + F64::nan(Neg, Quiet, all1_payload), + F64::nan(Pos, Signaling, all1_payload), + F64::nan(Neg, Signaling, all1_payload), + ]), + || F64::from(0.0 * all1_snan), + ); + // Mix signaling and non-signaling NaN. + check_all_outcomes( + HashSet::from_iter([ + F64::nan(Pos, Quiet, 0), + F64::nan(Neg, Quiet, 0), + F64::nan(Pos, Quiet, 1), + F64::nan(Neg, Quiet, 1), + F64::nan(Pos, Quiet, all1_payload), + F64::nan(Neg, Quiet, all1_payload), + F64::nan(Pos, Signaling, all1_payload), + F64::nan(Neg, Signaling, all1_payload), + ]), + || F64::from(just1 % all1_snan), + ); +} + +fn test_casts() { + let all1_payload_32 = u32_ones(22); + let all1_payload_64 = u64_ones(51); + let left1_payload_64 = (all1_payload_32 as u64) << (51 - 22); + + // 64-to-32 + check_all_outcomes( + HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), + || F32::from(F64::nan(Pos, Quiet, 0).as_f64() as f32), + ); + // The preferred payload is always a possibility. + check_all_outcomes( + HashSet::from_iter([ + F32::nan(Pos, Quiet, 0), + F32::nan(Neg, Quiet, 0), + F32::nan(Pos, Quiet, all1_payload_32), + F32::nan(Neg, Quiet, all1_payload_32), + ]), + || F32::from(F64::nan(Pos, Quiet, all1_payload_64).as_f64() as f32), + ); + // If the input is signaling, then the output *may* also be signaling. + check_all_outcomes( + HashSet::from_iter([ + F32::nan(Pos, Quiet, 0), + F32::nan(Neg, Quiet, 0), + F32::nan(Pos, Quiet, all1_payload_32), + F32::nan(Neg, Quiet, all1_payload_32), + F32::nan(Pos, Signaling, all1_payload_32), + F32::nan(Neg, Signaling, all1_payload_32), + ]), + || F32::from(F64::nan(Pos, Signaling, all1_payload_64).as_f64() as f32), + ); + // Check that the low bits are gone (not the high bits). + check_all_outcomes( + HashSet::from_iter([ + F32::nan(Pos, Quiet, 0), + F32::nan(Neg, Quiet, 0), + ]), + || F32::from(F64::nan(Pos, Quiet, 1).as_f64() as f32), + ); + check_all_outcomes( + HashSet::from_iter([ + F32::nan(Pos, Quiet, 0), + F32::nan(Neg, Quiet, 0), + F32::nan(Pos, Quiet, 1), + F32::nan(Neg, Quiet, 1), + ]), + || F32::from(F64::nan(Pos, Quiet, 1 << (51-22)).as_f64() as f32), + ); + check_all_outcomes( + HashSet::from_iter([ + F32::nan(Pos, Quiet, 0), + F32::nan(Neg, Quiet, 0), + // The `1` payload becomes `0`, and the `0` payload cannot be signaling, + // so these are the only options. + ]), + || F32::from(F64::nan(Pos, Signaling, 1).as_f64() as f32), + ); + + // 32-to-64 + check_all_outcomes( + HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), + || F64::from(F32::nan(Pos, Quiet, 0).as_f32() as f64), + ); + // The preferred payload is always a possibility. + // Also checks that 0s are added on the right. + check_all_outcomes( + HashSet::from_iter([ + F64::nan(Pos, Quiet, 0), + F64::nan(Neg, Quiet, 0), + F64::nan(Pos, Quiet, left1_payload_64), + F64::nan(Neg, Quiet, left1_payload_64), + ]), + || F64::from(F32::nan(Pos, Quiet, all1_payload_32).as_f32() as f64), + ); + // If the input is signaling, then the output *may* also be signaling. + check_all_outcomes( + HashSet::from_iter([ + F64::nan(Pos, Quiet, 0), + F64::nan(Neg, Quiet, 0), + F64::nan(Pos, Quiet, left1_payload_64), + F64::nan(Neg, Quiet, left1_payload_64), + F64::nan(Pos, Signaling, left1_payload_64), + F64::nan(Neg, Signaling, left1_payload_64), + ]), + || F64::from(F32::nan(Pos, Signaling, all1_payload_32).as_f32() as f64), + ); +} + +fn main() { + // Check our constants against std, just to be sure. + // We add 1 since our numbers are the number of bits stored + // to represent the value, and std has the precision of the value, + // which is one more due to the implicit leading 1. + assert_eq!(F32_MANTISSA + 1, f32::MANTISSA_DIGITS); + assert_eq!(F64_MANTISSA + 1, f64::MANTISSA_DIGITS); + + test_f32(); + test_f64(); + test_casts(); +} diff --git a/src/tools/miri/tests/pass/function_calls/target_feature_wasm.rs b/src/tools/miri/tests/pass/function_calls/target_feature_wasm.rs new file mode 100644 index 00000000000..5056f32de44 --- /dev/null +++ b/src/tools/miri/tests/pass/function_calls/target_feature_wasm.rs @@ -0,0 +1,11 @@ +//@only-target-wasm32: tests WASM-specific behavior +//@compile-flags: -C target-feature=-simd128 + +fn main() { + // Calling functions with `#[target_feature]` is not unsound on WASM, see #84988 + assert!(!cfg!(target_feature = "simd128")); + simd128_fn(); +} + +#[target_feature(enable = "simd128")] +fn simd128_fn() {} diff --git a/src/tools/miri/tests/pass/ptr_raw.rs b/src/tools/miri/tests/pass/ptr_raw.rs index 2f184358907..9743278961b 100644 --- a/src/tools/miri/tests/pass/ptr_raw.rs +++ b/src/tools/miri/tests/pass/ptr_raw.rs @@ -1,3 +1,7 @@ +#![feature(strict_provenance)] +use std::ptr::{self, addr_of}; +use std::mem; + fn basic_raw() { let mut x = 12; let x = &mut x; @@ -28,7 +32,37 @@ fn assign_overlapping() { unsafe { *ptr = *ptr }; } +fn deref_invalid() { + unsafe { + // `addr_of!(*ptr)` is never UB. + let _val = addr_of!(*ptr::invalid::<i32>(0)); + let _val = addr_of!(*ptr::invalid::<i32>(1)); // not aligned + + // Similarly, just mentioning the place is fine. + let _ = *ptr::invalid::<i32>(0); + let _ = *ptr::invalid::<i32>(1); + } +} + +fn deref_partially_dangling() { + let x = (1, 13); + let xptr = &x as *const _ as *const (i32, i32, i32); + let val = unsafe { (*xptr).1 }; + assert_eq!(val, 13); +} + +fn deref_too_big_slice() { + unsafe { + let slice: *const [u8] = mem::transmute((1usize, usize::MAX)); + // `&*slice` would complain that the slice is too big, but in a raw pointer this is fine. + let _val = addr_of!(*slice); + } +} + fn main() { basic_raw(); assign_overlapping(); + deref_invalid(); + deref_partially_dangling(); + deref_too_big_slice(); } diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml index c212e8aafe1..9e852b0645a 100644 --- a/src/tools/opt-dist/Cargo.toml +++ b/src/tools/opt-dist/Cargo.toml @@ -23,4 +23,4 @@ glob = "0.3" tempfile = "3.5" derive_builder = "0.12" clap = { version = "4", features = ["derive"] } -tabled = "0.13" +tabled = { version = "0.13", default-features = false, features = ["std"] } diff --git a/src/tools/opt-dist/src/bolt.rs b/src/tools/opt-dist/src/bolt.rs index cf9f4fabcec..f694c08f9b9 100644 --- a/src/tools/opt-dist/src/bolt.rs +++ b/src/tools/opt-dist/src/bolt.rs @@ -1,14 +1,14 @@ use anyhow::Context; use crate::exec::cmd; -use crate::training::LlvmBoltProfile; +use crate::training::BoltProfile; use camino::{Utf8Path, Utf8PathBuf}; use crate::utils::io::copy_file; /// Instruments an artifact at the given `path` (in-place) with BOLT and then calls `func`. /// After this function finishes, the original file will be restored. -pub fn with_bolt_instrumented<F: FnOnce() -> anyhow::Result<R>, R>( +pub fn with_bolt_instrumented<F: FnOnce(&Utf8Path) -> anyhow::Result<R>, R>( path: &Utf8Path, func: F, ) -> anyhow::Result<R> { @@ -20,10 +20,16 @@ pub fn with_bolt_instrumented<F: FnOnce() -> anyhow::Result<R>, R>( let instrumented_path = tempfile::NamedTempFile::new()?.into_temp_path(); + let profile_dir = + tempfile::TempDir::new().context("Could not create directory for BOLT profiles")?; + let profile_prefix = profile_dir.path().join("prof.fdata"); + let profile_prefix = Utf8Path::from_path(&profile_prefix).unwrap(); + // Instrument the original file with BOLT, saving the result into `instrumented_path` cmd(&["llvm-bolt"]) .arg("-instrument") .arg(path) + .arg(&format!("--instrumentation-file={profile_prefix}")) // Make sure that each process will write its profiles into a separate file .arg("--instrumentation-file-append-pid") .arg("-o") @@ -36,11 +42,11 @@ pub fn with_bolt_instrumented<F: FnOnce() -> anyhow::Result<R>, R>( // Run the function that will make use of the instrumented artifact. // The original file will be restored when `_backup_file` is dropped. - func() + func(profile_prefix) } /// Optimizes the file at `path` with BOLT in-place using the given `profile`. -pub fn bolt_optimize(path: &Utf8Path, profile: &LlvmBoltProfile) -> anyhow::Result<()> { +pub fn bolt_optimize(path: &Utf8Path, profile: &BoltProfile) -> anyhow::Result<()> { // Copy the artifact to a new location, so that we do not use the same input and output file. // BOLT cannot handle optimizing when the input and output is the same file, because it performs // in-place patching. diff --git a/src/tools/opt-dist/src/exec.rs b/src/tools/opt-dist/src/exec.rs index 04e0184528a..90a045e83d7 100644 --- a/src/tools/opt-dist/src/exec.rs +++ b/src/tools/opt-dist/src/exec.rs @@ -1,7 +1,7 @@ use crate::environment::Environment; use crate::metrics::{load_metrics, record_metrics}; use crate::timer::TimerSection; -use crate::training::{LlvmBoltProfile, LlvmPGOProfile, RustcPGOProfile}; +use crate::training::{BoltProfile, LlvmPGOProfile, RustcPGOProfile}; use camino::{Utf8Path, Utf8PathBuf}; use std::collections::BTreeMap; use std::fs::File; @@ -159,7 +159,12 @@ impl Bootstrap { self } - pub fn with_bolt_profile(mut self, profile: LlvmBoltProfile) -> Self { + pub fn with_rustc_bolt_ldflags(mut self) -> Self { + self.cmd = self.cmd.arg("--enable-bolt-settings"); + self + } + + pub fn with_bolt_profile(mut self, profile: BoltProfile) -> Self { self.cmd = self.cmd.arg("--reproducible-artifact").arg(profile.0.as_str()); self } diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index 03a1912f5ce..9cdff84676e 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -12,7 +12,10 @@ use crate::environment::{Environment, EnvironmentBuilder}; use crate::exec::{cmd, Bootstrap}; use crate::tests::run_tests; use crate::timer::Timer; -use crate::training::{gather_llvm_bolt_profiles, gather_llvm_profiles, gather_rustc_profiles}; +use crate::training::{ + gather_bolt_profiles, gather_llvm_profiles, gather_rustc_profiles, llvm_benchmarks, + rustc_benchmarks, +}; use crate::utils::artifact_size::print_binary_sizes; use crate::utils::io::{copy_directory, move_directory, reset_directory}; use crate::utils::{ @@ -212,7 +215,12 @@ fn execute_pipeline( print_free_disk_space()?; stage.section("Build PGO optimized rustc", |section| { - Bootstrap::build(env).rustc_pgo_optimize(&profile).run(section) + let mut cmd = Bootstrap::build(env).rustc_pgo_optimize(&profile); + if env.use_bolt() { + cmd = cmd.with_rustc_bolt_ldflags(); + } + + cmd.run(section) })?; Ok(profile) @@ -246,13 +254,13 @@ fn execute_pipeline( Ok(profile) })?; - let llvm_bolt_profile = if env.use_bolt() { + let bolt_profiles = if env.use_bolt() { // Stage 3: Build BOLT instrumented LLVM // We build a PGO optimized LLVM in this step, then instrument it with BOLT and gather BOLT profiles. // Note that we don't remove LLVM artifacts after this step, so that they are reused in the final dist build. // BOLT instrumentation is performed "on-the-fly" when the LLVM library is copied to the sysroot of rustc, // therefore the LLVM artifacts on disk are not "tainted" with BOLT instrumentation and they can be reused. - timer.section("Stage 3 (LLVM BOLT)", |stage| { + timer.section("Stage 3 (BOLT)", |stage| { stage.section("Build PGO optimized LLVM", |stage| { Bootstrap::build(env) .with_llvm_bolt_ldflags() @@ -261,16 +269,17 @@ fn execute_pipeline( .run(stage) })?; - // Find the path to the `libLLVM.so` file - let llvm_lib = io::find_file_in_dir( - &env.build_artifacts().join("stage2").join("lib"), - "libLLVM", - ".so", - )?; + let libdir = env.build_artifacts().join("stage2").join("lib"); + let llvm_lib = io::find_file_in_dir(&libdir, "libLLVM", ".so")?; - // Instrument it and gather profiles - let profile = with_bolt_instrumented(&llvm_lib, || { - stage.section("Gather profiles", |_| gather_llvm_bolt_profiles(env)) + log::info!("Optimizing {llvm_lib} with BOLT"); + + // FIXME(kobzol): try gather profiles together, at once for LLVM and rustc + // Instrument the libraries and gather profiles + let llvm_profile = with_bolt_instrumented(&llvm_lib, |llvm_profile_dir| { + stage.section("Gather profiles", |_| { + gather_bolt_profiles(env, "LLVM", llvm_benchmarks(env), llvm_profile_dir) + }) })?; print_free_disk_space()?; @@ -279,13 +288,29 @@ fn execute_pipeline( // the final dist build. However, when BOLT optimizes an artifact, it does so *in-place*, // therefore it will actually optimize all the hard links, which means that the final // packaged `libLLVM.so` file *will* be BOLT optimized. - bolt_optimize(&llvm_lib, &profile).context("Could not optimize LLVM with BOLT")?; + bolt_optimize(&llvm_lib, &llvm_profile).context("Could not optimize LLVM with BOLT")?; + + let rustc_lib = io::find_file_in_dir(&libdir, "librustc_driver", ".so")?; + + log::info!("Optimizing {rustc_lib} with BOLT"); + + // Instrument it and gather profiles + let rustc_profile = with_bolt_instrumented(&rustc_lib, |rustc_profile_dir| { + stage.section("Gather profiles", |_| { + gather_bolt_profiles(env, "rustc", rustc_benchmarks(env), rustc_profile_dir) + }) + })?; + print_free_disk_space()?; + + // Now optimize the library with BOLT. + bolt_optimize(&rustc_lib, &rustc_profile) + .context("Could not optimize rustc with BOLT")?; // LLVM is not being cleared here, we want to use the BOLT-optimized LLVM - Ok(Some(profile)) + Ok(vec![llvm_profile, rustc_profile]) })? } else { - None + vec![] }; let mut dist = Bootstrap::dist(env, &dist_args) @@ -293,13 +318,13 @@ fn execute_pipeline( .rustc_pgo_optimize(&rustc_pgo_profile) .avoid_rustc_rebuild(); - if let Some(llvm_bolt_profile) = llvm_bolt_profile { - dist = dist.with_bolt_profile(llvm_bolt_profile); + for bolt_profile in bolt_profiles { + dist = dist.with_bolt_profile(bolt_profile); } // Final stage: Assemble the dist artifacts // The previous PGO optimized rustc build and PGO optimized LLVM builds should be reused. - timer.section("Stage 4 (final build)", |stage| dist.run(stage))?; + timer.section("Stage 5 (final build)", |stage| dist.run(stage))?; // After dist has finished, run a subset of the test suite on the optimized artifacts to discover // possible regressions. diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs index 274f4cea0ab..46040e32a03 100644 --- a/src/tools/opt-dist/src/training.rs +++ b/src/tools/opt-dist/src/training.rs @@ -27,8 +27,6 @@ const RUSTC_PGO_CRATES: &[&str] = &[ "bitmaps-3.1.0", ]; -const LLVM_BOLT_CRATES: &[&str] = LLVM_PGO_CRATES; - fn init_compiler_benchmarks( env: &Environment, profiles: &[&str], @@ -113,6 +111,14 @@ fn log_profile_stats( Ok(()) } +pub fn llvm_benchmarks(env: &Environment) -> CmdBuilder { + init_compiler_benchmarks(env, &["Debug", "Opt"], &["Full"], LLVM_PGO_CRATES) +} + +pub fn rustc_benchmarks(env: &Environment) -> CmdBuilder { + init_compiler_benchmarks(env, &["Check", "Debug", "Opt"], &["All"], RUSTC_PGO_CRATES) +} + pub struct LlvmPGOProfile(pub Utf8PathBuf); pub fn gather_llvm_profiles( @@ -122,9 +128,7 @@ pub fn gather_llvm_profiles( log::info!("Running benchmarks with PGO instrumented LLVM"); with_log_group("Running benchmarks", || { - init_compiler_benchmarks(env, &["Debug", "Opt"], &["Full"], LLVM_PGO_CRATES) - .run() - .context("Cannot gather LLVM PGO profiles") + llvm_benchmarks(env).run().context("Cannot gather LLVM PGO profiles") })?; let merged_profile = env.artifact_dir().join("llvm-pgo.profdata"); @@ -157,7 +161,7 @@ pub fn gather_rustc_profiles( // Here we're profiling the `rustc` frontend, so we also include `Check`. // The benchmark set includes various stress tests that put the frontend under pressure. with_log_group("Running benchmarks", || { - init_compiler_benchmarks(env, &["Check", "Debug", "Opt"], &["All"], RUSTC_PGO_CRATES) + rustc_benchmarks(env) .env("LLVM_PROFILE_FILE", profile_template.as_str()) .run() .context("Cannot gather rustc PGO profiles") @@ -176,23 +180,25 @@ pub fn gather_rustc_profiles( Ok(RustcPGOProfile(merged_profile)) } -pub struct LlvmBoltProfile(pub Utf8PathBuf); +pub struct BoltProfile(pub Utf8PathBuf); -pub fn gather_llvm_bolt_profiles(env: &Environment) -> anyhow::Result<LlvmBoltProfile> { - log::info!("Running benchmarks with BOLT instrumented LLVM"); +pub fn gather_bolt_profiles( + env: &Environment, + name: &str, + benchmarks: CmdBuilder, + profile_prefix: &Utf8Path, +) -> anyhow::Result<BoltProfile> { + log::info!("Running benchmarks with BOLT instrumented {name}"); with_log_group("Running benchmarks", || { - init_compiler_benchmarks(env, &["Check", "Debug", "Opt"], &["Full"], LLVM_BOLT_CRATES) - .run() - .context("Cannot gather LLVM BOLT profiles") + benchmarks.run().with_context(|| "Cannot gather {name} BOLT profiles") })?; - let merged_profile = env.artifact_dir().join("llvm-bolt.profdata"); - let profile_root = Utf8PathBuf::from("/tmp/prof.fdata"); - log::info!("Merging LLVM BOLT profiles to {merged_profile}"); + let merged_profile = env.artifact_dir().join(format!("{name}-bolt.profdata")); + log::info!("Merging {name} BOLT profiles from {profile_prefix} to {merged_profile}"); let profiles: Vec<_> = - glob::glob(&format!("{profile_root}*"))?.collect::<Result<Vec<_>, _>>()?; + glob::glob(&format!("{profile_prefix}*"))?.collect::<Result<Vec<_>, _>>()?; let mut merge_args = vec!["merge-fdata"]; merge_args.extend(profiles.iter().map(|p| p.to_str().unwrap())); @@ -204,7 +210,7 @@ pub fn gather_llvm_bolt_profiles(env: &Environment) -> anyhow::Result<LlvmBoltPr .context("Cannot merge BOLT profiles") })?; - log::info!("LLVM BOLT statistics"); + log::info!("{name} BOLT statistics"); log::info!( "{merged_profile}: {}", humansize::format_size(std::fs::metadata(merged_profile.as_std_path())?.len(), BINARY) @@ -216,8 +222,17 @@ pub fn gather_llvm_bolt_profiles(env: &Environment) -> anyhow::Result<LlvmBoltPr .collect::<Result<Vec<_>, _>>()? .into_iter() .sum::<u64>(); - log::info!("{profile_root}: {}", humansize::format_size(size, BINARY)); + log::info!("{profile_prefix}: {}", humansize::format_size(size, BINARY)); log::info!("Profile file count: {}", profiles.len()); - Ok(LlvmBoltProfile(merged_profile)) + // Delete the gathered profiles + for profile in glob::glob(&format!("{profile_prefix}*"))?.into_iter() { + if let Ok(profile) = profile { + if let Err(error) = std::fs::remove_file(&profile) { + log::error!("Cannot delete BOLT profile {}: {error:?}", profile.display()); + } + } + } + + Ok(BoltProfile(merged_profile)) } diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js index af1bc05ddb2..8f6626f6296 100644 --- a/src/tools/rustdoc-gui/tester.js +++ b/src/tools/rustdoc-gui/tester.js @@ -249,12 +249,17 @@ async function main(argv) { console.log("`--no-headless` option is active, disabling concurrency for running tests."); } - console.log(`Running ${files.length} rustdoc-gui (${opts["jobs"]} concurrently) ...`); - if (opts["jobs"] < 1) { + const len = files.length; + console.log( + `Running ${len} rustdoc-gui (UNBOUNDED concurrency; use "-j#" for a limit) ...`, + ); process.setMaxListeners(files.length + 1); } else if (headless) { + console.log(`Running ${files.length} rustdoc-gui (${opts["jobs"]} concurrently) ...`); process.setMaxListeners(opts["jobs"] + 1); + } else { + console.log(`Running ${files.length} rustdoc-gui ...`); } // We catch this "event" to display a nicer message in case of unexpected exit (because of a diff --git a/src/tools/tidy/src/alphabetical.rs b/src/tools/tidy/src/alphabetical.rs index fdc411c8925..3e60915c224 100644 --- a/src/tools/tidy/src/alphabetical.rs +++ b/src/tools/tidy/src/alphabetical.rs @@ -30,8 +30,8 @@ fn is_close_bracket(c: char) -> bool { } // Don't let tidy check this here :D -const START_COMMENT: &str = concat!("// tidy-alphabetical", "-start"); -const END_COMMENT: &str = "// tidy-alphabetical-end"; +const START_COMMENT: &str = concat!("tidy-alphabetical", "-start"); +const END_COMMENT: &str = "tidy-alphabetical-end"; fn check_section<'a>( file: impl Display, diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index d900c04c124..8e791a7dc69 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -30,7 +30,7 @@ const FEATURE_GROUP_END_PREFIX: &str = "// feature-group-end"; #[derive(Debug, PartialEq, Clone)] pub enum Status { - Stable, + Accepted, Removed, Unstable, } @@ -38,7 +38,7 @@ pub enum Status { impl fmt::Display for Status { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let as_str = match *self { - Status::Stable => "stable", + Status::Accepted => "accepted", Status::Unstable => "unstable", Status::Removed => "removed", }; @@ -279,9 +279,9 @@ fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool { pub fn collect_lang_features(base_compiler_path: &Path, bad: &mut bool) -> Features { let mut features = Features::new(); - collect_lang_features_in(&mut features, base_compiler_path, "active.rs", bad); collect_lang_features_in(&mut features, base_compiler_path, "accepted.rs", bad); collect_lang_features_in(&mut features, base_compiler_path, "removed.rs", bad); + collect_lang_features_in(&mut features, base_compiler_path, "unstable.rs", bad); features } @@ -336,11 +336,11 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba let mut parts = line.split(','); let level = match parts.next().map(|l| l.trim().trim_start_matches('(')) { - Some("active") => Status::Unstable, + Some("unstable") => Status::Unstable, Some("incomplete") => Status::Unstable, Some("internal") => Status::Unstable, Some("removed") => Status::Removed, - Some("accepted") => Status::Stable, + Some("accepted") => Status::Accepted, _ => continue, }; let name = parts.next().unwrap().trim(); @@ -449,7 +449,7 @@ fn get_and_check_lib_features( Ok((name, f)) => { let mut check_features = |f: &Feature, list: &Features, display: &str| { if let Some(ref s) = list.get(name) { - if f.tracking_issue != s.tracking_issue && f.level != Status::Stable { + if f.tracking_issue != s.tracking_issue && f.level != Status::Accepted { tidy_error!( bad, "{}:{}: `issue` \"{}\" mismatches the {} `issue` of \"{}\"", @@ -566,7 +566,7 @@ fn map_lib_features( let level = if line.contains("[unstable(") { Status::Unstable } else if line.contains("[stable(") { - Status::Stable + Status::Accepted } else { continue; }; @@ -581,7 +581,7 @@ fn map_lib_features( Some(Err(_err)) => { err!("malformed stability attribute: can't parse `since` key"); } - None if level == Status::Stable => { + None if level == Status::Accepted => { err!("malformed stability attribute: missing the `since` key"); } None => None, diff --git a/tests/assembly/asm/arm-types.rs b/tests/assembly/asm/arm-types.rs index b22a26ce36f..9520f932779 100644 --- a/tests/assembly/asm/arm-types.rs +++ b/tests/assembly/asm/arm-types.rs @@ -1,6 +1,7 @@ // assembly-output: emit-asm // compile-flags: --target armv7-unknown-linux-gnueabihf // compile-flags: -C target-feature=+neon +// compile-flags: -C opt-level=0 // needs-llvm-components: arm #![feature(no_core, lang_items, rustc_attrs, repr_simd)] diff --git a/tests/assembly/closure-inherit-target-feature.rs b/tests/assembly/closure-inherit-target-feature.rs index 65728a15516..24802603452 100644 --- a/tests/assembly/closure-inherit-target-feature.rs +++ b/tests/assembly/closure-inherit-target-feature.rs @@ -22,6 +22,7 @@ pub unsafe fn sse41_blend_nofeature(x: __m128, y: __m128) -> __m128 { f(x, y) } +#[no_mangle] #[target_feature(enable = "sse4.1")] pub fn sse41_blend_noinline(x: __m128, y: __m128) -> __m128 { let f = { diff --git a/tests/assembly/dwarf5.rs b/tests/assembly/dwarf5.rs index f41e6bd55be..253baafb887 100644 --- a/tests/assembly/dwarf5.rs +++ b/tests/assembly/dwarf5.rs @@ -1,6 +1,6 @@ // Makes sure that `-Z dwarf-version=5` causes `rustc` to emit DWARF version 5. // assembly-output: emit-asm -// compile-flags: -g --target x86_64-unknown-linux-gnu -Z dwarf-version=5 +// compile-flags: -g --target x86_64-unknown-linux-gnu -Z dwarf-version=5 -Copt-level=0 // needs-llvm-components: x86 #![feature(no_core, lang_items)] diff --git a/tests/assembly/libs/issue-115339-zip-arrays.rs b/tests/assembly/libs/issue-115339-zip-arrays.rs new file mode 100644 index 00000000000..26b7b9770bc --- /dev/null +++ b/tests/assembly/libs/issue-115339-zip-arrays.rs @@ -0,0 +1,25 @@ +// assembly-output: emit-asm +// # zen3 previously exhibited odd vectorization +// compile-flags: --crate-type=lib -Ctarget-cpu=znver3 -O +// only-x86_64 +// ignore-sgx + +use std::iter; + +// previously this produced a long chain of +// 56: vpextrb $6, %xmm0, %ecx +// 57: orb %cl, 22(%rsi) +// 58: vpextrb $7, %xmm0, %ecx +// 59: orb %cl, 23(%rsi) +// [...] + +// CHECK-LABEL: zip_arrays: +#[no_mangle] +pub fn zip_arrays(mut a: [u8; 32], b: [u8; 32]) -> [u8; 32] { + // CHECK-NOT: vpextrb + // CHECK-NOT: orb %cl + // CHECK: vorps + iter::zip(&mut a, b).for_each(|(a, b)| *a |= b); + // CHECK: retq + a +} diff --git a/tests/assembly/x86_64-array-pair-load-store-merge.rs b/tests/assembly/x86_64-array-pair-load-store-merge.rs new file mode 100644 index 00000000000..55e317e91bf --- /dev/null +++ b/tests/assembly/x86_64-array-pair-load-store-merge.rs @@ -0,0 +1,20 @@ +// assembly-output: emit-asm +// compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel +// only-x86_64 +// ignore-sgx +// ignore-macos (manipulates rsp too) + +// Depending on various codegen choices, this might end up copying +// a `<2 x i8>`, an `i16`, or two `i8`s. +// Regardless of those choices, make sure the instructions use (2-byte) words. + +// CHECK-LABEL: array_copy_2_elements: +#[no_mangle] +pub fn array_copy_2_elements(a: &[u8; 2], p: &mut [u8; 2]) { + // CHECK-NOT: byte + // CHECK-NOT: mov + // CHECK: mov{{.+}}, word ptr + // CHECK-NEXT: mov word ptr + // CHECK-NEXT: ret + *p = *a; +} diff --git a/tests/codegen-units/item-collection/asm-sym.rs b/tests/codegen-units/item-collection/asm-sym.rs index 8bafb95bc16..4b05b771a9b 100644 --- a/tests/codegen-units/item-collection/asm-sym.rs +++ b/tests/codegen-units/item-collection/asm-sym.rs @@ -6,15 +6,18 @@ pub unsafe fn f() { //~ MONO_ITEM static f::S @@ asm_sym-cgu.0[External] static S: usize = 1; //~ MONO_ITEM fn f::fun @@ asm_sym-cgu.0[External] + #[inline(never)] fn fun() {} core::arch::asm!("/* {0} {1} */", sym S, sym fun); } //~ MONO_ITEM fn g @@ asm_sym-cgu.0[External] +#[inline(never)] pub unsafe fn g() { //~ MONO_ITEM static g::S @@ asm_sym-cgu.0[Internal] static S: usize = 2; //~ MONO_ITEM fn g::fun @@ asm_sym-cgu.0[Internal] + #[inline(never)] fn fun() {} core::arch::asm!("/* {0} {1} */", sym S, sym fun); } diff --git a/tests/codegen-units/item-collection/auxiliary/cgu_export_trait_method.rs b/tests/codegen-units/item-collection/auxiliary/cgu_export_trait_method.rs index ecea26dc4be..e94dded55cf 100644 --- a/tests/codegen-units/item-collection/auxiliary/cgu_export_trait_method.rs +++ b/tests/codegen-units/item-collection/auxiliary/cgu_export_trait_method.rs @@ -1,3 +1,5 @@ +// compile-flags: -Copt-level=0 + #![crate_type = "lib"] pub trait Trait : Sized { diff --git a/tests/codegen-units/item-collection/cross-crate-trait-method.rs b/tests/codegen-units/item-collection/cross-crate-trait-method.rs index b7216a14318..778b3820f18 100644 --- a/tests/codegen-units/item-collection/cross-crate-trait-method.rs +++ b/tests/codegen-units/item-collection/cross-crate-trait-method.rs @@ -1,4 +1,4 @@ -// compile-flags:-Zprint-mono-items=eager -Zinline-mir=no +// compile-flags:-Zprint-mono-items=eager -Zinline-mir=no -Copt-level=0 #![deny(dead_code)] #![feature(start)] diff --git a/tests/codegen-units/item-collection/items-within-generic-items.rs b/tests/codegen-units/item-collection/items-within-generic-items.rs index d37d7f7d9b2..bb1a3be36c5 100644 --- a/tests/codegen-units/item-collection/items-within-generic-items.rs +++ b/tests/codegen-units/item-collection/items-within-generic-items.rs @@ -1,4 +1,4 @@ -// compile-flags:-Zprint-mono-items=eager +// compile-flags:-Zprint-mono-items=eager -Copt-level=0 #![deny(dead_code)] #![feature(start)] diff --git a/tests/codegen-units/item-collection/unreferenced-const-fn.rs b/tests/codegen-units/item-collection/unreferenced-const-fn.rs index 17b92eae00d..5f59d801504 100644 --- a/tests/codegen-units/item-collection/unreferenced-const-fn.rs +++ b/tests/codegen-units/item-collection/unreferenced-const-fn.rs @@ -4,6 +4,7 @@ #![crate_type = "rlib"] //~ MONO_ITEM fn foo @@ unreferenced_const_fn-cgu.0[External] +#[inline(never)] pub const fn foo(x: u32) -> u32 { x + 0xf00 } diff --git a/tests/codegen/array-codegen.rs b/tests/codegen/array-codegen.rs index ba0d444f97e..bf5ae74679b 100644 --- a/tests/codegen/array-codegen.rs +++ b/tests/codegen/array-codegen.rs @@ -32,3 +32,25 @@ pub fn array_copy(a: &[u8; 4], p: &mut [u8; 4]) { // CHECK: store <4 x i8> %[[TEMP2]], ptr %p, align 1 *p = *a; } + +// CHECK-LABEL: @array_copy_1_element +#[no_mangle] +pub fn array_copy_1_element(a: &[u8; 1], p: &mut [u8; 1]) { + // CHECK: %[[LOCAL:.+]] = alloca [1 x i8], align 1 + // CHECK: %[[TEMP1:.+]] = load i8, ptr %a, align 1 + // CHECK: store i8 %[[TEMP1]], ptr %[[LOCAL]], align 1 + // CHECK: %[[TEMP2:.+]] = load i8, ptr %[[LOCAL]], align 1 + // CHECK: store i8 %[[TEMP2]], ptr %p, align 1 + *p = *a; +} + +// CHECK-LABEL: @array_copy_2_elements +#[no_mangle] +pub fn array_copy_2_elements(a: &[u8; 2], p: &mut [u8; 2]) { + // CHECK: %[[LOCAL:.+]] = alloca [2 x i8], align 1 + // CHECK: %[[TEMP1:.+]] = load <2 x i8>, ptr %a, align 1 + // CHECK: store <2 x i8> %[[TEMP1]], ptr %[[LOCAL]], align 1 + // CHECK: %[[TEMP2:.+]] = load <2 x i8>, ptr %[[LOCAL]], align 1 + // CHECK: store <2 x i8> %[[TEMP2]], ptr %p, align 1 + *p = *a; +} diff --git a/tests/codegen/array-optimized.rs b/tests/codegen/array-optimized.rs new file mode 100644 index 00000000000..27448fdcfad --- /dev/null +++ b/tests/codegen/array-optimized.rs @@ -0,0 +1,33 @@ +// compile-flags: -O + +#![crate_type = "lib"] + +// CHECK-LABEL: @array_copy_1_element +#[no_mangle] +pub fn array_copy_1_element(a: &[u8; 1], p: &mut [u8; 1]) { + // CHECK-NOT: alloca + // CHECK: %[[TEMP:.+]] = load i8, ptr %a, align 1 + // CHECK: store i8 %[[TEMP]], ptr %p, align 1 + // CHECK: ret + *p = *a; +} + +// CHECK-LABEL: @array_copy_2_elements +#[no_mangle] +pub fn array_copy_2_elements(a: &[u8; 2], p: &mut [u8; 2]) { + // CHECK-NOT: alloca + // CHECK: %[[TEMP:.+]] = load <2 x i8>, ptr %a, align 1 + // CHECK: store <2 x i8> %[[TEMP]], ptr %p, align 1 + // CHECK: ret + *p = *a; +} + +// CHECK-LABEL: @array_copy_4_elements +#[no_mangle] +pub fn array_copy_4_elements(a: &[u8; 4], p: &mut [u8; 4]) { + // CHECK-NOT: alloca + // CHECK: %[[TEMP:.+]] = load <4 x i8>, ptr %a, align 1 + // CHECK: store <4 x i8> %[[TEMP]], ptr %p, align 1 + // CHECK: ret + *p = *a; +} diff --git a/tests/codegen/asm-sanitize-llvm.rs b/tests/codegen/asm-sanitize-llvm.rs index 6dcacd08cac..41bed98038e 100644 --- a/tests/codegen/asm-sanitize-llvm.rs +++ b/tests/codegen/asm-sanitize-llvm.rs @@ -1,5 +1,5 @@ // FIXME(nagisa): remove the flags below once all targets support `asm!`. -// compile-flags: --target x86_64-unknown-linux-gnu +// compile-flags: --target x86_64-unknown-linux-gnu -Copt-level=0 // needs-llvm-components: x86 // Verify we sanitize the special tokens for the LLVM inline-assembly, ensuring people won't diff --git a/tests/codegen/async-fn-debug-awaitee-field.rs b/tests/codegen/async-fn-debug-awaitee-field.rs index 690505fd72b..29defe68f8b 100644 --- a/tests/codegen/async-fn-debug-awaitee-field.rs +++ b/tests/codegen/async-fn-debug-awaitee-field.rs @@ -3,7 +3,7 @@ // extensions rely on the field having this name. // ignore-tidy-linelength -// compile-flags: -C debuginfo=2 --edition=2018 +// compile-flags: -C debuginfo=2 --edition=2018 -Copt-level=0 #![crate_type = "lib"] diff --git a/tests/codegen/debug-linkage-name.rs b/tests/codegen/debug-linkage-name.rs index 9011a7da51d..9bf4d521fc0 100644 --- a/tests/codegen/debug-linkage-name.rs +++ b/tests/codegen/debug-linkage-name.rs @@ -1,8 +1,8 @@ // Verifies that linkage name is omitted when it is // the same as variable / function name. // -// compile-flags: -C no-prepopulate-passes -// compile-flags: -C debuginfo=2 +// compile-flags: -C no-prepopulate-passes -Copt-level=0 +// compile-flags: -C debuginfo=2 -Copt-level=0 #![crate_type = "lib"] pub mod xyz { diff --git a/tests/codegen/default-requires-uwtable.rs b/tests/codegen/default-requires-uwtable.rs index 5d77d3f14bb..26424f03568 100644 --- a/tests/codegen/default-requires-uwtable.rs +++ b/tests/codegen/default-requires-uwtable.rs @@ -1,5 +1,5 @@ // revisions: WINDOWS ANDROID -// compile-flags: -C panic=abort +// compile-flags: -C panic=abort -Copt-level=0 // [WINDOWS] compile-flags: --target=x86_64-pc-windows-msvc // [WINDOWS] needs-llvm-components: x86 // [ANDROID] compile-flags: --target=armv7-linux-androideabi diff --git a/tests/codegen/drop.rs b/tests/codegen/drop.rs index 3615ef47b53..14b5840e2fe 100644 --- a/tests/codegen/drop.rs +++ b/tests/codegen/drop.rs @@ -7,10 +7,12 @@ struct SomeUniqueName; impl Drop for SomeUniqueName { + #[inline(never)] fn drop(&mut self) { } } +#[inline(never)] pub fn possibly_unwinding() { } diff --git a/tests/codegen/force-frame-pointers.rs b/tests/codegen/force-frame-pointers.rs index 637c4234654..5791ae47937 100644 --- a/tests/codegen/force-frame-pointers.rs +++ b/tests/codegen/force-frame-pointers.rs @@ -1,4 +1,4 @@ -// compile-flags: -C no-prepopulate-passes -C force-frame-pointers=y +// compile-flags: -C no-prepopulate-passes -C force-frame-pointers=y -Copt-level=0 #![crate_type="lib"] diff --git a/tests/codegen/force-unwind-tables.rs b/tests/codegen/force-unwind-tables.rs index 4c0a5602c6d..c904978c9ff 100644 --- a/tests/codegen/force-unwind-tables.rs +++ b/tests/codegen/force-unwind-tables.rs @@ -1,4 +1,4 @@ -// compile-flags: -C no-prepopulate-passes -C force-unwind-tables=y +// compile-flags: -C no-prepopulate-passes -C force-unwind-tables=y -Copt-level=0 #![crate_type="lib"] diff --git a/tests/codegen/inline-function-args-debug-info.rs b/tests/codegen/inline-function-args-debug-info.rs index e3d8caa49d4..ffae99e0f24 100644 --- a/tests/codegen/inline-function-args-debug-info.rs +++ b/tests/codegen/inline-function-args-debug-info.rs @@ -6,6 +6,7 @@ #![crate_type = "lib"] +#[inline(never)] pub fn outer_function(x: usize, y: usize) -> usize { inner_function(x, y) + 1 } @@ -13,8 +14,8 @@ pub fn outer_function(x: usize, y: usize) -> usize { #[inline] fn inner_function(aaaa: usize, bbbb: usize) -> usize { // CHECK: !DILocalVariable(name: "aaaa", arg: 1 - // CHECK-SAME: line: 14 + // CHECK-SAME: line: 15 // CHECK: !DILocalVariable(name: "bbbb", arg: 2 - // CHECK-SAME: line: 14 + // CHECK-SAME: line: 15 aaaa + bbbb } diff --git a/tests/codegen/instrument-mcount.rs b/tests/codegen/instrument-mcount.rs index b26076e7a7b..50823775a41 100644 --- a/tests/codegen/instrument-mcount.rs +++ b/tests/codegen/instrument-mcount.rs @@ -1,5 +1,5 @@ // -// compile-flags: -Z instrument-mcount +// compile-flags: -Z instrument-mcount -Copt-level=0 #![crate_type = "lib"] diff --git a/tests/codegen/instrument-xray/basic.rs b/tests/codegen/instrument-xray/basic.rs index d3e49d53174..5da878474f2 100644 --- a/tests/codegen/instrument-xray/basic.rs +++ b/tests/codegen/instrument-xray/basic.rs @@ -1,7 +1,7 @@ // Checks that `-Z instrument-xray` produces expected instrumentation. // // needs-xray -// compile-flags: -Z instrument-xray=always +// compile-flags: -Z instrument-xray=always -Copt-level=0 #![crate_type = "lib"] diff --git a/tests/codegen/instrument-xray/options-combine.rs b/tests/codegen/instrument-xray/options-combine.rs index f7e500b65f6..d1e56586279 100644 --- a/tests/codegen/instrument-xray/options-combine.rs +++ b/tests/codegen/instrument-xray/options-combine.rs @@ -1,9 +1,9 @@ // Checks that `-Z instrument-xray` options can be specified multiple times. // // needs-xray -// compile-flags: -Z instrument-xray=skip-exit -// compile-flags: -Z instrument-xray=instruction-threshold=123 -// compile-flags: -Z instrument-xray=instruction-threshold=456 +// compile-flags: -Z instrument-xray=skip-exit -Copt-level=0 +// compile-flags: -Z instrument-xray=instruction-threshold=123 -Copt-level=0 +// compile-flags: -Z instrument-xray=instruction-threshold=456 -Copt-level=0 #![crate_type = "lib"] diff --git a/tests/codegen/instrument-xray/options-override.rs b/tests/codegen/instrument-xray/options-override.rs index 00f81837902..b1fc4c966dc 100644 --- a/tests/codegen/instrument-xray/options-override.rs +++ b/tests/codegen/instrument-xray/options-override.rs @@ -1,8 +1,8 @@ // Checks that the last `-Z instrument-xray` option wins. // // needs-xray -// compile-flags: -Z instrument-xray=always -// compile-flags: -Z instrument-xray=never +// compile-flags: -Z instrument-xray=always -Copt-level=0 +// compile-flags: -Z instrument-xray=never -Copt-level=0 #![crate_type = "lib"] diff --git a/tests/codegen/panic-unwind-default-uwtable.rs b/tests/codegen/panic-unwind-default-uwtable.rs index 4c85008cf35..b78b159d20d 100644 --- a/tests/codegen/panic-unwind-default-uwtable.rs +++ b/tests/codegen/panic-unwind-default-uwtable.rs @@ -1,4 +1,4 @@ -// compile-flags: -C panic=unwind -C no-prepopulate-passes +// compile-flags: -C panic=unwind -C no-prepopulate-passes -Copt-level=0 #![crate_type = "lib"] diff --git a/tests/codegen/personality_lifetimes.rs b/tests/codegen/personality_lifetimes.rs index 47243bece98..b39718a8d08 100644 --- a/tests/codegen/personality_lifetimes.rs +++ b/tests/codegen/personality_lifetimes.rs @@ -9,10 +9,12 @@ struct S; impl Drop for S { + #[inline(never)] fn drop(&mut self) { } } +#[inline(never)] fn might_unwind() { } diff --git a/tests/codegen/sanitizer/cfi-emit-type-metadata-attr-cfi-encoding.rs b/tests/codegen/sanitizer/cfi-emit-type-metadata-attr-cfi-encoding.rs index 084d8bf803c..f16890afad0 100644 --- a/tests/codegen/sanitizer/cfi-emit-type-metadata-attr-cfi-encoding.rs +++ b/tests/codegen/sanitizer/cfi-emit-type-metadata-attr-cfi-encoding.rs @@ -1,7 +1,7 @@ // Verifies that user-defined CFI encoding for types are emitted. // // needs-sanitizer-cfi -// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi +// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 #![crate_type="lib"] #![feature(cfi_encoding, extern_types)] diff --git a/tests/codegen/sanitizer/cfi-emit-type-metadata-id-itanium-cxx-abi.rs b/tests/codegen/sanitizer/cfi-emit-type-metadata-id-itanium-cxx-abi.rs index 2d8b13e2080..4ed7c27fc4e 100644 --- a/tests/codegen/sanitizer/cfi-emit-type-metadata-id-itanium-cxx-abi.rs +++ b/tests/codegen/sanitizer/cfi-emit-type-metadata-id-itanium-cxx-abi.rs @@ -1,7 +1,7 @@ // Verifies that type metadata identifiers for functions are emitted correctly. // // needs-sanitizer-cfi -// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi +// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Copt-level=0 #![crate_type="lib"] #![allow(dead_code)] diff --git a/tests/codegen/sanitizer/cfi-generalize-pointers.rs b/tests/codegen/sanitizer/cfi-generalize-pointers.rs index 677ebdb27ec..17cb42d3e74 100644 --- a/tests/codegen/sanitizer/cfi-generalize-pointers.rs +++ b/tests/codegen/sanitizer/cfi-generalize-pointers.rs @@ -1,7 +1,7 @@ // Verifies that pointer types are generalized. // // needs-sanitizer-cfi -// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers +// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-generalize-pointers -Copt-level=0 #![crate_type="lib"] diff --git a/tests/codegen/sanitizer/cfi-normalize-integers.rs b/tests/codegen/sanitizer/cfi-normalize-integers.rs index aa3913cb8e7..9663aa54c28 100644 --- a/tests/codegen/sanitizer/cfi-normalize-integers.rs +++ b/tests/codegen/sanitizer/cfi-normalize-integers.rs @@ -1,7 +1,7 @@ // Verifies that integer types are normalized. // // needs-sanitizer-cfi -// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers +// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi -Zsanitizer-cfi-normalize-integers -Copt-level=0 #![crate_type="lib"] diff --git a/tests/codegen/sanitizer/kasan-emits-instrumentation.rs b/tests/codegen/sanitizer/kasan-emits-instrumentation.rs index 783bc47b9d0..29d50d8df24 100644 --- a/tests/codegen/sanitizer/kasan-emits-instrumentation.rs +++ b/tests/codegen/sanitizer/kasan-emits-instrumentation.rs @@ -1,6 +1,6 @@ // Verifies that `-Zsanitizer=kernel-address` emits sanitizer instrumentation. -// compile-flags: -Zsanitizer=kernel-address +// compile-flags: -Zsanitizer=kernel-address -Copt-level=0 // revisions: aarch64 riscv64imac riscv64gc x86_64 //[aarch64] compile-flags: --target aarch64-unknown-none //[aarch64] needs-llvm-components: aarch64 diff --git a/tests/codegen/sanitizer/memtag-attr-check.rs b/tests/codegen/sanitizer/memtag-attr-check.rs index 2fd362656d4..3e5e14e8429 100644 --- a/tests/codegen/sanitizer/memtag-attr-check.rs +++ b/tests/codegen/sanitizer/memtag-attr-check.rs @@ -2,7 +2,7 @@ // applied when enabling the memtag sanitizer. // // needs-sanitizer-memtag -// compile-flags: -Zsanitizer=memtag -Ctarget-feature=+mte +// compile-flags: -Zsanitizer=memtag -Ctarget-feature=+mte -Copt-level=0 #![crate_type = "lib"] diff --git a/tests/codegen/sanitizer/no-sanitize.rs b/tests/codegen/sanitizer/no-sanitize.rs index d0b69243453..029cf8e7f5c 100644 --- a/tests/codegen/sanitizer/no-sanitize.rs +++ b/tests/codegen/sanitizer/no-sanitize.rs @@ -2,7 +2,7 @@ // selectively disable sanitizer instrumentation. // // needs-sanitizer-address -// compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static +// compile-flags: -Zsanitizer=address -Ctarget-feature=-crt-static -Copt-level=0 #![crate_type="lib"] #![feature(no_sanitize)] diff --git a/tests/codegen/sanitizer/safestack-attr-check.rs b/tests/codegen/sanitizer/safestack-attr-check.rs index b73ed00e730..b19e2d13133 100644 --- a/tests/codegen/sanitizer/safestack-attr-check.rs +++ b/tests/codegen/sanitizer/safestack-attr-check.rs @@ -1,7 +1,7 @@ // This tests that the safestack attribute is applied when enabling the safe-stack sanitizer. // // needs-sanitizer-safestack -// compile-flags: -Zsanitizer=safestack +// compile-flags: -Zsanitizer=safestack -Copt-level=0 #![crate_type = "lib"] diff --git a/tests/codegen/src-hash-algorithm/src-hash-algorithm-md5.rs b/tests/codegen/src-hash-algorithm/src-hash-algorithm-md5.rs index 64be1127786..6ef0f0406d2 100644 --- a/tests/codegen/src-hash-algorithm/src-hash-algorithm-md5.rs +++ b/tests/codegen/src-hash-algorithm/src-hash-algorithm-md5.rs @@ -1,4 +1,4 @@ -// compile-flags: -g -Z src-hash-algorithm=md5 +// compile-flags: -g -Z src-hash-algorithm=md5 -Copt-level=0 #![crate_type = "lib"] diff --git a/tests/codegen/src-hash-algorithm/src-hash-algorithm-sha1.rs b/tests/codegen/src-hash-algorithm/src-hash-algorithm-sha1.rs index 54e07152142..ebfa3040aca 100644 --- a/tests/codegen/src-hash-algorithm/src-hash-algorithm-sha1.rs +++ b/tests/codegen/src-hash-algorithm/src-hash-algorithm-sha1.rs @@ -1,4 +1,4 @@ -// compile-flags: -g -Z src-hash-algorithm=sha1 +// compile-flags: -g -Z src-hash-algorithm=sha1 -Copt-level=0 #![crate_type = "lib"] diff --git a/tests/codegen/src-hash-algorithm/src-hash-algorithm-sha256.rs b/tests/codegen/src-hash-algorithm/src-hash-algorithm-sha256.rs index dc7db8e2372..5ec678d55f3 100644 --- a/tests/codegen/src-hash-algorithm/src-hash-algorithm-sha256.rs +++ b/tests/codegen/src-hash-algorithm/src-hash-algorithm-sha256.rs @@ -1,4 +1,4 @@ -// compile-flags: -g -Z src-hash-algorithm=sha256 +// compile-flags: -g -Z src-hash-algorithm=sha256 -Copt-level=0 #![crate_type = "lib"] diff --git a/tests/codegen/target-cpu-on-functions.rs b/tests/codegen/target-cpu-on-functions.rs index c043eceb5cd..d5250f22cca 100644 --- a/tests/codegen/target-cpu-on-functions.rs +++ b/tests/codegen/target-cpu-on-functions.rs @@ -15,7 +15,8 @@ pub extern "C" fn exported() { // CHECK-LABEL: ; target_cpu_on_functions::not_exported // CHECK-NEXT: ; Function Attrs: -// CHECK-NEXT: define {{.*}}() {{.*}} #0 +// CHECK-NEXT: define {{.*}}() {{.*}} #1 +#[inline(never)] fn not_exported() {} // CHECK: attributes #0 = {{.*}} "target-cpu"="{{.*}}" diff --git a/tests/codegen/target-feature-inline-closure.rs b/tests/codegen/target-feature-inline-closure.rs index d075706173f..54cb27242d5 100644 --- a/tests/codegen/target-feature-inline-closure.rs +++ b/tests/codegen/target-feature-inline-closure.rs @@ -31,3 +31,7 @@ unsafe fn without_avx(x: __m256) -> __m256 { }; add(x, x) } + +// Don't allow the above CHECK-NOT to accidentally match a commit hash in the +// compiler version. +// CHECK-LABEL: rustc version diff --git a/tests/codegen/tied-features-strength.rs b/tests/codegen/tied-features-strength.rs index 51334c12158..71cea48c4da 100644 --- a/tests/codegen/tied-features-strength.rs +++ b/tests/codegen/tied-features-strength.rs @@ -7,16 +7,16 @@ // are targeting older LLVM versions. Once the min supported version // is LLVM-14 we can remove the optional regex matching for this feature. -// [ENABLE_SVE] compile-flags: -C target-feature=+sve +// [ENABLE_SVE] compile-flags: -C target-feature=+sve -Copt-level=0 // ENABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)?|(\+sve,?)|(\+neon,?))*}}" } -// [DISABLE_SVE] compile-flags: -C target-feature=-sve +// [DISABLE_SVE] compile-flags: -C target-feature=-sve -Copt-level=0 // DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)?|(-sve,?)|(\+neon,?))*}}" } -// [DISABLE_NEON] compile-flags: -C target-feature=-neon +// [DISABLE_NEON] compile-flags: -C target-feature=-neon -Copt-level=0 // DISABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)?|(-fp-armv8,?)|(-neon,?))*}}" } -// [ENABLE_NEON] compile-flags: -C target-feature=+neon +// [ENABLE_NEON] compile-flags: -C target-feature=+neon -Copt-level=0 // ENABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)?|(\+fp-armv8,?)|(\+neon,?))*}}" } diff --git a/tests/codegen/tune-cpu-on-functions.rs b/tests/codegen/tune-cpu-on-functions.rs index ed8dc0e9383..116f0772d25 100644 --- a/tests/codegen/tune-cpu-on-functions.rs +++ b/tests/codegen/tune-cpu-on-functions.rs @@ -3,7 +3,7 @@ // no-prefer-dynamic // -// compile-flags: -C no-prepopulate-passes -C panic=abort -C linker-plugin-lto -Cpasses=name-anon-globals -Z tune-cpu=generic +// compile-flags: -C no-prepopulate-passes -C panic=abort -C linker-plugin-lto -Cpasses=name-anon-globals -Z tune-cpu=generic -Copt-level=0 #![crate_type = "staticlib"] diff --git a/tests/codegen/vec_pop_push_noop.rs b/tests/codegen/vec_pop_push_noop.rs new file mode 100644 index 00000000000..8bc7b68a816 --- /dev/null +++ b/tests/codegen/vec_pop_push_noop.rs @@ -0,0 +1,24 @@ +// compile-flags: -O + +#![crate_type = "lib"] + +#[no_mangle] +// CHECK-LABEL: @noop( +pub fn noop(v: &mut Vec<u8>) { + // CHECK-NOT: reserve_for_push + // CHECK-NOT: call + // CHECK: tail call void @llvm.assume + // CHECK-NOT: reserve_for_push + // CHECK-NOT: call + // CHECK: ret + if let Some(x) = v.pop() { + v.push(x) + } +} + +#[no_mangle] +// CHECK-LABEL: @push_byte( +pub fn push_byte(v: &mut Vec<u8>) { + // CHECK: call {{.*}}reserve_for_push + v.push(3); +} diff --git a/tests/coverage-map/status-quo/issue-84561.cov-map b/tests/coverage-map/status-quo/issue-84561.cov-map index fe098fd396c..01fa7ec573c 100644 --- a/tests/coverage-map/status-quo/issue-84561.cov-map +++ b/tests/coverage-map/status-quo/issue-84561.cov-map @@ -1,11 +1,10 @@ Function name: <issue_84561::Foo as core::cmp::PartialEq>::eq -Raw bytes (14): 0x[01, 01, 00, 02, 01, 04, 0a, 00, 13, 00, 00, 0a, 00, 13] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 0a, 00, 13] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 -Number of file 0 mappings: 2 +Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 4, 10) to (start + 0, 19) -- Code(Zero) at (prev + 0, 10) to (start + 0, 19) Function name: <issue_84561::Foo as core::fmt::Debug>::fmt Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 89, 01, 09, 00, 25, 05, 00, 25, 00, 26, 02, 01, 09, 00, 0f, 07, 01, 05, 00, 06] diff --git a/tests/mir-opt/building/custom/consts.statics.built.after.mir b/tests/mir-opt/building/custom/consts.statics.built.after.mir index ea394c5b727..a5cb6ff992e 100644 --- a/tests/mir-opt/building/custom/consts.statics.built.after.mir +++ b/tests/mir-opt/building/custom/consts.statics.built.after.mir @@ -6,16 +6,16 @@ fn statics() -> () { let mut _2: *mut i32; bb0: { - _1 = const {alloc1: &i32}; - _2 = const {alloc2: *mut i32}; + _1 = const {ALLOC0: &i32}; + _2 = const {ALLOC1: *mut i32}; return; } } -alloc2 (static: T, size: 4, align: 4) { +ALLOC1 (static: T, size: 4, align: 4) { 0a 0a 0a 0a │ .... } -alloc1 (static: S, size: 4, align: 4) { +ALLOC0 (static: S, size: 4, align: 4) { 05 05 05 05 │ .... } diff --git a/tests/mir-opt/byte_slice.main.SimplifyCfg-elaborate-drops.after.mir b/tests/mir-opt/byte_slice.main.SimplifyCfg-elaborate-drops.after.mir index 9b17b4b63dd..09a65e6e6a6 100644 --- a/tests/mir-opt/byte_slice.main.SimplifyCfg-elaborate-drops.after.mir +++ b/tests/mir-opt/byte_slice.main.SimplifyCfg-elaborate-drops.after.mir @@ -23,6 +23,6 @@ fn main() -> () { } } -alloc1 (size: 3, align: 1) { +ALLOC0 (size: 3, align: 1) { 66 6f 6f │ foo } diff --git a/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir index 8c8e6959595..f20bfef8c79 100644 --- a/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir +++ b/tests/mir-opt/const_allocation.main.ConstProp.after.32bit.mir @@ -8,7 +8,7 @@ fn main() -> () { bb0: { StorageLive(_1); StorageLive(_2); - _2 = const {alloc1: &&[(Option<i32>, &[&str])]}; + _2 = const {ALLOC9: &&[(Option<i32>, &[&str])]}; _1 = (*_2); StorageDead(_2); StorageDead(_1); @@ -17,43 +17,43 @@ fn main() -> () { } } -alloc1 (static: FOO, size: 8, align: 4) { - ╾─alloc19─╼ 03 00 00 00 │ ╾──╼.... +ALLOC9 (static: FOO, size: 8, align: 4) { + ╾ALLOC0╼ 03 00 00 00 │ ╾──╼.... } -alloc19 (size: 48, align: 4) { - 0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc6──╼ 00 00 00 00 │ ....░░░░╾──╼.... - 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc10─╼ 02 00 00 00 │ ....░░░░╾──╼.... - 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc15─╼ 03 00 00 00 │ ....*...╾──╼.... +ALLOC0 (size: 48, align: 4) { + 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC1╼ 00 00 00 00 │ ....░░░░╾──╼.... + 0x10 │ 00 00 00 00 __ __ __ __ ╾ALLOC2╼ 02 00 00 00 │ ....░░░░╾──╼.... + 0x20 │ 01 00 00 00 2a 00 00 00 ╾ALLOC3╼ 03 00 00 00 │ ....*...╾──╼.... } -alloc6 (size: 0, align: 4) {} +ALLOC1 (size: 0, align: 4) {} -alloc10 (size: 16, align: 4) { - ╾─alloc9──╼ 03 00 00 00 ╾─alloc11─╼ 03 00 00 00 │ ╾──╼....╾──╼.... +ALLOC2 (size: 16, align: 4) { + ╾ALLOC4╼ 03 00 00 00 ╾ALLOC5╼ 03 00 00 00 │ ╾──╼....╾──╼.... } -alloc9 (size: 3, align: 1) { +ALLOC4 (size: 3, align: 1) { 66 6f 6f │ foo } -alloc11 (size: 3, align: 1) { +ALLOC5 (size: 3, align: 1) { 62 61 72 │ bar } -alloc15 (size: 24, align: 4) { - 0x00 │ ╾─alloc14─╼ 03 00 00 00 ╾─alloc16─╼ 03 00 00 00 │ ╾──╼....╾──╼.... - 0x10 │ ╾─alloc17─╼ 04 00 00 00 │ ╾──╼.... +ALLOC3 (size: 24, align: 4) { + 0x00 │ ╾ALLOC6╼ 03 00 00 00 ╾ALLOC7╼ 03 00 00 00 │ ╾──╼....╾──╼.... + 0x10 │ ╾ALLOC8╼ 04 00 00 00 │ ╾──╼.... } -alloc14 (size: 3, align: 1) { +ALLOC6 (size: 3, align: 1) { 6d 65 68 │ meh } -alloc16 (size: 3, align: 1) { +ALLOC7 (size: 3, align: 1) { 6d 6f 70 │ mop } -alloc17 (size: 4, align: 1) { +ALLOC8 (size: 4, align: 1) { 6d c3 b6 70 │ m..p } diff --git a/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir index e2254703296..263cae2f3ea 100644 --- a/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir +++ b/tests/mir-opt/const_allocation.main.ConstProp.after.64bit.mir @@ -8,7 +8,7 @@ fn main() -> () { bb0: { StorageLive(_1); StorageLive(_2); - _2 = const {alloc1: &&[(Option<i32>, &[&str])]}; + _2 = const {ALLOC9: &&[(Option<i32>, &[&str])]}; _1 = (*_2); StorageDead(_2); StorageDead(_1); @@ -17,47 +17,47 @@ fn main() -> () { } } -alloc1 (static: FOO, size: 16, align: 8) { - ╾───────alloc19───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ +ALLOC9 (static: FOO, size: 16, align: 8) { + ╾ALLOC0╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ } -alloc19 (size: 72, align: 8) { - 0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc6────────╼ │ ....░░░░╾──────╼ +ALLOC0 (size: 72, align: 8) { + 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC1╼ │ ....░░░░╾──────╼ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░ - 0x20 │ ╾───────alloc10───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc15───────╼ │ ....*...╾──────╼ + 0x20 │ ╾ALLOC2╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x30 │ 01 00 00 00 2a 00 00 00 ╾ALLOC3╼ │ ....*...╾──────╼ 0x40 │ 03 00 00 00 00 00 00 00 │ ........ } -alloc6 (size: 0, align: 8) {} +ALLOC1 (size: 0, align: 8) {} -alloc10 (size: 32, align: 8) { - 0x00 │ ╾───────alloc9────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x10 │ ╾───────alloc11───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ +ALLOC2 (size: 32, align: 8) { + 0x00 │ ╾ALLOC4╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x10 │ ╾ALLOC5╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ } -alloc9 (size: 3, align: 1) { +ALLOC4 (size: 3, align: 1) { 66 6f 6f │ foo } -alloc11 (size: 3, align: 1) { +ALLOC5 (size: 3, align: 1) { 62 61 72 │ bar } -alloc15 (size: 48, align: 8) { - 0x00 │ ╾───────alloc14───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x10 │ ╾───────alloc16───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x20 │ ╾───────alloc17───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ +ALLOC3 (size: 48, align: 8) { + 0x00 │ ╾ALLOC6╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x10 │ ╾ALLOC7╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x20 │ ╾ALLOC8╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ } -alloc14 (size: 3, align: 1) { +ALLOC6 (size: 3, align: 1) { 6d 65 68 │ meh } -alloc16 (size: 3, align: 1) { +ALLOC7 (size: 3, align: 1) { 6d 6f 70 │ mop } -alloc17 (size: 4, align: 1) { +ALLOC8 (size: 4, align: 1) { 6d c3 b6 70 │ m..p } diff --git a/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir index c5f6902b4b4..713abb264a7 100644 --- a/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir +++ b/tests/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir @@ -8,7 +8,7 @@ fn main() -> () { bb0: { StorageLive(_1); StorageLive(_2); - _2 = const {alloc1: &&[(Option<i32>, &[&u8])]}; + _2 = const {ALLOC9: &&[(Option<i32>, &[&u8])]}; _1 = (*_2); StorageDead(_2); StorageDead(_1); @@ -17,42 +17,42 @@ fn main() -> () { } } -alloc1 (static: FOO, size: 8, align: 4) { - ╾─alloc23─╼ 03 00 00 00 │ ╾──╼.... +ALLOC9 (static: FOO, size: 8, align: 4) { + ╾ALLOC0╼ 03 00 00 00 │ ╾──╼.... } -alloc23 (size: 48, align: 4) { - 0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc10─╼ 00 00 00 00 │ ....░░░░╾──╼.... - 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc15─╼ 02 00 00 00 │ ....░░░░╾──╼.... - 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc21─╼ 03 00 00 00 │ ....*...╾──╼.... +ALLOC0 (size: 48, align: 4) { + 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC1╼ 00 00 00 00 │ ....░░░░╾──╼.... + 0x10 │ 00 00 00 00 __ __ __ __ ╾ALLOC2╼ 02 00 00 00 │ ....░░░░╾──╼.... + 0x20 │ 01 00 00 00 2a 00 00 00 ╾ALLOC3╼ 03 00 00 00 │ ....*...╾──╼.... } -alloc10 (size: 0, align: 4) {} +ALLOC1 (size: 0, align: 4) {} -alloc15 (size: 8, align: 4) { - ╾─alloc13─╼ ╾─alloc14─╼ │ ╾──╼╾──╼ +ALLOC2 (size: 8, align: 4) { + ╾ALLOC4╼ ╾ALLOC5╼ │ ╾──╼╾──╼ } -alloc13 (size: 1, align: 1) { +ALLOC4 (size: 1, align: 1) { 05 │ . } -alloc14 (size: 1, align: 1) { +ALLOC5 (size: 1, align: 1) { 06 │ . } -alloc21 (size: 12, align: 4) { - ╾─a18+0x3─╼ ╾─alloc19─╼ ╾─a20+0x2─╼ │ ╾──╼╾──╼╾──╼ +ALLOC3 (size: 12, align: 4) { + ╾ALLOC6+0x3╼ ╾ALLOC7╼ ╾ALLOC8+0x2╼ │ ╾──╼╾──╼╾──╼ } -alloc18 (size: 4, align: 1) { +ALLOC6 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } -alloc19 (size: 1, align: 1) { +ALLOC7 (size: 1, align: 1) { 2a │ * } -alloc20 (size: 4, align: 1) { +ALLOC8 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } diff --git a/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir index b95b8c78748..e9d61ef120c 100644 --- a/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir +++ b/tests/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir @@ -8,7 +8,7 @@ fn main() -> () { bb0: { StorageLive(_1); StorageLive(_2); - _2 = const {alloc1: &&[(Option<i32>, &[&u8])]}; + _2 = const {ALLOC9: &&[(Option<i32>, &[&u8])]}; _1 = (*_2); StorageDead(_2); StorageDead(_1); @@ -17,45 +17,45 @@ fn main() -> () { } } -alloc1 (static: FOO, size: 16, align: 8) { - ╾───────alloc23───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ +ALLOC9 (static: FOO, size: 16, align: 8) { + ╾ALLOC0╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ } -alloc23 (size: 72, align: 8) { - 0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc10───────╼ │ ....░░░░╾──────╼ +ALLOC0 (size: 72, align: 8) { + 0x00 │ 00 00 00 00 __ __ __ __ ╾ALLOC1╼ │ ....░░░░╾──────╼ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░ - 0x20 │ ╾───────alloc15───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc21───────╼ │ ....*...╾──────╼ + 0x20 │ ╾ALLOC2╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x30 │ 01 00 00 00 2a 00 00 00 ╾ALLOC3╼ │ ....*...╾──────╼ 0x40 │ 03 00 00 00 00 00 00 00 │ ........ } -alloc10 (size: 0, align: 8) {} +ALLOC1 (size: 0, align: 8) {} -alloc15 (size: 16, align: 8) { - ╾───────alloc13───────╼ ╾───────alloc14───────╼ │ ╾──────╼╾──────╼ +ALLOC2 (size: 16, align: 8) { + ╾ALLOC4╼ ╾ALLOC5╼ │ ╾──────╼╾──────╼ } -alloc13 (size: 1, align: 1) { +ALLOC4 (size: 1, align: 1) { 05 │ . } -alloc14 (size: 1, align: 1) { +ALLOC5 (size: 1, align: 1) { 06 │ . } -alloc21 (size: 24, align: 8) { - 0x00 │ ╾─────alloc18+0x3─────╼ ╾───────alloc19───────╼ │ ╾──────╼╾──────╼ - 0x10 │ ╾─────alloc20+0x2─────╼ │ ╾──────╼ +ALLOC3 (size: 24, align: 8) { + 0x00 │ ╾ALLOC6+0x3╼ ╾ALLOC7╼ │ ╾──────╼╾──────╼ + 0x10 │ ╾ALLOC8+0x2╼ │ ╾──────╼ } -alloc18 (size: 4, align: 1) { +ALLOC6 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } -alloc19 (size: 1, align: 1) { +ALLOC7 (size: 1, align: 1) { 2a │ * } -alloc20 (size: 4, align: 1) { +ALLOC8 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } diff --git a/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir b/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir index e172c754001..c18c067c72e 100644 --- a/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir +++ b/tests/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir @@ -8,7 +8,7 @@ fn main() -> () { bb0: { StorageLive(_1); StorageLive(_2); - _2 = const {alloc1: &&Packed}; + _2 = const {ALLOC4: &&Packed}; _1 = (*_2); StorageDead(_2); StorageDead(_1); @@ -17,31 +17,31 @@ fn main() -> () { } } -alloc1 (static: FOO, size: 4, align: 4) { - ╾─alloc12─╼ │ ╾──╼ +ALLOC4 (static: FOO, size: 4, align: 4) { + ╾ALLOC0╼ │ ╾──╼ } -alloc12 (size: 168, align: 1) { +ALLOC0 (size: 168, align: 1) { 0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................ - 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc7──╼ │ ............╾──╼ + 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾ALLOC1╼ │ ............╾──╼ 0x20 │ 01 ef cd ab 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x50 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ - 0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾─alloc9──╼ 00 00 │ ..........╾──╼.. - 0x90 │ ╾a10+0x63─╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............ + 0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾ALLOC2╼ 00 00 │ ..........╾──╼.. + 0x90 │ ╾ALLOC3+0x63╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............ 0xa0 │ 00 00 00 00 00 00 00 00 │ ........ } -alloc7 (size: 4, align: 4) { +ALLOC1 (size: 4, align: 4) { 2a 00 00 00 │ *... } -alloc9 (fn: main) +ALLOC2 (fn: main) -alloc10 (size: 100, align: 1) { +ALLOC3 (size: 100, align: 1) { 0x00 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x20 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ diff --git a/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir b/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir index d5feea723e7..6af0e3cbd94 100644 --- a/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir +++ b/tests/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir @@ -8,7 +8,7 @@ fn main() -> () { bb0: { StorageLive(_1); StorageLive(_2); - _2 = const {alloc1: &&Packed}; + _2 = const {ALLOC2: &&Packed}; _1 = (*_2); StorageDead(_2); StorageDead(_1); @@ -17,13 +17,13 @@ fn main() -> () { } } -alloc1 (static: FOO, size: 8, align: 8) { - ╾───────alloc12───────╼ │ ╾──────╼ +ALLOC2 (static: FOO, size: 8, align: 8) { + ╾ALLOC0╼ │ ╾──────╼ } -alloc12 (size: 180, align: 1) { +ALLOC0 (size: 180, align: 1) { 0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................ - 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──alloc7── │ ............╾─── + 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──ALLOC3── │ ............╾─── 0x20 │ ──────────╼ 01 ef cd ab 00 00 00 00 00 00 00 00 │ ───╼............ 0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ @@ -31,18 +31,18 @@ alloc12 (size: 180, align: 1) { 0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x80 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ╾──── │ ..............╾─ - 0x90 │ ─────alloc9─────╼ 00 00 ╾────alloc10+0x63─────╼ │ ─────╼..╾──────╼ + 0x90 │ ─────ALLOC4─────╼ 00 00 ╾ALLOC1+0x63╼ │ ─────╼..╾──────╼ 0xa0 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0xb0 │ 00 00 00 00 │ .... } -alloc7 (size: 4, align: 4) { +ALLOC3 (size: 4, align: 4) { 2a 00 00 00 │ *... } -alloc9 (fn: main) +ALLOC4 (fn: main) -alloc10 (size: 100, align: 1) { +ALLOC1 (size: 100, align: 1) { 0x00 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x20 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ diff --git a/tests/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir b/tests/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir index 5b8d3ca78e3..960b982242d 100644 --- a/tests/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir +++ b/tests/mir-opt/const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir @@ -7,7 +7,7 @@ promoted[0] in BAR: &[&i32; 1] = { let mut _3: &i32; bb0: { - _3 = const {alloc1: &i32}; + _3 = const {ALLOC0: &i32}; _2 = &(*_3); _1 = [move _2]; _0 = &_1; @@ -15,6 +15,6 @@ promoted[0] in BAR: &[&i32; 1] = { } } -alloc1 (static: Y, size: 4, align: 4) { +ALLOC0 (static: Y, size: 4, align: 4) { 2a 00 00 00 │ *... } diff --git a/tests/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff b/tests/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff index 14d2d7fc85c..4a93db3fcaa 100644 --- a/tests/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff +++ b/tests/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff @@ -16,7 +16,7 @@ - StorageLive(_3); - StorageLive(_4); - StorageLive(_5); -- _5 = const {alloc1: &i32}; +- _5 = const {ALLOC0: &i32}; - _4 = &(*_5); - _3 = [move _4]; - _2 = &_3; @@ -40,7 +40,7 @@ } - } - -- alloc1 (static: Y, size: 4, align: 4) { +- ALLOC0 (static: Y, size: 4, align: 4) { - 2a 00 00 00 │ *... } diff --git a/tests/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir b/tests/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir index 85355389be5..a9c05442764 100644 --- a/tests/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir +++ b/tests/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir @@ -7,7 +7,7 @@ promoted[0] in FOO: &[&i32; 1] = { let mut _3: *const i32; bb0: { - _3 = const {alloc3: *const i32}; + _3 = const {ALLOC0: *const i32}; _2 = &(*_3); _1 = [move _2]; _0 = &_1; @@ -15,4 +15,4 @@ promoted[0] in FOO: &[&i32; 1] = { } } -alloc3 (extern static: X) +ALLOC0 (extern static: X) diff --git a/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff index ffdd195eca3..21d21b0eee0 100644 --- a/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff +++ b/tests/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff @@ -18,7 +18,7 @@ - StorageLive(_3); - StorageLive(_4); - StorageLive(_5); -- _5 = const {alloc3: *const i32}; +- _5 = const {ALLOC0: *const i32}; - _4 = &(*_5); - _3 = [move _4]; - _2 = &_3; @@ -42,5 +42,5 @@ } } - -- alloc3 (extern static: X) +- ALLOC0 (extern static: X) diff --git a/tests/mir-opt/const_prop/checked_add.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/checked_add.main.ConstProp.panic-abort.diff index c2fd7f65f5e..5a958cc7a47 100644 --- a/tests/mir-opt/const_prop/checked_add.main.ConstProp.panic-abort.diff +++ b/tests/mir-opt/const_prop/checked_add.main.ConstProp.panic-abort.diff @@ -26,7 +26,7 @@ } + } + -+ alloc3 (size: 8, align: 4) { ++ ALLOC0 (size: 8, align: 4) { + 02 00 00 00 00 __ __ __ │ .....░░░ } diff --git a/tests/mir-opt/const_prop/checked_add.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/checked_add.main.ConstProp.panic-unwind.diff index 21a31f9aba3..ab48186aed9 100644 --- a/tests/mir-opt/const_prop/checked_add.main.ConstProp.panic-unwind.diff +++ b/tests/mir-opt/const_prop/checked_add.main.ConstProp.panic-unwind.diff @@ -26,7 +26,7 @@ } + } + -+ alloc3 (size: 8, align: 4) { ++ ALLOC0 (size: 8, align: 4) { + 02 00 00 00 00 __ __ __ │ .....░░░ } diff --git a/tests/mir-opt/const_prop/indirect.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/indirect.main.ConstProp.panic-abort.diff index c0efc873029..530cfc6539a 100644 --- a/tests/mir-opt/const_prop/indirect.main.ConstProp.panic-abort.diff +++ b/tests/mir-opt/const_prop/indirect.main.ConstProp.panic-abort.diff @@ -31,7 +31,7 @@ } + } + -+ alloc3 (size: 2, align: 1) { ++ ALLOC0 (size: 2, align: 1) { + 03 00 │ .. } diff --git a/tests/mir-opt/const_prop/indirect.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/indirect.main.ConstProp.panic-unwind.diff index 2aee6f164ae..08cf72e47a9 100644 --- a/tests/mir-opt/const_prop/indirect.main.ConstProp.panic-unwind.diff +++ b/tests/mir-opt/const_prop/indirect.main.ConstProp.panic-unwind.diff @@ -31,7 +31,7 @@ } + } + -+ alloc3 (size: 2, align: 1) { ++ ALLOC0 (size: 2, align: 1) { + 03 00 │ .. } 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 d585ae89e82..b30deb2a4d4 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 @@ -39,7 +39,7 @@ } + } + -+ alloc3 (size: 2, align: 1) { ++ ALLOC0 (size: 2, align: 1) { + 00 01 │ .. } 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 9fe39090638..47c51196c02 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 @@ -39,7 +39,7 @@ } + } + -+ alloc3 (size: 2, align: 1) { ++ ALLOC0 (size: 2, align: 1) { + 00 01 │ .. } diff --git a/tests/mir-opt/const_prop/issue_66971.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/issue_66971.main.ConstProp.panic-abort.diff index 18341ba7db9..6484b4b67af 100644 --- a/tests/mir-opt/const_prop/issue_66971.main.ConstProp.panic-abort.diff +++ b/tests/mir-opt/const_prop/issue_66971.main.ConstProp.panic-abort.diff @@ -20,11 +20,11 @@ } + } + -+ alloc8 (size: 2, align: 1) { ++ ALLOC0 (size: 2, align: 1) { + 00 00 │ .. + } + -+ alloc7 (size: 2, align: 1) { ++ ALLOC1 (size: 2, align: 1) { + 00 00 │ .. } diff --git a/tests/mir-opt/const_prop/issue_66971.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/issue_66971.main.ConstProp.panic-unwind.diff index 50763c10f0c..b02f0407839 100644 --- a/tests/mir-opt/const_prop/issue_66971.main.ConstProp.panic-unwind.diff +++ b/tests/mir-opt/const_prop/issue_66971.main.ConstProp.panic-unwind.diff @@ -20,11 +20,11 @@ } + } + -+ alloc8 (size: 2, align: 1) { ++ ALLOC0 (size: 2, align: 1) { + 00 00 │ .. + } + -+ alloc7 (size: 2, align: 1) { ++ ALLOC1 (size: 2, align: 1) { + 00 00 │ .. } diff --git a/tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-abort.diff index 015180db896..c1ef453e9df 100644 --- a/tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-abort.diff +++ b/tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-abort.diff @@ -25,15 +25,15 @@ } + } + -+ alloc12 (size: 2, align: 1) { ++ ALLOC0 (size: 2, align: 1) { + 01 02 │ .. + } + -+ alloc11 (size: 2, align: 1) { ++ ALLOC1 (size: 2, align: 1) { + 01 02 │ .. + } + -+ alloc8 (size: 2, align: 1) { ++ ALLOC2 (size: 2, align: 1) { + 01 02 │ .. } diff --git a/tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-unwind.diff index 8e41705c1af..53cdcc18167 100644 --- a/tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-unwind.diff +++ b/tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-unwind.diff @@ -25,15 +25,15 @@ } + } + -+ alloc12 (size: 2, align: 1) { ++ ALLOC0 (size: 2, align: 1) { + 01 02 │ .. + } + -+ alloc11 (size: 2, align: 1) { ++ ALLOC1 (size: 2, align: 1) { + 01 02 │ .. + } + -+ alloc8 (size: 2, align: 1) { ++ ALLOC2 (size: 2, align: 1) { + 01 02 │ .. } diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff b/tests/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff index 56a127ae31e..c3ace9687e6 100644 --- a/tests/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/mutable_variable_aggregate.main.ConstProp.diff @@ -27,11 +27,11 @@ } + } + -+ alloc7 (size: 8, align: 4) { ++ ALLOC0 (size: 8, align: 4) { + 2a 00 00 00 63 00 00 00 │ *...c... + } + -+ alloc5 (size: 8, align: 4) { ++ ALLOC1 (size: 8, align: 4) { + 2a 00 00 00 2b 00 00 00 │ *...+... } diff --git a/tests/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff b/tests/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff index ac26f8ef4ae..1f74bdcfd03 100644 --- a/tests/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff @@ -23,7 +23,7 @@ StorageLive(_2); StorageLive(_3); StorageLive(_4); - _4 = const {alloc1: *mut u32}; + _4 = const {ALLOC0: *mut u32}; _3 = (*_4); _1 = move _3; StorageDead(_3); @@ -39,7 +39,7 @@ } } - alloc1 (static: STATIC, size: 4, align: 4) { + ALLOC0 (static: STATIC, size: 4, align: 4) { 42 42 42 42 │ BBBB } diff --git a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.panic-abort.diff index a1b433716c8..85bd2b6e722 100644 --- a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.panic-abort.diff +++ b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.panic-abort.diff @@ -48,7 +48,7 @@ } + } + -+ alloc7 (size: 8, align: 4) { ++ ALLOC0 (size: 8, align: 4) { + 01 00 00 00 02 00 00 00 │ ........ } diff --git a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.panic-unwind.diff index 2dc514194bc..06e96e57a62 100644 --- a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.panic-unwind.diff +++ b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.panic-unwind.diff @@ -48,7 +48,7 @@ } + } + -+ alloc7 (size: 8, align: 4) { ++ ALLOC0 (size: 8, align: 4) { + 01 00 00 00 02 00 00 00 │ ........ } diff --git a/tests/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff b/tests/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff index 29c455f35b3..e193c82d2c0 100644 --- a/tests/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff +++ b/tests/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff @@ -16,12 +16,12 @@ StorageLive(_1); StorageLive(_2); StorageLive(_3); - _3 = const {alloc1: &u8}; + _3 = const {ALLOC0: &u8}; - _2 = (*_3); + _2 = const 2_u8; StorageLive(_4); StorageLive(_5); - _5 = const {alloc1: &u8}; + _5 = const {ALLOC0: &u8}; - _4 = (*_5); - _1 = Add(move _2, move _4); + _4 = const 2_u8; @@ -36,7 +36,7 @@ } } - alloc1 (static: FOO, size: 1, align: 1) { + ALLOC0 (static: FOO, size: 1, align: 1) { 02 │ . } diff --git a/tests/mir-opt/const_prop/return_place.add.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/return_place.add.ConstProp.panic-abort.diff index 6c9de476465..974a42e5078 100644 --- a/tests/mir-opt/const_prop/return_place.add.ConstProp.panic-abort.diff +++ b/tests/mir-opt/const_prop/return_place.add.ConstProp.panic-abort.diff @@ -19,7 +19,7 @@ } + } + -+ alloc5 (size: 8, align: 4) { ++ ALLOC0 (size: 8, align: 4) { + 04 00 00 00 00 __ __ __ │ .....░░░ } diff --git a/tests/mir-opt/const_prop/return_place.add.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/return_place.add.ConstProp.panic-unwind.diff index 0f079278c43..55dbc700285 100644 --- a/tests/mir-opt/const_prop/return_place.add.ConstProp.panic-unwind.diff +++ b/tests/mir-opt/const_prop/return_place.add.ConstProp.panic-unwind.diff @@ -19,7 +19,7 @@ } + } + -+ alloc5 (size: 8, align: 4) { ++ ALLOC0 (size: 8, align: 4) { + 04 00 00 00 00 __ __ __ │ .....░░░ } diff --git a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-abort.mir b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-abort.mir index c2488f3944c..f87c26bb004 100644 --- a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-abort.mir +++ b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-abort.mir @@ -15,6 +15,6 @@ fn add() -> u32 { } } -alloc5 (size: 8, align: 4) { +ALLOC0 (size: 8, align: 4) { 04 00 00 00 00 __ __ __ │ .....░░░ } diff --git a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir index fa0b9c77eaf..33f97591387 100644 --- a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir +++ b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir @@ -15,6 +15,6 @@ fn add() -> u32 { } } -alloc5 (size: 8, align: 4) { +ALLOC0 (size: 8, align: 4) { 04 00 00 00 00 __ __ __ │ .....░░░ } diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-abort.diff index 988ef7dd225..f19650d5a83 100644 --- a/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-abort.diff +++ b/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-abort.diff @@ -31,15 +31,15 @@ } + } + -+ alloc9 (size: 8, align: 4) { ++ ALLOC0 (size: 8, align: 4) { + 01 00 00 00 02 00 00 00 │ ........ + } + -+ alloc8 (size: 8, align: 4) { ++ ALLOC1 (size: 8, align: 4) { + 01 00 00 00 02 00 00 00 │ ........ + } + -+ alloc6 (size: 8, align: 4) { ++ ALLOC2 (size: 8, align: 4) { + 01 00 00 00 02 00 00 00 │ ........ } diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-unwind.diff index 29844619720..67307c42331 100644 --- a/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-unwind.diff +++ b/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-unwind.diff @@ -31,15 +31,15 @@ } + } + -+ alloc9 (size: 8, align: 4) { ++ ALLOC0 (size: 8, align: 4) { + 01 00 00 00 02 00 00 00 │ ........ + } + -+ alloc8 (size: 8, align: 4) { ++ ALLOC1 (size: 8, align: 4) { + 01 00 00 00 02 00 00 00 │ ........ + } + -+ alloc6 (size: 8, align: 4) { ++ ALLOC2 (size: 8, align: 4) { + 01 00 00 00 02 00 00 00 │ ........ } diff --git a/tests/mir-opt/copy-prop/calls.multiple_edges.CopyProp.diff b/tests/mir-opt/copy-prop/calls.multiple_edges.CopyProp.diff new file mode 100644 index 00000000000..4d56a8b25d3 --- /dev/null +++ b/tests/mir-opt/copy-prop/calls.multiple_edges.CopyProp.diff @@ -0,0 +1,21 @@ +- // MIR for `multiple_edges` before CopyProp ++ // MIR for `multiple_edges` after CopyProp + + fn multiple_edges(_1: bool) -> u8 { + let mut _0: u8; + let mut _2: u8; + + bb0: { + switchInt(_1) -> [1: bb1, otherwise: bb2]; + } + + bb1: { + _2 = dummy(const 13_u8) -> [return: bb2, unwind continue]; + } + + bb2: { + _0 = _2; + return; + } + } + diff --git a/tests/mir-opt/copy-prop/calls.nrvo.CopyProp.diff b/tests/mir-opt/copy-prop/calls.nrvo.CopyProp.diff new file mode 100644 index 00000000000..b5d56909b0d --- /dev/null +++ b/tests/mir-opt/copy-prop/calls.nrvo.CopyProp.diff @@ -0,0 +1,24 @@ +- // MIR for `nrvo` before CopyProp ++ // MIR for `nrvo` after CopyProp + + fn nrvo() -> u8 { + let mut _0: u8; + let _1: u8; + scope 1 { +- debug y => _1; ++ debug y => _0; + } + + bb0: { +- StorageLive(_1); +- _1 = dummy(const 5_u8) -> [return: bb1, unwind continue]; ++ _0 = dummy(const 5_u8) -> [return: bb1, unwind continue]; + } + + bb1: { +- _0 = _1; +- StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/copy-prop/calls.rs b/tests/mir-opt/copy-prop/calls.rs new file mode 100644 index 00000000000..c1f86f1f412 --- /dev/null +++ b/tests/mir-opt/copy-prop/calls.rs @@ -0,0 +1,43 @@ +// Check that CopyProp does propagate return values of call terminators. +// unit-test: CopyProp +// needs-unwind + +#![feature(custom_mir, core_intrinsics)] +use std::intrinsics::mir::*; + +#[inline(never)] +fn dummy(x: u8) -> u8 { + x +} + +// EMIT_MIR calls.nrvo.CopyProp.diff +fn nrvo() -> u8 { + let y = dummy(5); // this should get NRVO + y +} + +// EMIT_MIR calls.multiple_edges.CopyProp.diff +#[custom_mir(dialect = "runtime", phase = "initial")] +fn multiple_edges(t: bool) -> u8 { + mir! { + let x: u8; + { + match t { true => bbt, _ => ret } + } + bbt = { + Call(x = dummy(13), ret) + } + ret = { + // `x` is not assigned on the `bb0 -> ret` edge, + // so should not be marked as SSA for merging with `_0`. + RET = x; + Return() + } + } +} + +fn main() { + // Make sure the function actually gets instantiated. + nrvo(); + multiple_edges(false); +} diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-abort.diff index b9b46f16a8b..9bfd46231c4 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-abort.diff @@ -87,13 +87,13 @@ + _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; StorageDead(_5); - _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize)); -+ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc7, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; ++ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; StorageDead(_4); - _2 = Box::<[bool]>(_3, const std::alloc::Global); -+ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc10, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); ++ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); StorageDead(_3); - _1 = A { foo: move _2 }; -+ _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc11, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }; ++ _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }; StorageDead(_2); _0 = const (); drop(_1) -> [return: bb1, unwind unreachable]; @@ -105,15 +105,15 @@ } + } + -+ alloc11 (size: 8, align: 4) { ++ ALLOC2 (size: 8, align: 4) { + 01 00 00 00 00 00 00 00 │ ........ + } + -+ alloc10 (size: 8, align: 4) { ++ ALLOC1 (size: 8, align: 4) { + 01 00 00 00 00 00 00 00 │ ........ + } + -+ alloc7 (size: 8, align: 4) { ++ ALLOC0 (size: 8, align: 4) { + 01 00 00 00 00 00 00 00 │ ........ } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-unwind.diff index 93b18f23e61..dba50b1428e 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.32bit.panic-unwind.diff @@ -87,13 +87,13 @@ + _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; StorageDead(_5); - _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize)); -+ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc7, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; ++ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; StorageDead(_4); - _2 = Box::<[bool]>(_3, const std::alloc::Global); -+ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc10, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); ++ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); StorageDead(_3); - _1 = A { foo: move _2 }; -+ _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc11, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }; ++ _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }; StorageDead(_2); _0 = const (); drop(_1) -> [return: bb1, unwind: bb2]; @@ -109,15 +109,15 @@ } + } + -+ alloc11 (size: 8, align: 4) { ++ ALLOC2 (size: 8, align: 4) { + 01 00 00 00 00 00 00 00 │ ........ + } + -+ alloc10 (size: 8, align: 4) { ++ ALLOC1 (size: 8, align: 4) { + 01 00 00 00 00 00 00 00 │ ........ + } + -+ alloc7 (size: 8, align: 4) { ++ ALLOC0 (size: 8, align: 4) { + 01 00 00 00 00 00 00 00 │ ........ } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-abort.diff index 3d3af62856b..33fe4628d83 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-abort.diff @@ -87,13 +87,13 @@ + _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; StorageDead(_5); - _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize)); -+ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc7, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; ++ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; StorageDead(_4); - _2 = Box::<[bool]>(_3, const std::alloc::Global); -+ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc10, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); ++ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); StorageDead(_3); - _1 = A { foo: move _2 }; -+ _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc11, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }; ++ _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }; StorageDead(_2); _0 = const (); drop(_1) -> [return: bb1, unwind unreachable]; @@ -105,15 +105,15 @@ } + } + -+ alloc11 (size: 16, align: 8) { ++ ALLOC2 (size: 16, align: 8) { + 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ + } + -+ alloc10 (size: 16, align: 8) { ++ ALLOC1 (size: 16, align: 8) { + 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ + } + -+ alloc7 (size: 16, align: 8) { ++ ALLOC0 (size: 16, align: 8) { + 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-unwind.diff index 1933f9bafb3..b2d561911de 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.ConstProp.64bit.panic-unwind.diff @@ -87,13 +87,13 @@ + _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; StorageDead(_5); - _3 = move _4 as std::ptr::Unique<[bool]> (PointerCoercion(Unsize)); -+ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc7, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; ++ _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; StorageDead(_4); - _2 = Box::<[bool]>(_3, const std::alloc::Global); -+ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc10, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); ++ _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); StorageDead(_3); - _1 = A { foo: move _2 }; -+ _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc11, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }; ++ _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }; StorageDead(_2); _0 = const (); drop(_1) -> [return: bb1, unwind: bb2]; @@ -109,15 +109,15 @@ } + } + -+ alloc11 (size: 16, align: 8) { ++ ALLOC2 (size: 16, align: 8) { + 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ + } + -+ alloc10 (size: 16, align: 8) { ++ ALLOC1 (size: 16, align: 8) { + 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ + } + -+ alloc7 (size: 16, align: 8) { ++ ALLOC0 (size: 16, align: 8) { + 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff index 7862c23da80..1751b0de2f1 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-abort.diff @@ -81,11 +81,11 @@ StorageDead(_6); _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; StorageDead(_5); - _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc7, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; + _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; StorageDead(_4); - _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc10, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); + _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); StorageDead(_3); - _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc11, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }; + _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }; StorageDead(_2); _0 = const (); drop(_1) -> [return: bb1, unwind unreachable]; @@ -97,15 +97,15 @@ } } - alloc11 (size: 8, align: 4) { + ALLOC2 (size: 8, align: 4) { 01 00 00 00 00 00 00 00 │ ........ } - alloc10 (size: 8, align: 4) { + ALLOC1 (size: 8, align: 4) { 01 00 00 00 00 00 00 00 │ ........ } - alloc7 (size: 8, align: 4) { + ALLOC0 (size: 8, align: 4) { 01 00 00 00 00 00 00 00 │ ........ } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff index bd4150ebb45..858a9d33ddf 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.32bit.panic-unwind.diff @@ -81,11 +81,11 @@ StorageDead(_6); _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; StorageDead(_5); - _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc7, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; + _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; StorageDead(_4); - _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc10, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); + _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); StorageDead(_3); - _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc11, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }; + _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }; StorageDead(_2); _0 = const (); drop(_1) -> [return: bb1, unwind: bb2]; @@ -101,15 +101,15 @@ } } - alloc11 (size: 8, align: 4) { + ALLOC2 (size: 8, align: 4) { 01 00 00 00 00 00 00 00 │ ........ } - alloc10 (size: 8, align: 4) { + ALLOC1 (size: 8, align: 4) { 01 00 00 00 00 00 00 00 │ ........ } - alloc7 (size: 8, align: 4) { + ALLOC0 (size: 8, align: 4) { 01 00 00 00 00 00 00 00 │ ........ } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff index 312fc7b7a82..51707042075 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-abort.diff @@ -81,11 +81,11 @@ StorageDead(_6); _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; StorageDead(_5); - _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc7, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; + _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; StorageDead(_4); - _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc10, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); + _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); StorageDead(_3); - _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc11, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }; + _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }; StorageDead(_2); _0 = const (); drop(_1) -> [return: bb1, unwind unreachable]; @@ -97,15 +97,15 @@ } } - alloc11 (size: 16, align: 8) { + ALLOC2 (size: 16, align: 8) { 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ } - alloc10 (size: 16, align: 8) { + ALLOC1 (size: 16, align: 8) { 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ } - alloc7 (size: 16, align: 8) { + ALLOC0 (size: 16, align: 8) { 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ } diff --git a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff index 3227d8b8435..9141a6c67be 100644 --- a/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/default_boxed_slice.main.DataflowConstProp.64bit.panic-unwind.diff @@ -81,11 +81,11 @@ StorageDead(_6); _4 = const Unique::<[bool; 0]> {{ pointer: NonNull::<[bool; 0]> {{ pointer: {0x1 as *const [bool; 0]} }}, _marker: PhantomData::<[bool; 0]> }}; StorageDead(_5); - _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc7, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; + _3 = const Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}; StorageDead(_4); - _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc10, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); + _2 = const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global); StorageDead(_3); - _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: alloc11, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }; + _1 = A { foo: const Box::<[bool]>(Unique::<[bool]> {{ pointer: NonNull::<[bool]> {{ pointer: Indirect { alloc_id: ALLOC2, offset: Size(0 bytes) }: *const [bool] }}, _marker: PhantomData::<[bool]> }}, std::alloc::Global) }; StorageDead(_2); _0 = const (); drop(_1) -> [return: bb1, unwind: bb2]; @@ -101,15 +101,15 @@ } } - alloc11 (size: 16, align: 8) { + ALLOC2 (size: 16, align: 8) { 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ } - alloc10 (size: 16, align: 8) { + ALLOC1 (size: 16, align: 8) { 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ } - alloc7 (size: 16, align: 8) { + ALLOC0 (size: 16, align: 8) { 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ } diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff index ae8b44c953e..1348b279330 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.32bit.diff @@ -43,7 +43,7 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = const {alloc1: &E}; + _2 = const {ALLOC1: &E}; _1 = (*_2); StorageDead(_2); StorageLive(_3); @@ -78,7 +78,7 @@ bb4: { StorageLive(_7); StorageLive(_8); - _8 = const {alloc2: &&E}; + _8 = const {ALLOC2: &&E}; _7 = (*_8); StorageDead(_8); StorageLive(_9); @@ -112,15 +112,15 @@ } } - alloc2 (static: RC, size: 4, align: 4) { - ╾─alloc14─╼ │ ╾──╼ + ALLOC2 (static: RC, size: 4, align: 4) { + ╾ALLOC0╼ │ ╾──╼ } - alloc14 (size: 8, align: 4) { + ALLOC0 (size: 8, align: 4) { 01 00 00 00 04 00 00 00 │ ........ } - alloc1 (static: statics::C, size: 8, align: 4) { + ALLOC1 (static: statics::C, size: 8, align: 4) { 00 00 00 00 00 00 00 00 │ ........ } diff --git a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff index 63799b3bac3..66929e886d3 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/enum.statics.DataflowConstProp.64bit.diff @@ -43,7 +43,7 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = const {alloc1: &E}; + _2 = const {ALLOC1: &E}; _1 = (*_2); StorageDead(_2); StorageLive(_3); @@ -78,7 +78,7 @@ bb4: { StorageLive(_7); StorageLive(_8); - _8 = const {alloc2: &&E}; + _8 = const {ALLOC2: &&E}; _7 = (*_8); StorageDead(_8); StorageLive(_9); @@ -112,15 +112,15 @@ } } - alloc2 (static: RC, size: 8, align: 8) { - ╾───────alloc14───────╼ │ ╾──────╼ + ALLOC2 (static: RC, size: 8, align: 8) { + ╾ALLOC0╼ │ ╾──────╼ } - alloc14 (size: 8, align: 4) { + ALLOC0 (size: 8, align: 4) { 01 00 00 00 04 00 00 00 │ ........ } - alloc1 (static: statics::C, size: 8, align: 4) { + ALLOC1 (static: statics::C, size: 8, align: 4) { 00 00 00 00 00 00 00 00 │ ........ } diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff index 2de6ba307d5..e80f31ca934 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff +++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.32bit.diff @@ -84,7 +84,7 @@ + _10 = const S(13_i32); StorageDead(_11); StorageLive(_16); - _16 = const {alloc1: &&BigStruct}; + _16 = const {ALLOC1: &&BigStruct}; _17 = deref_copy (*_16); StorageLive(_12); _18 = deref_copy (*_16); @@ -119,11 +119,11 @@ } } - alloc1 (static: STAT, size: 4, align: 4) { - ╾─alloc15─╼ │ ╾──╼ + ALLOC1 (static: STAT, size: 4, align: 4) { + ╾ALLOC0╼ │ ╾──╼ } - alloc15 (size: 16, align: 4) { + ALLOC0 (size: 16, align: 4) { 01 00 00 00 00 00 e0 40 0d 00 00 00 05 __ __ __ │ .......@.....░░░ } diff --git a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff index 71a28f2165b..de9cf197199 100644 --- a/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff +++ b/tests/mir-opt/dataflow-const-prop/struct.main.DataflowConstProp.64bit.diff @@ -84,7 +84,7 @@ + _10 = const S(13_i32); StorageDead(_11); StorageLive(_16); - _16 = const {alloc1: &&BigStruct}; + _16 = const {ALLOC1: &&BigStruct}; _17 = deref_copy (*_16); StorageLive(_12); _18 = deref_copy (*_16); @@ -119,11 +119,11 @@ } } - alloc1 (static: STAT, size: 8, align: 8) { - ╾───────alloc15───────╼ │ ╾──────╼ + ALLOC1 (static: STAT, size: 8, align: 8) { + ╾ALLOC0╼ │ ╾──────╼ } - alloc15 (size: 16, align: 4) { + ALLOC0 (size: 16, align: 4) { 01 00 00 00 00 00 e0 40 0d 00 00 00 05 __ __ __ │ .......@.....░░░ } diff --git a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff index d5e58265dcc..142e08f4d6c 100644 --- a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff +++ b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff @@ -4,29 +4,20 @@ fn main() -> () { let mut _0: (); let _1: main::Un; - let mut _2: u32; - let mut _3: u32; scope 1 { debug un => _1; scope 2 { } - scope 3 (inlined std::mem::drop::<u32>) { - debug _x => _3; + scope 4 (inlined std::mem::drop::<u32>) { + debug _x => const 1_u32; } } + scope 3 (inlined val) { + } bb0: { StorageLive(_1); - StorageLive(_2); - _2 = val() -> [return: bb1, unwind unreachable]; - } - - bb1: { - _1 = Un { us: move _2 }; - StorageDead(_2); - StorageLive(_3); - _3 = (_1.0: u32); - StorageDead(_3); + _1 = Un { us: const 1_u32 }; StorageDead(_1); return; } diff --git a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff index 5eaaeba135b..142e08f4d6c 100644 --- a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff +++ b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff @@ -4,29 +4,20 @@ fn main() -> () { let mut _0: (); let _1: main::Un; - let mut _2: u32; - let mut _3: u32; scope 1 { debug un => _1; scope 2 { } - scope 3 (inlined std::mem::drop::<u32>) { - debug _x => _3; + scope 4 (inlined std::mem::drop::<u32>) { + debug _x => const 1_u32; } } + scope 3 (inlined val) { + } bb0: { StorageLive(_1); - StorageLive(_2); - _2 = val() -> [return: bb1, unwind continue]; - } - - bb1: { - _1 = Un { us: move _2 }; - StorageDead(_2); - StorageLive(_3); - _3 = (_1.0: u32); - StorageDead(_3); + _1 = Un { us: const 1_u32 }; StorageDead(_1); return; } diff --git a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff index ec5f5c1f1fc..775a60f1c96 100644 --- a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff +++ b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff @@ -66,7 +66,7 @@ } + } + -+ alloc15 (size: 8, align: 4) { ++ ALLOC0 (size: 8, align: 4) { + 02 00 00 00 05 20 00 00 │ ..... .. } diff --git a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff index 9bf8637ec76..c4b57579943 100644 --- a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff +++ b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff @@ -66,7 +66,7 @@ } + } + -+ alloc15 (size: 16, align: 8) { ++ ALLOC0 (size: 16, align: 8) { + 02 00 00 00 00 00 00 00 05 20 00 00 00 00 00 00 │ ......... ...... } diff --git a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff index 7dc6d21a907..f7d0d1fb56c 100644 --- a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff +++ b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff @@ -66,7 +66,7 @@ } + } + -+ alloc14 (size: 8, align: 4) { ++ ALLOC0 (size: 8, align: 4) { + 05 20 00 00 01 00 00 00 │ . ...... } diff --git a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff index 0b000876a86..15f1bd0df51 100644 --- a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff +++ b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff @@ -66,7 +66,7 @@ } + } + -+ alloc14 (size: 16, align: 8) { ++ ALLOC0 (size: 16, align: 8) { + 05 20 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ . .............. } diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.panic-abort.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.panic-abort.diff index a538756ba2d..298a6084899 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.panic-abort.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.panic-abort.diff @@ -7,104 +7,104 @@ debug upper => _3; let mut _0: std::result::Result<(), std::fmt::Error>; let _4: bool; - let mut _5: &std::fmt::Formatter<'_>; - let mut _7: std::option::Option<usize>; - let mut _8: &std::fmt::Formatter<'_>; - let mut _9: isize; - let mut _11: &mut std::fmt::Formatter<'_>; - let mut _12: &T; - let mut _13: core::num::flt2dec::Sign; - let mut _14: u32; - let mut _15: u32; - let mut _16: usize; - let mut _17: bool; - let mut _18: &mut std::fmt::Formatter<'_>; - let mut _19: &T; - let mut _20: core::num::flt2dec::Sign; - let mut _21: bool; + let mut _6: std::option::Option<usize>; + let mut _7: isize; + let mut _9: &mut std::fmt::Formatter<'_>; + let mut _10: &T; + let mut _11: core::num::flt2dec::Sign; + let mut _12: u32; + let mut _13: u32; + let mut _14: usize; + let mut _15: bool; + let mut _16: &mut std::fmt::Formatter<'_>; + let mut _17: &T; + let mut _18: core::num::flt2dec::Sign; + let mut _19: bool; scope 1 { debug force_sign => _4; - let _6: core::num::flt2dec::Sign; + let _5: core::num::flt2dec::Sign; scope 2 { - debug sign => _6; + debug sign => _5; scope 3 { - debug precision => _10; - let _10: usize; + debug precision => _8; + let _8: usize; + scope 5 (inlined Formatter::<'_>::precision) { + debug self => _1; + } } } } + scope 4 (inlined Formatter::<'_>::sign_plus) { + debug self => _1; + let mut _20: u32; + let mut _21: u32; + } bb0: { StorageLive(_4); + StorageLive(_20); + StorageLive(_21); + _21 = ((*_1).0: u32); + _20 = BitAnd(move _21, const 1_u32); + StorageDead(_21); + _4 = Ne(move _20, const 0_u32); + StorageDead(_20); StorageLive(_5); - _5 = &(*_1); - _4 = Formatter::<'_>::sign_plus(move _5) -> [return: bb1, unwind unreachable]; + switchInt(_4) -> [0: bb2, otherwise: bb1]; } bb1: { - StorageDead(_5); - StorageLive(_6); - switchInt(_4) -> [0: bb3, otherwise: bb2]; +- _5 = MinusPlus; ++ _5 = const MinusPlus; + goto -> bb3; } bb2: { -- _6 = MinusPlus; -+ _6 = const MinusPlus; - goto -> bb4; +- _5 = Minus; ++ _5 = const Minus; + goto -> bb3; } bb3: { -- _6 = Minus; -+ _6 = const Minus; - goto -> bb4; + StorageLive(_6); + _6 = ((*_1).4: std::option::Option<usize>); + _7 = discriminant(_6); + switchInt(move _7) -> [1: bb4, otherwise: bb6]; } bb4: { - StorageLive(_7); - StorageLive(_8); - _8 = &(*_1); - _7 = Formatter::<'_>::precision(move _8) -> [return: bb5, unwind unreachable]; + _8 = ((_6 as Some).0: usize); + StorageLive(_11); + _11 = _5; + StorageLive(_12); + StorageLive(_13); + _13 = _8 as u32 (IntToInt); + _12 = Add(move _13, const 1_u32); + StorageDead(_13); + _0 = float_to_exponential_common_exact::<T>(_1, _2, move _11, move _12, _3) -> [return: bb5, unwind unreachable]; } bb5: { - StorageDead(_8); - _9 = discriminant(_7); - switchInt(move _9) -> [1: bb6, otherwise: bb8]; + StorageDead(_12); + StorageDead(_11); + goto -> bb8; } bb6: { - _10 = ((_7 as Some).0: usize); - StorageLive(_13); - _13 = _6; - StorageLive(_14); - StorageLive(_15); - _15 = _10 as u32 (IntToInt); - _14 = Add(move _15, const 1_u32); - StorageDead(_15); - _0 = float_to_exponential_common_exact::<T>(_1, _2, move _13, move _14, _3) -> [return: bb7, unwind unreachable]; + StorageLive(_18); + _18 = _5; + _0 = float_to_exponential_common_shortest::<T>(_1, _2, move _18, _3) -> [return: bb7, unwind unreachable]; } bb7: { - StorageDead(_14); - StorageDead(_13); - goto -> bb10; + StorageDead(_18); + goto -> bb8; } bb8: { - StorageLive(_20); - _20 = _6; - _0 = float_to_exponential_common_shortest::<T>(_1, _2, move _20, _3) -> [return: bb9, unwind unreachable]; - } - - bb9: { - StorageDead(_20); - goto -> bb10; - } - - bb10: { - StorageDead(_6); + StorageDead(_5); StorageDead(_4); - StorageDead(_7); + StorageDead(_6); return; } } diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.panic-unwind.diff index 8a3dcfab44b..037f4f7cfac 100644 --- a/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.panic-unwind.diff +++ b/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.panic-unwind.diff @@ -7,104 +7,104 @@ debug upper => _3; let mut _0: std::result::Result<(), std::fmt::Error>; let _4: bool; - let mut _5: &std::fmt::Formatter<'_>; - let mut _7: std::option::Option<usize>; - let mut _8: &std::fmt::Formatter<'_>; - let mut _9: isize; - let mut _11: &mut std::fmt::Formatter<'_>; - let mut _12: &T; - let mut _13: core::num::flt2dec::Sign; - let mut _14: u32; - let mut _15: u32; - let mut _16: usize; - let mut _17: bool; - let mut _18: &mut std::fmt::Formatter<'_>; - let mut _19: &T; - let mut _20: core::num::flt2dec::Sign; - let mut _21: bool; + let mut _6: std::option::Option<usize>; + let mut _7: isize; + let mut _9: &mut std::fmt::Formatter<'_>; + let mut _10: &T; + let mut _11: core::num::flt2dec::Sign; + let mut _12: u32; + let mut _13: u32; + let mut _14: usize; + let mut _15: bool; + let mut _16: &mut std::fmt::Formatter<'_>; + let mut _17: &T; + let mut _18: core::num::flt2dec::Sign; + let mut _19: bool; scope 1 { debug force_sign => _4; - let _6: core::num::flt2dec::Sign; + let _5: core::num::flt2dec::Sign; scope 2 { - debug sign => _6; + debug sign => _5; scope 3 { - debug precision => _10; - let _10: usize; + debug precision => _8; + let _8: usize; + scope 5 (inlined Formatter::<'_>::precision) { + debug self => _1; + } } } } + scope 4 (inlined Formatter::<'_>::sign_plus) { + debug self => _1; + let mut _20: u32; + let mut _21: u32; + } bb0: { StorageLive(_4); + StorageLive(_20); + StorageLive(_21); + _21 = ((*_1).0: u32); + _20 = BitAnd(move _21, const 1_u32); + StorageDead(_21); + _4 = Ne(move _20, const 0_u32); + StorageDead(_20); StorageLive(_5); - _5 = &(*_1); - _4 = Formatter::<'_>::sign_plus(move _5) -> [return: bb1, unwind continue]; + switchInt(_4) -> [0: bb2, otherwise: bb1]; } bb1: { - StorageDead(_5); - StorageLive(_6); - switchInt(_4) -> [0: bb3, otherwise: bb2]; +- _5 = MinusPlus; ++ _5 = const MinusPlus; + goto -> bb3; } bb2: { -- _6 = MinusPlus; -+ _6 = const MinusPlus; - goto -> bb4; +- _5 = Minus; ++ _5 = const Minus; + goto -> bb3; } bb3: { -- _6 = Minus; -+ _6 = const Minus; - goto -> bb4; + StorageLive(_6); + _6 = ((*_1).4: std::option::Option<usize>); + _7 = discriminant(_6); + switchInt(move _7) -> [1: bb4, otherwise: bb6]; } bb4: { - StorageLive(_7); - StorageLive(_8); - _8 = &(*_1); - _7 = Formatter::<'_>::precision(move _8) -> [return: bb5, unwind continue]; + _8 = ((_6 as Some).0: usize); + StorageLive(_11); + _11 = _5; + StorageLive(_12); + StorageLive(_13); + _13 = _8 as u32 (IntToInt); + _12 = Add(move _13, const 1_u32); + StorageDead(_13); + _0 = float_to_exponential_common_exact::<T>(_1, _2, move _11, move _12, _3) -> [return: bb5, unwind continue]; } bb5: { - StorageDead(_8); - _9 = discriminant(_7); - switchInt(move _9) -> [1: bb6, otherwise: bb8]; + StorageDead(_12); + StorageDead(_11); + goto -> bb8; } bb6: { - _10 = ((_7 as Some).0: usize); - StorageLive(_13); - _13 = _6; - StorageLive(_14); - StorageLive(_15); - _15 = _10 as u32 (IntToInt); - _14 = Add(move _15, const 1_u32); - StorageDead(_15); - _0 = float_to_exponential_common_exact::<T>(_1, _2, move _13, move _14, _3) -> [return: bb7, unwind continue]; + StorageLive(_18); + _18 = _5; + _0 = float_to_exponential_common_shortest::<T>(_1, _2, move _18, _3) -> [return: bb7, unwind continue]; } bb7: { - StorageDead(_14); - StorageDead(_13); - goto -> bb10; + StorageDead(_18); + goto -> bb8; } bb8: { - StorageLive(_20); - _20 = _6; - _0 = float_to_exponential_common_shortest::<T>(_1, _2, move _20, _3) -> [return: bb9, unwind continue]; - } - - bb9: { - StorageDead(_20); - goto -> bb10; - } - - bb10: { - StorageDead(_6); + StorageDead(_5); StorageDead(_4); - StorageDead(_7); + StorageDead(_6); return; } } diff --git a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff index 7d5553b2f37..da45ebcb4d8 100644 --- a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-abort.diff @@ -8,11 +8,11 @@ + scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) { + debug f => _2; + let mut _3: &fn() -> ! {sleep}; -+ let mut _4: !; ++ let _4: !; + let mut _5: &fn() -> ! {sleep}; -+ let mut _6: !; + scope 2 { + debug a => _4; ++ let _6: !; + scope 3 { + debug b => _6; + } diff --git a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff index 9f8c5806c90..d65c65e5fd0 100644 --- a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff @@ -10,10 +10,10 @@ + let mut _3: &fn() -> ! {sleep}; + let _4: !; + let mut _5: &fn() -> ! {sleep}; -+ let mut _6: !; + let mut _7: !; + scope 2 { + debug a => _4; ++ let _6: !; + scope 3 { + debug b => _6; + } diff --git a/tests/mir-opt/inline/issue_106141.rs b/tests/mir-opt/inline/issue_106141.rs index eed1d89172c..e442f8a7522 100644 --- a/tests/mir-opt/inline/issue_106141.rs +++ b/tests/mir-opt/inline/issue_106141.rs @@ -3,6 +3,7 @@ pub fn outer() -> usize { inner() } +#[inline(never)] fn index() -> usize { loop {} } diff --git a/tests/mir-opt/inline/issue_78442.bar.Inline.panic-abort.diff b/tests/mir-opt/inline/issue_78442.bar.Inline.panic-abort.diff index bee01a5f97b..b9f268df351 100644 --- a/tests/mir-opt/inline/issue_78442.bar.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/issue_78442.bar.Inline.panic-abort.diff @@ -8,31 +8,37 @@ let mut _3: &fn() {foo}; let _4: fn() {foo}; let mut _5: (); ++ scope 1 (inlined hide_foo) { ++ } bb0: { StorageLive(_2); StorageLive(_3); StorageLive(_4); - _4 = hide_foo() -> [return: bb1, unwind unreachable]; - } - - bb1: { +- _4 = hide_foo() -> [return: bb1, unwind unreachable]; +- } +- +- bb1: { _3 = &_4; StorageLive(_5); _5 = (); - _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind unreachable]; +- _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind unreachable]; ++ _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb1, unwind unreachable]; } - bb2: { +- bb2: { ++ bb1: { StorageDead(_5); StorageDead(_3); StorageDead(_4); StorageDead(_2); _0 = const (); - drop(_1) -> [return: bb3, unwind unreachable]; +- drop(_1) -> [return: bb3, unwind unreachable]; ++ drop(_1) -> [return: bb2, unwind unreachable]; } - bb3: { +- bb3: { ++ bb2: { return; } } diff --git a/tests/mir-opt/inline/issue_78442.bar.Inline.panic-unwind.diff b/tests/mir-opt/inline/issue_78442.bar.Inline.panic-unwind.diff index 5a946712ea4..8495164df9c 100644 --- a/tests/mir-opt/inline/issue_78442.bar.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/issue_78442.bar.Inline.panic-unwind.diff @@ -8,39 +8,48 @@ let mut _3: &fn() {foo}; let _4: fn() {foo}; let mut _5: (); ++ scope 1 (inlined hide_foo) { ++ } bb0: { StorageLive(_2); StorageLive(_3); StorageLive(_4); - _4 = hide_foo() -> [return: bb1, unwind: bb4]; - } - - bb1: { +- _4 = hide_foo() -> [return: bb1, unwind: bb4]; +- } +- +- bb1: { _3 = &_4; StorageLive(_5); _5 = (); - _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; +- _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; ++ _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb1, unwind: bb3]; } - bb2: { +- bb2: { ++ bb1: { StorageDead(_5); StorageDead(_3); StorageDead(_4); StorageDead(_2); _0 = const (); - drop(_1) -> [return: bb3, unwind: bb5]; +- drop(_1) -> [return: bb3, unwind: bb5]; ++ drop(_1) -> [return: bb2, unwind: bb4]; } - bb3: { +- bb3: { ++ bb2: { return; } - bb4 (cleanup): { - drop(_1) -> [return: bb5, unwind terminate(cleanup)]; +- bb4 (cleanup): { +- drop(_1) -> [return: bb5, unwind terminate(cleanup)]; ++ bb3 (cleanup): { ++ drop(_1) -> [return: bb4, unwind terminate(cleanup)]; } - bb5 (cleanup): { +- bb5 (cleanup): { ++ bb4 (cleanup): { resume; } } diff --git a/tests/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff b/tests/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff index 28a7ffda371..13ff1e284d9 100644 --- a/tests/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff +++ b/tests/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff @@ -4,8 +4,10 @@ fn bar() -> bool { let mut _0: bool; ++ coverage Counter(0) => /the/src/instrument_coverage.rs:20:1 - 22:2; ++ bb0: { -+ Coverage::Counter(0) for [/the/src/instrument_coverage.rs:20:1 - 22:2]; ++ Coverage::CounterIncrement(0); _0 = const true; return; } diff --git a/tests/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/tests/mir-opt/instrument_coverage.main.InstrumentCoverage.diff index 9a8caa26307..f5c59c84693 100644 --- a/tests/mir-opt/instrument_coverage.main.InstrumentCoverage.diff +++ b/tests/mir-opt/instrument_coverage.main.InstrumentCoverage.diff @@ -7,13 +7,21 @@ let mut _2: bool; let mut _3: !; ++ coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Add, rhs: Counter(1) }; ++ coverage ExpressionId(1) => Expression { lhs: Expression(0), op: Subtract, rhs: Counter(1) }; ++ coverage Counter(0) => /the/src/instrument_coverage.rs:11:1 - 11:11; ++ coverage Expression(0) => /the/src/instrument_coverage.rs:12:5 - 13:17; ++ coverage Expression(1) => /the/src/instrument_coverage.rs:14:13 - 14:18; ++ coverage Expression(1) => /the/src/instrument_coverage.rs:17:1 - 17:2; ++ coverage Counter(1) => /the/src/instrument_coverage.rs:15:10 - 15:11; ++ bb0: { -+ Coverage::Counter(0) for [/the/src/instrument_coverage.rs:11:1 - 11:11]; ++ Coverage::CounterIncrement(0); goto -> bb1; } bb1: { -+ Coverage::Expression(0) = Counter(0) + Counter(1) for [/the/src/instrument_coverage.rs:12:5 - 13:17]; ++ Coverage::ExpressionUsed(0); falseUnwind -> [real: bb2, unwind: bb6]; } @@ -27,14 +35,14 @@ } bb4: { -+ Coverage::Expression(1) = Expression(0) - Counter(1) for [/the/src/instrument_coverage.rs:14:13 - 14:18, /the/src/instrument_coverage.rs:17:1 - 17:2]; ++ Coverage::ExpressionUsed(1); _0 = const (); StorageDead(_2); return; } bb5: { -+ Coverage::Counter(1) for [/the/src/instrument_coverage.rs:15:10 - 15:11]; ++ Coverage::CounterIncrement(1); _1 = const (); StorageDead(_2); goto -> bb1; diff --git a/tests/mir-opt/issue_99325.main.built.after.32bit.mir b/tests/mir-opt/issue_99325.main.built.after.32bit.mir index 132b713356e..f8ac75513ba 100644 --- a/tests/mir-opt/issue_99325.main.built.after.32bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.32bit.mir @@ -271,6 +271,6 @@ fn main() -> () { } } -alloc4 (size: 4, align: 1) { +ALLOC0 (size: 4, align: 1) { 41 41 41 41 │ AAAA } diff --git a/tests/mir-opt/issue_99325.main.built.after.64bit.mir b/tests/mir-opt/issue_99325.main.built.after.64bit.mir index 132b713356e..f8ac75513ba 100644 --- a/tests/mir-opt/issue_99325.main.built.after.64bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.64bit.mir @@ -271,6 +271,6 @@ fn main() -> () { } } -alloc4 (size: 4, align: 1) { +ALLOC0 (size: 4, align: 1) { 41 41 41 41 │ AAAA } diff --git a/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir index 2fbe5088268..8dbb688999a 100644 --- a/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir @@ -6,21 +6,20 @@ fn filter_mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> Option<U>) -> () let mut _0: (); let mut _3: std::iter::FilterMap<impl Iterator<Item = T>, impl Fn(T) -> Option<U>>; let mut _4: std::iter::FilterMap<impl Iterator<Item = T>, impl Fn(T) -> Option<U>>; - let mut _5: std::iter::FilterMap<impl Iterator<Item = T>, impl Fn(T) -> Option<U>>; - let mut _6: &mut std::iter::FilterMap<impl Iterator<Item = T>, impl Fn(T) -> Option<U>>; - let mut _9: std::option::Option<U>; - let mut _10: isize; - let _12: (); + let mut _5: &mut std::iter::FilterMap<impl Iterator<Item = T>, impl Fn(T) -> Option<U>>; + let mut _8: std::option::Option<U>; + let mut _9: isize; + let _11: (); scope 1 { - debug iter => _5; - let _11: U; + debug iter => _4; + let _10: U; scope 2 { - debug x => _11; + debug x => _10; } scope 4 (inlined <FilterMap<impl Iterator<Item = T>, impl Fn(T) -> Option<U>> as Iterator>::next) { - debug self => _6; - let mut _7: &mut impl Iterator<Item = T>; - let mut _8: &mut impl Fn(T) -> Option<U>; + debug self => _5; + let mut _6: &mut impl Iterator<Item = T>; + let mut _7: &mut impl Fn(T) -> Option<U>; } } scope 3 (inlined <FilterMap<impl Iterator<Item = T>, impl Fn(T) -> Option<U>> as IntoIterator>::into_iter) { @@ -28,54 +27,49 @@ fn filter_mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> Option<U>) -> () } bb0: { - StorageLive(_4); - StorageLive(_3); _3 = <impl Iterator<Item = T> as Iterator>::filter_map::<U, impl Fn(T) -> Option<U>>(move _1, move _2) -> [return: bb1, unwind continue]; } bb1: { + StorageLive(_4); _4 = move _3; - StorageDead(_3); - StorageLive(_5); - _5 = move _4; goto -> bb2; } bb2: { - StorageLive(_9); - _6 = &mut _5; - StorageLive(_7); - _7 = &mut (_5.0: impl Iterator<Item = T>); StorageLive(_8); - _8 = &mut (_5.1: impl Fn(T) -> Option<U>); - _9 = <impl Iterator<Item = T> as Iterator>::find_map::<U, &mut impl Fn(T) -> Option<U>>(move _7, move _8) -> [return: bb3, unwind: bb9]; + _5 = &mut _4; + StorageLive(_6); + _6 = &mut (_4.0: impl Iterator<Item = T>); + StorageLive(_7); + _7 = &mut (_4.1: impl Fn(T) -> Option<U>); + _8 = <impl Iterator<Item = T> as Iterator>::find_map::<U, &mut impl Fn(T) -> Option<U>>(move _6, move _7) -> [return: bb3, unwind: bb9]; } bb3: { - StorageDead(_8); StorageDead(_7); - _10 = discriminant(_9); - switchInt(move _10) -> [0: bb4, 1: bb6, otherwise: bb8]; + StorageDead(_6); + _9 = discriminant(_8); + switchInt(move _9) -> [0: bb4, 1: bb6, otherwise: bb8]; } bb4: { - StorageDead(_9); - drop(_5) -> [return: bb5, unwind continue]; + StorageDead(_8); + drop(_4) -> [return: bb5, unwind continue]; } bb5: { - StorageDead(_5); StorageDead(_4); return; } bb6: { - _11 = move ((_9 as Some).0: U); - _12 = opaque::<U>(move _11) -> [return: bb7, unwind: bb9]; + _10 = move ((_8 as Some).0: U); + _11 = opaque::<U>(move _10) -> [return: bb7, unwind: bb9]; } bb7: { - StorageDead(_9); + StorageDead(_8); goto -> bb2; } @@ -84,7 +78,7 @@ fn filter_mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> Option<U>) -> () } bb9 (cleanup): { - drop(_5) -> [return: bb10, unwind terminate(cleanup)]; + drop(_4) -> [return: bb10, unwind terminate(cleanup)]; } bb10 (cleanup): { diff --git a/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir index c30df7425d2..30bdc131090 100644 --- a/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir @@ -6,16 +6,15 @@ fn mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> U) -> () { let mut _0: (); let mut _3: std::iter::Map<impl Iterator<Item = T>, impl Fn(T) -> U>; let mut _4: std::iter::Map<impl Iterator<Item = T>, impl Fn(T) -> U>; - let mut _5: std::iter::Map<impl Iterator<Item = T>, impl Fn(T) -> U>; - let mut _6: &mut std::iter::Map<impl Iterator<Item = T>, impl Fn(T) -> U>; - let mut _7: std::option::Option<U>; - let mut _8: isize; - let _10: (); + let mut _5: &mut std::iter::Map<impl Iterator<Item = T>, impl Fn(T) -> U>; + let mut _6: std::option::Option<U>; + let mut _7: isize; + let _9: (); scope 1 { - debug iter => _5; - let _9: U; + debug iter => _4; + let _8: U; scope 2 { - debug x => _9; + debug x => _8; } } scope 3 (inlined <Map<impl Iterator<Item = T>, impl Fn(T) -> U> as IntoIterator>::into_iter) { @@ -23,50 +22,45 @@ fn mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> U) -> () { } bb0: { - StorageLive(_4); - StorageLive(_3); _3 = <impl Iterator<Item = T> as Iterator>::map::<U, impl Fn(T) -> U>(move _1, move _2) -> [return: bb1, unwind continue]; } bb1: { + StorageLive(_4); _4 = move _3; - StorageDead(_3); - StorageLive(_5); - _5 = move _4; goto -> bb2; } bb2: { - StorageLive(_7); StorageLive(_6); - _6 = &mut _5; - _7 = <Map<impl Iterator<Item = T>, impl Fn(T) -> U> as Iterator>::next(move _6) -> [return: bb3, unwind: bb9]; + StorageLive(_5); + _5 = &mut _4; + _6 = <Map<impl Iterator<Item = T>, impl Fn(T) -> U> as Iterator>::next(move _5) -> [return: bb3, unwind: bb9]; } bb3: { - StorageDead(_6); - _8 = discriminant(_7); - switchInt(move _8) -> [0: bb4, 1: bb6, otherwise: bb8]; + StorageDead(_5); + _7 = discriminant(_6); + switchInt(move _7) -> [0: bb4, 1: bb6, otherwise: bb8]; } bb4: { - StorageDead(_7); - drop(_5) -> [return: bb5, unwind continue]; + StorageDead(_6); + drop(_4) -> [return: bb5, unwind continue]; } bb5: { - StorageDead(_5); StorageDead(_4); return; } bb6: { - _9 = move ((_7 as Some).0: U); - _10 = opaque::<U>(move _9) -> [return: bb7, unwind: bb9]; + _8 = move ((_6 as Some).0: U); + _9 = opaque::<U>(move _8) -> [return: bb7, unwind: bb9]; } bb7: { - StorageDead(_7); + StorageDead(_6); goto -> bb2; } @@ -75,7 +69,7 @@ fn mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> U) -> () { } bb9 (cleanup): { - drop(_5) -> [return: bb10, unwind terminate(cleanup)]; + drop(_4) -> [return: bb10, unwind terminate(cleanup)]; } bb10 (cleanup): { diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.32bit.panic-abort.diff index 681e9666e0f..bddd961c933 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.32bit.panic-abort.diff @@ -57,7 +57,7 @@ } + } + -+ alloc5 (size: 8, align: 4) { ++ ALLOC0 (size: 8, align: 4) { + 04 00 00 00 00 __ __ __ │ .....░░░ } diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.32bit.panic-unwind.diff index db16b8d82d2..297ebd79fad 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.32bit.panic-unwind.diff @@ -57,7 +57,7 @@ } + } + -+ alloc5 (size: 8, align: 4) { ++ ALLOC0 (size: 8, align: 4) { + 04 00 00 00 00 __ __ __ │ .....░░░ } diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.64bit.panic-abort.diff index 681e9666e0f..bddd961c933 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.64bit.panic-abort.diff @@ -57,7 +57,7 @@ } + } + -+ alloc5 (size: 8, align: 4) { ++ ALLOC0 (size: 8, align: 4) { + 04 00 00 00 00 __ __ __ │ .....░░░ } diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.64bit.panic-unwind.diff index db16b8d82d2..297ebd79fad 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.64bit.panic-unwind.diff @@ -57,7 +57,7 @@ } + } + -+ alloc5 (size: 8, align: 4) { ++ ALLOC0 (size: 8, align: 4) { + 04 00 00 00 00 __ __ __ │ .....░░░ } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-abort.mir index df6d2263dc3..d97c96ac8a0 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-abort.mir @@ -7,17 +7,13 @@ fn slice_index_range(_1: &[u32], _2: std::ops::Range<usize>) -> &[u32] { scope 1 (inlined #[track_caller] core::slice::index::<impl Index<std::ops::Range<usize>> for [u32]>::index) { debug self => _1; debug index => _2; - let _3: &[u32]; } bb0: { - StorageLive(_3); - _3 = <std::ops::Range<usize> as SliceIndex<[u32]>>::index(move _2, move _1) -> [return: bb1, unwind unreachable]; + _0 = <std::ops::Range<usize> as SliceIndex<[u32]>>::index(move _2, move _1) -> [return: bb1, unwind unreachable]; } bb1: { - _0 = _3; - StorageDead(_3); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-unwind.mir index cc1795c3f97..4a976002fa5 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-unwind.mir @@ -7,17 +7,13 @@ fn slice_index_range(_1: &[u32], _2: std::ops::Range<usize>) -> &[u32] { scope 1 (inlined #[track_caller] core::slice::index::<impl Index<std::ops::Range<usize>> for [u32]>::index) { debug self => _1; debug index => _2; - let _3: &[u32]; } bb0: { - StorageLive(_3); - _3 = <std::ops::Range<usize> as SliceIndex<[u32]>>::index(move _2, move _1) -> [return: bb1, unwind continue]; + _0 = <std::ops::Range<usize> as SliceIndex<[u32]>>::index(move _2, move _1) -> [return: bb1, unwind continue]; } bb1: { - _0 = _3; - StorageDead(_3); return; } } diff --git a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir index 1d3317efd41..7af69e08ca1 100644 --- a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir @@ -4,17 +4,14 @@ fn outer(_1: u8) -> u8 { debug v => _1; // in scope 0 at $DIR/spans.rs:9:14: 9:15 let mut _0: u8; // return place in scope 0 at $DIR/spans.rs:9:24: 9:26 let mut _2: &u8; // in scope 0 at $DIR/spans.rs:10:11: 10:13 + scope 1 (inlined inner) { // at $DIR/spans.rs:10:5: 10:14 + debug x => _2; // in scope 1 at $DIR/spans.rs:13:14: 13:15 + } bb0: { StorageLive(_2); // scope 0 at $DIR/spans.rs:10:11: 10:13 _2 = &_1; // scope 0 at $DIR/spans.rs:10:11: 10:13 - _0 = inner(move _2) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/spans.rs:10:5: 10:14 - // mir::ConstOperand - // + span: $DIR/spans.rs:10:5: 10:10 - // + const_: Const { ty: for<'a> fn(&'a u8) -> u8 {inner}, val: Value(inner) } - } - - bb1: { + _0 = _1; // scope 1 at $DIR/spans.rs:14:5: 14:7 StorageDead(_2); // scope 0 at $DIR/spans.rs:10:13: 10:14 return; // scope 0 at $DIR/spans.rs:11:2: 11:2 } diff --git a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir index aba66861f7d..7af69e08ca1 100644 --- a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir @@ -4,17 +4,14 @@ fn outer(_1: u8) -> u8 { debug v => _1; // in scope 0 at $DIR/spans.rs:9:14: 9:15 let mut _0: u8; // return place in scope 0 at $DIR/spans.rs:9:24: 9:26 let mut _2: &u8; // in scope 0 at $DIR/spans.rs:10:11: 10:13 + scope 1 (inlined inner) { // at $DIR/spans.rs:10:5: 10:14 + debug x => _2; // in scope 1 at $DIR/spans.rs:13:14: 13:15 + } bb0: { StorageLive(_2); // scope 0 at $DIR/spans.rs:10:11: 10:13 _2 = &_1; // scope 0 at $DIR/spans.rs:10:11: 10:13 - _0 = inner(move _2) -> [return: bb1, unwind continue]; // scope 0 at $DIR/spans.rs:10:5: 10:14 - // mir::ConstOperand - // + span: $DIR/spans.rs:10:5: 10:10 - // + const_: Const { ty: for<'a> fn(&'a u8) -> u8 {inner}, val: Value(inner) } - } - - bb1: { + _0 = _1; // scope 1 at $DIR/spans.rs:14:5: 14:7 StorageDead(_2); // scope 0 at $DIR/spans.rs:10:13: 10:14 return; // scope 0 at $DIR/spans.rs:11:2: 11:2 } diff --git a/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff b/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff index 8fe361f2be4..1648f5dd8ca 100644 --- a/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff @@ -92,8 +92,8 @@ StorageDead(_7); - StorageDead(_6); - StorageLive(_10); - StorageLive(_11); - StorageLive(_12); +- StorageLive(_11); +- StorageLive(_12); StorageLive(_13); _26 = const _; _13 = &(*_26); @@ -105,8 +105,9 @@ bb5: { StorageDead(_15); StorageDead(_13); - _11 = &(*_12); - _16 = Len((*_11)); +- _11 = &(*_12); +- _16 = Len((*_11)); ++ _16 = Len((*_12)); _17 = const 3_usize; _18 = Ge(move _16, move _17); switchInt(move _18) -> [0: bb7, otherwise: bb6]; @@ -114,12 +115,15 @@ bb6: { StorageLive(_19); - _19 = &(*_11)[1 of 3]; +- _19 = &(*_11)[1 of 3]; ++ _19 = &(*_12)[1 of 3]; StorageLive(_20); - _20 = &(*_11)[2:-1]; +- _20 = &(*_11)[2:-1]; ++ _20 = &(*_12)[2:-1]; StorageLive(_21); - _21 = &(*_11)[-1 of 3]; +- _21 = &(*_11)[-1 of 3]; - _10 = const (); ++ _21 = &(*_12)[-1 of 3]; StorageDead(_21); StorageDead(_20); StorageDead(_19); @@ -132,8 +136,8 @@ } bb8: { - StorageDead(_12); - StorageDead(_11); +- StorageDead(_12); +- StorageDead(_11); - StorageDead(_10); StorageLive(_22); StorageLive(_23); diff --git a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/while_storage.while_loop.PreCodegen.after.panic-abort.mir index c04fdeb637d..e6ce33ed682 100644 --- a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/while_storage.while_loop.PreCodegen.after.panic-abort.mir @@ -3,44 +3,26 @@ fn while_loop(_1: bool) -> () { debug c => _1; let mut _0: (); - let mut _2: bool; - let mut _3: bool; + scope 1 (inlined get_bool) { + debug c => _1; + } + scope 2 (inlined get_bool) { + debug c => _1; + } bb0: { goto -> bb1; } bb1: { - StorageLive(_2); - _2 = get_bool(_1) -> [return: bb2, unwind unreachable]; + switchInt(_1) -> [0: bb3, otherwise: bb2]; } bb2: { - switchInt(move _2) -> [0: bb7, otherwise: bb3]; + switchInt(_1) -> [0: bb1, otherwise: bb3]; } bb3: { - StorageLive(_3); - _3 = get_bool(_1) -> [return: bb4, unwind unreachable]; - } - - bb4: { - switchInt(move _3) -> [0: bb5, otherwise: bb6]; - } - - bb5: { - StorageDead(_3); - StorageDead(_2); - goto -> bb1; - } - - bb6: { - StorageDead(_3); - goto -> bb7; - } - - bb7: { - StorageDead(_2); return; } } diff --git a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/while_storage.while_loop.PreCodegen.after.panic-unwind.mir index 7dc4f7ab1a8..e6ce33ed682 100644 --- a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/while_storage.while_loop.PreCodegen.after.panic-unwind.mir @@ -3,44 +3,26 @@ fn while_loop(_1: bool) -> () { debug c => _1; let mut _0: (); - let mut _2: bool; - let mut _3: bool; + scope 1 (inlined get_bool) { + debug c => _1; + } + scope 2 (inlined get_bool) { + debug c => _1; + } bb0: { goto -> bb1; } bb1: { - StorageLive(_2); - _2 = get_bool(_1) -> [return: bb2, unwind continue]; + switchInt(_1) -> [0: bb3, otherwise: bb2]; } bb2: { - switchInt(move _2) -> [0: bb7, otherwise: bb3]; + switchInt(_1) -> [0: bb1, otherwise: bb3]; } bb3: { - StorageLive(_3); - _3 = get_bool(_1) -> [return: bb4, unwind continue]; - } - - bb4: { - switchInt(move _3) -> [0: bb5, otherwise: bb6]; - } - - bb5: { - StorageDead(_3); - StorageDead(_2); - goto -> bb1; - } - - bb6: { - StorageDead(_3); - goto -> bb7; - } - - bb7: { - StorageDead(_2); return; } } diff --git a/tests/pretty/format-args-str-escape.pp b/tests/pretty/format-args-str-escape.pp new file mode 100644 index 00000000000..b84bc2303b7 --- /dev/null +++ b/tests/pretty/format-args-str-escape.pp @@ -0,0 +1,21 @@ +#![feature(prelude_import)] +#![no_std] +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; +// pretty-compare-only +// pretty-mode:expanded +// pp-exact:format-args-str-escape.pp + +fn main() { + { ::std::io::_print(format_args!("\u{1b}[1mHello, world!\u{1b}[0m\n")); }; + { ::std::io::_print(format_args!("\u{1b}[1mHello, world!\u{1b}[0m\n")); }; + { + ::std::io::_print(format_args!("Not an escape sequence: \\u{{1B}}[1mbold\\x1B[0m\n")); + }; + { + ::std::io::_print(format_args!("{0}\n", + "\x1B[1mHello, world!\x1B[0m")); + }; +} diff --git a/tests/pretty/format-args-str-escape.rs b/tests/pretty/format-args-str-escape.rs new file mode 100644 index 00000000000..e596fcfd8bc --- /dev/null +++ b/tests/pretty/format-args-str-escape.rs @@ -0,0 +1,10 @@ +// pretty-compare-only +// pretty-mode:expanded +// pp-exact:format-args-str-escape.pp + +fn main() { + println!("\x1B[1mHello, world!\x1B[0m"); + println!("\u{1B}[1mHello, world!\u{1B}[0m"); + println!("Not an escape sequence: \\u{{1B}}[1mbold\\x1B[0m"); + println!("{}", "\x1B[1mHello, world!\x1B[0m"); +} diff --git a/tests/run-make-fulldeps/issue-19371/foo.rs b/tests/run-make-fulldeps/issue-19371/foo.rs index 1c9d33dcc8e..7ee46e1520a 100644 --- a/tests/run-make-fulldeps/issue-19371/foo.rs +++ b/tests/run-make-fulldeps/issue-19371/foo.rs @@ -57,6 +57,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) { locale_resources: &[], lint_caps: Default::default(), parse_sess_created: None, + hash_untracked_state: None, register_lints: None, override_queries: None, make_codegen_backend: None, diff --git a/tests/run-make/dump-ice-to-disk/check.sh b/tests/run-make/dump-ice-to-disk/check.sh index ab6f9ab6018..ff6e4be35af 100644 --- a/tests/run-make/dump-ice-to-disk/check.sh +++ b/tests/run-make/dump-ice-to-disk/check.sh @@ -11,6 +11,12 @@ export RUSTC_ICE=$TMPDIR $RUSTC src/lib.rs -Z treat-err-as-bug=1 1>$TMPDIR/rust-test-default-set.log 2>&1 default_set=$(cat $TMPDIR/rustc-ice-*.txt | wc -l) content=$(cat $TMPDIR/rustc-ice-*.txt) +# Ensure that the ICE dump path doesn't contain `:` because they cause problems on Windows +windows_safe=$(echo rustc-ice-*.txt | grep ':') +if [ ! -z "$windows_safe" ]; then + exit 1 +fi + rm $TMPDIR/rustc-ice-*.txt RUST_BACKTRACE=short $RUSTC src/lib.rs -Z treat-err-as-bug=1 1>$TMPDIR/rust-test-short.log 2>&1 short=$(cat $TMPDIR/rustc-ice-*.txt | wc -l) diff --git a/tests/run-make/emit-stack-sizes/foo.rs b/tests/run-make/emit-stack-sizes/foo.rs index ee51ae32886..fd0b5120578 100644 --- a/tests/run-make/emit-stack-sizes/foo.rs +++ b/tests/run-make/emit-stack-sizes/foo.rs @@ -1,3 +1,4 @@ #![crate_type = "lib"] +#[inline(never)] pub fn foo() {} diff --git a/tests/run-make/intrinsic-unreachable/exit-ret.rs b/tests/run-make/intrinsic-unreachable/exit-ret.rs index e7b9694d9f2..c8ba5b4599f 100644 --- a/tests/run-make/intrinsic-unreachable/exit-ret.rs +++ b/tests/run-make/intrinsic-unreachable/exit-ret.rs @@ -2,6 +2,7 @@ use std::arch::asm; #[deny(unreachable_code)] +#[inline(never)] pub fn exit(n: usize) -> i32 { unsafe { // Pretend this asm is an exit() syscall. diff --git a/tests/run-make/intrinsic-unreachable/exit-unreachable.rs b/tests/run-make/intrinsic-unreachable/exit-unreachable.rs index ec85db733df..75f893eb2df 100644 --- a/tests/run-make/intrinsic-unreachable/exit-unreachable.rs +++ b/tests/run-make/intrinsic-unreachable/exit-unreachable.rs @@ -5,6 +5,7 @@ use std::arch::asm; use std::intrinsics; #[allow(unreachable_code)] +#[inline(never)] pub fn exit(n: usize) -> i32 { unsafe { // Pretend this asm is an exit() syscall. diff --git a/tests/run-make/wasm-override-linker/Makefile b/tests/run-make/wasm-override-linker/Makefile new file mode 100644 index 00000000000..52339f9261c --- /dev/null +++ b/tests/run-make/wasm-override-linker/Makefile @@ -0,0 +1,13 @@ +# needs-matching-clang + +include ../tools.mk + +ifeq ($(TARGET),wasm32-unknown-unknown) +all: + $(RUSTC) foo.rs --crate-type cdylib --target $(TARGET) -C linker=$(CLANG) +else ifeq ($(TARGET),wasm64-unknown-unknown) +all: + $(RUSTC) foo.rs --crate-type cdylib --target $(TARGET) -C linker=$(CLANG) +else +all: +endif diff --git a/tests/run-make/wasm-override-linker/foo.rs b/tests/run-make/wasm-override-linker/foo.rs new file mode 100644 index 00000000000..f4167a4fc4a --- /dev/null +++ b/tests/run-make/wasm-override-linker/foo.rs @@ -0,0 +1,6 @@ +#![crate_type = "cdylib"] + +#[no_mangle] +pub extern "C" fn add(a: i32, b: i32) -> i32 { + a + b +} diff --git a/tests/rustdoc-gui/anchors.goml b/tests/rustdoc-gui/anchors.goml index 30b83f0da38..72e0bcd77e0 100644 --- a/tests/rustdoc-gui/anchors.goml +++ b/tests/rustdoc-gui/anchors.goml @@ -56,7 +56,7 @@ define-function: ( assert-css: ("#top-doc-prose-title", {"color": |title_color|}) - assert-css: (".sidebar a", {"color": |sidebar_link_color|}) + assert-css: (".sidebar .block a", {"color": |sidebar_link_color|}) assert-css: (".main-heading h1 a", {"color": |title_color|}) // We move the cursor over the "Implementations" title so the anchor is displayed. diff --git a/tests/rustdoc-gui/huge-logo.goml b/tests/rustdoc-gui/huge-logo.goml index 6d3eb66068c..bfc24c3260d 100644 --- a/tests/rustdoc-gui/huge-logo.goml +++ b/tests/rustdoc-gui/huge-logo.goml @@ -4,8 +4,8 @@ go-to: "file://" + |DOC_PATH| + "/huge_logo/index.html" set-window-size: (1280, 1024) // offsetWidth = width of sidebar -assert-property: (".sidebar .logo-container", {"offsetWidth": "200", "offsetHeight": 100}) -assert-property: (".sidebar .logo-container img", {"offsetWidth": "100", "offsetHeight": 100}) +assert-property: (".sidebar-crate .logo-container", {"offsetWidth": "48", "offsetHeight": 48}) +assert-property: (".sidebar-crate .logo-container img", {"offsetWidth": "48", "offsetHeight": 48}) set-window-size: (400, 600) // offset = size + margin diff --git a/tests/rustdoc-gui/rust-logo.goml b/tests/rustdoc-gui/rust-logo.goml index cd453aea276..696cab34dcc 100644 --- a/tests/rustdoc-gui/rust-logo.goml +++ b/tests/rustdoc-gui/rust-logo.goml @@ -1,18 +1,18 @@ // This test ensures that the correct style is applied to the rust logo in the sidebar. -go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +go-to: "file://" + |DOC_PATH| + "/staged_api/index.html" define-function: ( "check-logo", (theme, filter), block { // Going to the doc page. - go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" + go-to: "file://" + |DOC_PATH| + "/staged_api/index.html" // Changing theme. set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} reload: assert-css: (".rust-logo", {"filter": |filter|}) // Going to the source code page. - go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" + go-to: "file://" + |DOC_PATH| + "/src/staged_api/lib.rs.html" // Changing theme (since it's local files, the local storage works by folder). set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} reload: @@ -26,6 +26,15 @@ define-function: ( assert-false: ".rust-logo" // Check there is no filter. assert-css: (".sidebar .logo-container img", {"filter": "none"}) + // Now we check that this page has no logo at all + go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" + assert-false: ".rust-logo" + assert-false: ".logo-container" + assert-false: ".sub-logo-container" + go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" + assert-false: ".rust-logo" + assert-false: ".logo-container" + assert-false: ".sub-logo-container" }, ) diff --git a/tests/rustdoc-gui/search-result-impl-disambiguation.goml b/tests/rustdoc-gui/search-result-impl-disambiguation.goml new file mode 100644 index 00000000000..6d12032e891 --- /dev/null +++ b/tests/rustdoc-gui/search-result-impl-disambiguation.goml @@ -0,0 +1,43 @@ +// ignore-tidy-linelength + +// Checks that, if a type has two methods with the same name, they both get +// linked correctly. +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" + +// This should link to the inherent impl +write: (".search-input", "ZyxwvutMethodDisambiguation -> bool") +// To be SURE that the search will be run. +press-key: 'Enter' +// Waiting for the search results to appear... +wait-for: "#search-tabs" +// Check the disambiguated link. +assert-count: ("a.result-method", 1) +assert-attribute: ("a.result-method", { + "href": "../test_docs/struct.ZyxwvutMethodDisambiguation.html#impl-ZyxwvutMethodDisambiguation/method.method_impl_disambiguation" +}) +click: "a.result-method" +wait-for: "#impl-ZyxwvutMethodDisambiguation" +assert-document-property: ({ + "URL": "struct.ZyxwvutMethodDisambiguation.html#method.method_impl_disambiguation" +}, ENDS_WITH) +assert: "section:target" + +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" + +// This should link to the trait impl +write: (".search-input", "ZyxwvutMethodDisambiguation, usize -> usize") +// To be SURE that the search will be run. +press-key: 'Enter' +// Waiting for the search results to appear... +wait-for: "#search-tabs" +// Check the disambiguated link. +assert-count: ("a.result-method", 1) +assert-attribute: ("a.result-method", { + "href": "../test_docs/struct.ZyxwvutMethodDisambiguation.html#impl-ZyxwvutTrait-for-ZyxwvutMethodDisambiguation/method.method_impl_disambiguation" +}) +click: "a.result-method" +wait-for: "#impl-ZyxwvutMethodDisambiguation" +assert-document-property: ({ + "URL": "struct.ZyxwvutMethodDisambiguation.html#method.method_impl_disambiguation-1" +}, ENDS_WITH) +assert: "section:target" diff --git a/tests/rustdoc-gui/sidebar-mobile.goml b/tests/rustdoc-gui/sidebar-mobile.goml index 4b8337ace3a..d3a82d9ebe6 100644 --- a/tests/rustdoc-gui/sidebar-mobile.goml +++ b/tests/rustdoc-gui/sidebar-mobile.goml @@ -26,7 +26,7 @@ assert-css: (".sidebar", {"left": "0px"}) // Make sure the "struct Foo" header is hidden, since the mobile topbar already does it. assert-css: ("//nav[contains(@class, 'sidebar')]//h2/a[text()='Foo']/parent::h2", {"display": "none"}) // Make sure the global navigation is still here. -assert-css: ("//nav[contains(@class, 'sidebar')]//h2/a[text()='In test_docs']/parent::h2", {"display": "block"}) +assert-css: ("//nav[contains(@class, 'sidebar')]//h2/a[text()='In crate test_docs']/parent::h2", {"display": "block"}) // Click elsewhere. click: "body" @@ -50,7 +50,7 @@ assert-position: ("#method\.must_use", {"y": 46}) // Check that the bottom-most item on the sidebar menu can be scrolled fully into view. click: ".sidebar-menu-toggle" scroll-to: ".block.keyword li:nth-child(1)" -compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 543.19}) +compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 544}) // Now checking the background color of the sidebar. show-text: true diff --git a/tests/rustdoc-gui/sidebar-source-code-display.goml b/tests/rustdoc-gui/sidebar-source-code-display.goml index 88546ed2549..cea4db1466b 100644 --- a/tests/rustdoc-gui/sidebar-source-code-display.goml +++ b/tests/rustdoc-gui/sidebar-source-code-display.goml @@ -174,14 +174,14 @@ click: "#src-sidebar-toggle" wait-for-css: (".sidebar", {"left": "-1000px"}) // We scroll to line 117 to change the scroll position. scroll-to: '//*[@id="117"]' -assert-window-property: {"pageYOffset": "2542"} +assert-window-property: {"pageYOffset": "2516"} // Expanding the sidebar... click: "#src-sidebar-toggle" wait-for-css: (".sidebar", {"left": "0px"}) click: "#src-sidebar-toggle" wait-for-css: (".sidebar", {"left": "-1000px"}) // The "scrollTop" property should be the same. -assert-window-property: {"pageYOffset": "2542"} +assert-window-property: {"pageYOffset": "2516"} // We now check that opening the sidebar and clicking a link will close it. // The behavior here on mobile is different than the behavior on desktop, diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml index 520481d3bba..eff66d803d2 100644 --- a/tests/rustdoc-gui/sidebar.goml +++ b/tests/rustdoc-gui/sidebar.goml @@ -50,9 +50,9 @@ set-local-storage: {"rustdoc-theme": "light"} // We reload the page so the local storage settings are being used. reload: -assert-text: (".sidebar > .location", "Crate test_docs") -// In modules, we only have one "location" element. -assert-count: (".sidebar .location", 1) +assert-text: (".sidebar > .sidebar-crate > h2 > a", "test_docs") +// Crate root has no "location" element +assert-count: (".sidebar .location", 0) assert-count: (".sidebar h2", 1) assert-text: ("#all-types", "All Items") assert-css: ("#all-types", {"color": "#356da4"}) @@ -74,8 +74,9 @@ assert-text: ("#structs + .item-table .item-name > a", "Foo") click: "#structs + .item-table .item-name > a" // PAGE: struct.Foo.html +assert-count: (".sidebar .sidebar-crate", 1) assert-count: (".sidebar .location", 1) -assert-count: (".sidebar h2", 2) +assert-count: (".sidebar h2", 3) // We check that there is no crate listed outside of the top level. assert-false: ".sidebar-elems > .crate" @@ -94,7 +95,8 @@ click: ".sidebar-elems ul.crate > li:first-child > a" // PAGE: lib2/index.html go-to: "file://" + |DOC_PATH| + "/lib2/index.html" assert-property: (".sidebar", {"clientWidth": "200"}) -assert-text: (".sidebar > .location", "Crate lib2") +assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2") +assert-count: (".sidebar .location", 0) // We check that we have the crates list and that the "current" on is now "lib2". assert-text: (".sidebar-elems ul.crate > li > a.current", "lib2") // We now go to the "foobar" function page. @@ -108,22 +110,39 @@ click: "#functions + .item-table .item-name > a" // PAGE: fn.foobar.html // In items containing no items (like functions or constants) and in modules, we have no -// "location" elements. Only the parent module h2. +// "location" elements. Only the crate and optional parent module. +// This page, being directly below the crate, only has its heading. +assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2") assert-count: (".sidebar .location", 0) assert-count: (".sidebar h2", 1) -assert-text: (".sidebar .sidebar-elems h2", "In lib2") // We check that we don't have the crate list. assert-false: ".sidebar-elems > .crate" go-to: "./module/index.html" assert-property: (".sidebar", {"clientWidth": "200"}) +assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2") assert-text: (".sidebar > .location", "Module module") +assert-count: (".sidebar .location", 1) +// Module page requires three headings: +// - Presistent crate branding (name and version) +// - Module name, followed by TOC for module headings +// - "In crate [name]" parent pointer, followed by sibling navigation +assert-count: (".sidebar h2", 3) +assert-text: (".sidebar > .sidebar-elems > h2", "In crate lib2") +assert-property: (".sidebar > .sidebar-elems > h2 > a", { + "href": "/lib2/index.html", +}, ENDS_WITH) // We check that we don't have the crate list. assert-false: ".sidebar-elems > .crate" go-to: "./sub_module/sub_sub_module/index.html" assert-property: (".sidebar", {"clientWidth": "200"}) +assert-text: (".sidebar > .sidebar-crate > h2 > a", "lib2") assert-text: (".sidebar > .location", "Module sub_sub_module") +assert-text: (".sidebar > .sidebar-elems > h2", "In lib2::module::sub_module") +assert-property: (".sidebar > .sidebar-elems > h2 > a", { + "href": "/module/sub_module/index.html", +}, ENDS_WITH) // We check that we don't have the crate list. assert-false: ".sidebar-elems .crate" assert-text: (".sidebar-elems > section ul > li:nth-child(1)", "Functions") @@ -152,14 +171,14 @@ assert-property: (".sidebar", {"clientWidth": "200"}) // Checks that all.html and index.html have their sidebar link in the same place. go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" -store-property: (".sidebar .location a", { +store-property: (".sidebar .sidebar-crate h2 a", { "clientWidth": index_sidebar_width, "clientHeight": index_sidebar_height, "offsetTop": index_sidebar_y, "offsetLeft": index_sidebar_x, }) go-to: "file://" + |DOC_PATH| + "/test_docs/all.html" -assert-property: (".sidebar .location a", { +assert-property: (".sidebar .sidebar-crate h2 a", { "clientWidth": |index_sidebar_width|, "clientHeight": |index_sidebar_height|, "offsetTop": |index_sidebar_y|, diff --git a/tests/rustdoc-gui/source-anchor-scroll.goml b/tests/rustdoc-gui/source-anchor-scroll.goml index 0e4913cafb2..940851ea146 100644 --- a/tests/rustdoc-gui/source-anchor-scroll.goml +++ b/tests/rustdoc-gui/source-anchor-scroll.goml @@ -8,13 +8,13 @@ set-window-size: (600, 800) assert-property: ("html", {"scrollTop": "0"}) click: '//a[text() = "barbar" and @href="#5-7"]' -assert-property: ("html", {"scrollTop": "149"}) +assert-property: ("html", {"scrollTop": "123"}) click: '//a[text() = "bar" and @href="#28-36"]' -assert-property: ("html", {"scrollTop": "180"}) +assert-property: ("html", {"scrollTop": "154"}) click: '//a[text() = "sub_fn" and @href="#2-4"]' -assert-property: ("html", {"scrollTop": "77"}) +assert-property: ("html", {"scrollTop": "51"}) // We now check that clicking on lines doesn't change the scroll // Extra information: the "sub_fn" function header is on line 1. click: '//*[@id="6"]' -assert-property: ("html", {"scrollTop": "77"}) +assert-property: ("html", {"scrollTop": "51"}) diff --git a/tests/rustdoc-gui/source-code-page.goml b/tests/rustdoc-gui/source-code-page.goml index f19e3ce80e1..ad57380ae25 100644 --- a/tests/rustdoc-gui/source-code-page.goml +++ b/tests/rustdoc-gui/source-code-page.goml @@ -89,9 +89,9 @@ assert-css: (".src-line-numbers", {"text-align": "right"}) // do anything (and certainly not add a `#NaN` to the URL!). go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" // We use this assert-position to know where we will click. -assert-position: ("//*[@id='1']", {"x": 88, "y": 112}) +assert-position: ("//*[@id='1']", {"x": 88, "y": 86}) // We click on the left of the "1" anchor but still in the "src-line-number" `<pre>`. -click: (87, 103) +click: (87, 77) assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH) // Checking the source code sidebar. @@ -163,16 +163,16 @@ assert-css: ("nav.sub", {"flex-direction": "row"}) // To check this, we maintain the invariant: // // offsetTop[nav.sub form] = offsetTop[#main-content] - offsetHeight[nav.sub form] - offsetTop[nav.sub form] -assert-property: ("nav.sub form", {"offsetTop": 28, "offsetHeight": 34}) -assert-property: ("#main-content", {"offsetTop": 90}) -// 28 = 90 - 34 - 28 +assert-property: ("nav.sub form", {"offsetTop": 15, "offsetHeight": 34}) +assert-property: ("#main-content", {"offsetTop": 64}) +// 15 = 64 - 34 - 15 // Now do the same check on moderately-sized, tablet mobile. set-window-size: (700, 700) assert-css: ("nav.sub", {"flex-direction": "row"}) -assert-property: ("nav.sub form", {"offsetTop": 21, "offsetHeight": 34}) -assert-property: ("#main-content", {"offsetTop": 76}) -// 21 = 76 - 34 - 21 +assert-property: ("nav.sub form", {"offsetTop": 8, "offsetHeight": 34}) +assert-property: ("#main-content", {"offsetTop": 50}) +// 8 = 50 - 34 - 8 // Check the sidebar directory entries have a marker and spacing (tablet). store-property: ("#src-sidebar > .title", { @@ -198,7 +198,12 @@ call-function: ("check-sidebar-dir-entry", { "y": |source_sidebar_title_y| + |source_sidebar_title_height| + 6, }) +// The logo is not present on this page. +assert-false: ".sub-logo-container > img" + +// Check the staged-api page instead, which does. // Now we check that the logo has a bottom margin so it's not stuck to the search input. +go-to: "file://" + |DOC_PATH| + "/src/staged_api/lib.rs.html" assert-css: (".sub-logo-container > img", {"margin-bottom": "8px"}) store-property: (".sub-logo-container", {"clientHeight": logo_height}) assert-position: (".search-form", {"y": |logo_height| + 8}) diff --git a/tests/rustdoc-gui/src/staged_api/lib.rs b/tests/rustdoc-gui/src/staged_api/lib.rs index 0c914470e28..9b5ad1c5ff3 100644 --- a/tests/rustdoc-gui/src/staged_api/lib.rs +++ b/tests/rustdoc-gui/src/staged_api/lib.rs @@ -1,6 +1,8 @@ #![feature(staged_api)] +#![feature(rustdoc_internals)] #![allow(internal_features)] #![stable(feature = "some_feature", since = "1.3.5")] +#![doc(rust_logo)] #[stable(feature = "some_feature", since = "1.3.5")] pub struct Foo {} diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index 38180aef762..5c91bcbb4ee 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -529,3 +529,21 @@ pub mod cfgs { /// Some docs. pub mod cfgs {} } + +pub struct ZyxwvutMethodDisambiguation; + +impl ZyxwvutMethodDisambiguation { + pub fn method_impl_disambiguation(&self) -> bool { + true + } +} + +pub trait ZyxwvutTrait { + fn method_impl_disambiguation(&self, x: usize) -> usize; +} + +impl ZyxwvutTrait for ZyxwvutMethodDisambiguation { + fn method_impl_disambiguation(&self, x: usize) -> usize { + x + } +} diff --git a/tests/rustdoc-js-std/simd-type-signatures.js b/tests/rustdoc-js-std/simd-type-signatures.js new file mode 100644 index 00000000000..5c7cf372bce --- /dev/null +++ b/tests/rustdoc-js-std/simd-type-signatures.js @@ -0,0 +1,70 @@ +// exact-check +// ignore-order +// ignore-tidy-linelength + +// This test case verifies that the href points at the correct impl + +const FILTER_CRATE = "std"; + +const EXPECTED = [ + { + 'query': 'simd<i16>, simd<i16> -> simd<i16>', + 'others': [ + { + 'path': 'std::simd::prelude::Simd', + 'name': 'simd_max', + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci16,+LANES%3E/method.simd_max' + }, + { + 'path': 'std::simd::prelude::Simd', + 'name': 'simd_min', + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci16,+LANES%3E/method.simd_min' + }, + { + 'path': 'std::simd::prelude::Simd', + 'name': 'simd_clamp', + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci16,+LANES%3E/method.simd_clamp' + }, + { + 'path': 'std::simd::prelude::Simd', + 'name': 'saturating_add', + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdInt-for-Simd%3Ci16,+LANES%3E/method.saturating_add' + }, + { + 'path': 'std::simd::prelude::Simd', + 'name': 'saturating_sub', + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdInt-for-Simd%3Ci16,+LANES%3E/method.saturating_sub' + }, + ], + }, + { + 'query': 'simd<i8>, simd<i8> -> simd<i8>', + 'others': [ + { + 'path': 'std::simd::prelude::Simd', + 'name': 'simd_max', + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci8,+LANES%3E/method.simd_max' + }, + { + 'path': 'std::simd::prelude::Simd', + 'name': 'simd_min', + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci8,+LANES%3E/method.simd_min' + }, + { + 'path': 'std::simd::prelude::Simd', + 'name': 'simd_clamp', + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdOrd-for-Simd%3Ci8,+LANES%3E/method.simd_clamp' + }, + { + 'path': 'std::simd::prelude::Simd', + 'name': 'saturating_add', + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdInt-for-Simd%3Ci8,+LANES%3E/method.saturating_add' + }, + { + 'path': 'std::simd::prelude::Simd', + 'name': 'saturating_sub', + 'href': '../std/simd/prelude/struct.Simd.html#impl-SimdInt-for-Simd%3Ci8,+LANES%3E/method.saturating_sub' + }, + ], + }, +]; diff --git a/tests/rustdoc-js/auxiliary/equivalent.rs b/tests/rustdoc-js/auxiliary/equivalent.rs new file mode 100644 index 00000000000..a19b5a2d44d --- /dev/null +++ b/tests/rustdoc-js/auxiliary/equivalent.rs @@ -0,0 +1,15 @@ +use std::borrow::Borrow; + +pub trait Equivalent<K: ?Sized> { + fn equivalent(&self, key: &K) -> bool; +} + +impl<Q: ?Sized, K: ?Sized> Equivalent<K> for Q +where + Q: Eq, + K: Borrow<Q>, +{ + fn equivalent(&self, key: &K) -> bool { + PartialEq::eq(self, key.borrow()) + } +} diff --git a/tests/rustdoc-js/search-method-disambiguate.js b/tests/rustdoc-js/search-method-disambiguate.js new file mode 100644 index 00000000000..70aa895f994 --- /dev/null +++ b/tests/rustdoc-js/search-method-disambiguate.js @@ -0,0 +1,28 @@ +// exact-check +// ignore-order +// ignore-tidy-linelength + +const FILTER_CRATE = "search_method_disambiguate"; + +const EXPECTED = [ + { + 'query': 'MyTy -> bool', + 'others': [ + { + 'path': 'search_method_disambiguate::MyTy', + 'name': 'my_method', + 'href': '../search_method_disambiguate/struct.MyTy.html#impl-X-for-MyTy%3Cbool%3E/method.my_method' + }, + ], + }, + { + 'query': 'MyTy -> u8', + 'others': [ + { + 'path': 'search_method_disambiguate::MyTy', + 'name': 'my_method', + 'href': '../search_method_disambiguate/struct.MyTy.html#impl-X-for-MyTy%3Cu8%3E/method.my_method' + }, + ], + } +]; diff --git a/tests/rustdoc-js/search-method-disambiguate.rs b/tests/rustdoc-js/search-method-disambiguate.rs new file mode 100644 index 00000000000..ae884447a92 --- /dev/null +++ b/tests/rustdoc-js/search-method-disambiguate.rs @@ -0,0 +1,22 @@ +pub trait X { + type InnerType; + fn my_method(&self) -> Self::InnerType; +} + +pub struct MyTy<T> { + pub t: T, +} + +impl X for MyTy<bool> { + type InnerType = bool; + fn my_method(&self) -> bool { + self.t + } +} + +impl X for MyTy<u8> { + type InnerType = u8; + fn my_method(&self) -> u8 { + self.t + } +} diff --git a/tests/rustdoc-js/search-non-local-trait-impl.js b/tests/rustdoc-js/search-non-local-trait-impl.js new file mode 100644 index 00000000000..9ebeceb69f9 --- /dev/null +++ b/tests/rustdoc-js/search-non-local-trait-impl.js @@ -0,0 +1,9 @@ +// exact-check + +// This test ensures that methods from blanket impls of not available foreign traits +// don't show up in the search results. + +const EXPECTED = { + 'query': 'equivalent', + 'others': [], +}; diff --git a/tests/rustdoc-js/search-non-local-trait-impl.rs b/tests/rustdoc-js/search-non-local-trait-impl.rs new file mode 100644 index 00000000000..462b75b0b13 --- /dev/null +++ b/tests/rustdoc-js/search-non-local-trait-impl.rs @@ -0,0 +1,8 @@ +// aux-crate:priv:equivalent=equivalent.rs +// compile-flags: -Zunstable-options --extern equivalent +// edition:2018 + +extern crate equivalent; + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct LayoutError; diff --git a/tests/rustdoc-ui/check-cfg/check-cfg-unstable.rs b/tests/rustdoc-ui/check-cfg/check-cfg-unstable.rs index 5c500ce6ce0..806b6d1253d 100644 --- a/tests/rustdoc-ui/check-cfg/check-cfg-unstable.rs +++ b/tests/rustdoc-ui/check-cfg/check-cfg-unstable.rs @@ -1,2 +1,2 @@ // check-fail -// compile-flags: --check-cfg=names() +// compile-flags: --check-cfg=cfg() diff --git a/tests/rustdoc-ui/check-cfg/check-cfg.rs b/tests/rustdoc-ui/check-cfg/check-cfg.rs index fa8789ad3ed..96fa9e08dde 100644 --- a/tests/rustdoc-ui/check-cfg/check-cfg.rs +++ b/tests/rustdoc-ui/check-cfg/check-cfg.rs @@ -1,5 +1,5 @@ // check-pass -// compile-flags: --check-cfg=names() -Z unstable-options +// compile-flags: --check-cfg=cfg() -Z unstable-options /// uniz is nor a builtin nor pass as arguments so is unexpected #[cfg(uniz)] diff --git a/tests/rustdoc-ui/check-cfg/check-cfg.stderr b/tests/rustdoc-ui/check-cfg/check-cfg.stderr index 03fb6f96fb5..d010c1f7ec6 100644 --- a/tests/rustdoc-ui/check-cfg/check-cfg.stderr +++ b/tests/rustdoc-ui/check-cfg/check-cfg.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `uniz` --> $DIR/check-cfg.rs:5:7 | LL | #[cfg(uniz)] diff --git a/tests/rustdoc-ui/doctest/check-cfg-test.rs b/tests/rustdoc-ui/doctest/check-cfg-test.rs index 49a801c3fb3..38cd59aa790 100644 --- a/tests/rustdoc-ui/doctest/check-cfg-test.rs +++ b/tests/rustdoc-ui/doctest/check-cfg-test.rs @@ -1,5 +1,5 @@ // check-pass -// compile-flags: --test --nocapture --check-cfg=values(feature,"test") -Z unstable-options +// compile-flags: --test --nocapture --check-cfg=cfg(feature,values("test")) -Z unstable-options // normalize-stderr-test: "tests/rustdoc-ui/doctest" -> "$$DIR" // normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR" // normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" diff --git a/tests/rustdoc-ui/doctest/check-cfg-test.stderr b/tests/rustdoc-ui/doctest/check-cfg-test.stderr index f84543c2072..0bfd569e381 100644 --- a/tests/rustdoc-ui/doctest/check-cfg-test.stderr +++ b/tests/rustdoc-ui/doctest/check-cfg-test.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `invalid` --> $DIR/check-cfg-test.rs:9:7 | LL | #[cfg(feature = "invalid")] diff --git a/tests/rustdoc/issue-31808.rs b/tests/rustdoc-ui/ice-assoc-const-for-primitive-31808.rs index e55c5bd4f7c..6e4709403a4 100644 --- a/tests/rustdoc/issue-31808.rs +++ b/tests/rustdoc-ui/ice-assoc-const-for-primitive-31808.rs @@ -1,5 +1,10 @@ +// check-pass + // Test that associated item impls on primitive types don't crash rustdoc +// https://github.com/rust-lang/rust/issues/31808 +#![crate_name="issue_31808"] + pub trait Foo { const BAR: usize; type BAZ; diff --git a/tests/rustdoc-ui/issues/issue-96287.stderr b/tests/rustdoc-ui/issues/issue-96287.stderr index 7722eb96028..c4809a311fc 100644 --- a/tests/rustdoc-ui/issues/issue-96287.stderr +++ b/tests/rustdoc-ui/issues/issue-96287.stderr @@ -2,7 +2,12 @@ error[E0220]: associated type `Assoc` not found for `V` --> $DIR/issue-96287.rs:7:33 | LL | pub type Foo<V> = impl Trait<V::Assoc>; - | ^^^^^ there is a similarly named associated type `Assoc` in the trait `TraitWithAssoc` + | ^^^^^ there is an associated type `Assoc` in the trait `TraitWithAssoc` + | +help: consider restricting type parameter `V` + | +LL | pub type Foo<V: TraitWithAssoc> = impl Trait<V::Assoc>; + | ++++++++++++++++ error: aborting due to previous error diff --git a/tests/rustdoc/async-trait-sig.rs b/tests/rustdoc/async-trait-sig.rs index 2578bc8f7a1..db1848f716d 100644 --- a/tests/rustdoc/async-trait-sig.rs +++ b/tests/rustdoc/async-trait-sig.rs @@ -1,6 +1,5 @@ // edition:2021 -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] pub trait Foo { diff --git a/tests/rustdoc/async-trait.rs b/tests/rustdoc/async-trait.rs index a473e467473..8de95aac22c 100644 --- a/tests/rustdoc/async-trait.rs +++ b/tests/rustdoc/async-trait.rs @@ -1,7 +1,6 @@ // aux-build:async-trait-dep.rs // edition:2021 -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] extern crate async_trait_dep; diff --git a/tests/rustdoc/auxiliary/async-trait-dep.rs b/tests/rustdoc/auxiliary/async-trait-dep.rs index 10a55dd0260..d455ee99e09 100644 --- a/tests/rustdoc/auxiliary/async-trait-dep.rs +++ b/tests/rustdoc/auxiliary/async-trait-dep.rs @@ -1,6 +1,5 @@ // edition:2021 -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] pub trait Meow { diff --git a/tests/rustdoc/auxiliary/enum-variant.rs b/tests/rustdoc/auxiliary/enum-variant.rs index 90c71b86329..a0a7fd894f9 100644 --- a/tests/rustdoc/auxiliary/enum-variant.rs +++ b/tests/rustdoc/auxiliary/enum-variant.rs @@ -22,3 +22,27 @@ pub enum H { A, C(u32), } + +#[repr(C)] +pub enum N { + A, + B, +} + +#[repr(C)] +pub enum O { + A(u32), + B, +} + +#[repr(u32)] +pub enum P { + A, + B, +} + +#[repr(u32)] +pub enum Q { + A(u32), + B, +} diff --git a/tests/rustdoc/issue-29503.rs b/tests/rustdoc/blanket-impl-29503.rs index 01ae4438500..d6a132e1c26 100644 --- a/tests/rustdoc/issue-29503.rs +++ b/tests/rustdoc/blanket-impl-29503.rs @@ -1,3 +1,6 @@ +// https://github.com/rust-lang/rust/issues/29503 +#![crate_name="issue_29503"] + use std::fmt; // @has issue_29503/trait.MyTrait.html diff --git a/tests/rustdoc/blanket-reexport-item.rs b/tests/rustdoc/blanket-reexport-item.rs index 437f0001fcf..315a38c30c5 100644 --- a/tests/rustdoc/blanket-reexport-item.rs +++ b/tests/rustdoc/blanket-reexport-item.rs @@ -1,6 +1,6 @@ #![crate_name = "foo"] -// @has foo/struct.S.html '//*[@id="impl-Into%3CU%3E-for-S"]//h3[@class="code-header"]' 'impl<T, U> Into<U> for T' +// @has foo/struct.S.html '//*[@id="impl-Into%3CU%3E-for-T"]//h3[@class="code-header"]' 'impl<T, U> Into<U> for T' pub struct S2 {} mod m { pub struct S {} diff --git a/tests/rustdoc/const-effect-param.rs b/tests/rustdoc/const-effect-param.rs new file mode 100644 index 00000000000..f50a9b96d81 --- /dev/null +++ b/tests/rustdoc/const-effect-param.rs @@ -0,0 +1,12 @@ +#![crate_name = "foo"] +#![feature(effects, const_trait_impl)] + +#[const_trait] +pub trait Tr { + fn f(); +} + +// @has foo/fn.g.html +// @has - '//pre[@class="rust item-decl"]' 'pub const fn g<T: Tr>()' +/// foo +pub const fn g<T: ~const Tr>() {} diff --git a/tests/rustdoc/const-fn-effects.rs b/tests/rustdoc/const-fn-effects.rs new file mode 100644 index 00000000000..7c19b4b2c0c --- /dev/null +++ b/tests/rustdoc/const-fn-effects.rs @@ -0,0 +1,19 @@ +#![crate_name = "foo"] +#![feature(effects)] + +// @has foo/fn.bar.html +// @has - '//pre[@class="rust item-decl"]' 'pub const fn bar() -> ' +/// foo +pub const fn bar() -> usize { + 2 +} + +// @has foo/struct.Foo.html +// @has - '//*[@class="method"]' 'const fn new()' +pub struct Foo(usize); + +impl Foo { + pub const fn new() -> Foo { + Foo(0) + } +} diff --git a/tests/rustdoc/const-generics/const-impl.rs b/tests/rustdoc/const-generics/const-impl.rs index 152b643bf4b..b424ea4b33c 100644 --- a/tests/rustdoc/const-generics/const-impl.rs +++ b/tests/rustdoc/const-generics/const-impl.rs @@ -31,7 +31,7 @@ impl<T> VSet<T, { Order::Unsorted }> { pub struct Escape<const S: &'static str>; -// @has foo/struct.Escape.html '//*[@id="impl-Escape%3Cr%23%22%3Cscript%3Ealert(%22Escape%22);%3C/script%3E%22%23%3E"]/h3[@class="code-header"]' 'impl Escape<r#"<script>alert("Escape");</script>"#>' +// @has foo/struct.Escape.html '//*[@id="impl-Escape%3C%22%3Cscript%3Ealert(%5C%22Escape%5C%22);%3C/script%3E%22%3E"]/h3[@class="code-header"]' 'impl Escape<r#"<script>alert("Escape");</script>"#>' impl Escape<r#"<script>alert("Escape");</script>"#> { pub fn f() {} } diff --git a/tests/rustdoc/issue-33302.rs b/tests/rustdoc/const-rendering-macros-33302.rs index a316f3ad99b..0f5cb921411 100644 --- a/tests/rustdoc/issue-33302.rs +++ b/tests/rustdoc/const-rendering-macros-33302.rs @@ -1,3 +1,6 @@ +// https://github.com/rust-lang/rust/issues/33302 +#![crate_name="issue_33302"] + // Ensure constant and array length values are not taken from source // code, which wreaks havoc with macros. diff --git a/tests/rustdoc/crate-version-escape.rs b/tests/rustdoc/crate-version-escape.rs index 8413709f15e..f134d9baa7d 100644 --- a/tests/rustdoc/crate-version-escape.rs +++ b/tests/rustdoc/crate-version-escape.rs @@ -2,4 +2,4 @@ #![crate_name = "foo"] -// @has 'foo/index.html' '//li[@class="version"]' 'Version <script>alert("hi")</script>' +// @has 'foo/index.html' '//*[@class="version"]' '<script>alert("hi")</script>' diff --git a/tests/rustdoc/crate-version-extra.rs b/tests/rustdoc/crate-version-extra.rs new file mode 100644 index 00000000000..72a2c4ba5f7 --- /dev/null +++ b/tests/rustdoc/crate-version-extra.rs @@ -0,0 +1,7 @@ +// compile-flags: '--crate-version=1.3.37-nightly (203c57dbe 2023-09-17)' + +#![crate_name="foo"] + +// main version next to logo, extra version data below it +// @has 'foo/index.html' '//h2/span[@class="version"]' '1.3.37-nightly' +// @has 'foo/index.html' '//nav[@class="sidebar"]/div[@class="version"]' '(203c57dbe 2023-09-17)' diff --git a/tests/rustdoc/crate-version.rs b/tests/rustdoc/crate-version.rs index 2592c98530f..d4be845b71e 100644 --- a/tests/rustdoc/crate-version.rs +++ b/tests/rustdoc/crate-version.rs @@ -1,3 +1,3 @@ // compile-flags: --crate-version=1.3.37 -// @has 'crate_version/index.html' '//*[@class="version"]' 'Version 1.3.37' +// @has 'crate_version/index.html' '//*[@class="version"]' '1.3.37' diff --git a/tests/rustdoc/issue-32890.rs b/tests/rustdoc/disambiguate-anchors-32890.rs index 970954433ec..d88601d65d3 100644 --- a/tests/rustdoc/issue-32890.rs +++ b/tests/rustdoc/disambiguate-anchors-32890.rs @@ -1,3 +1,6 @@ +// https://github.com/rust-lang/rust/issues/32890 +#![crate_name="issue_32890"] + // @has issue_32890/struct.Foo.html pub struct Foo<T>(T); diff --git a/tests/rustdoc/issue-29449.rs b/tests/rustdoc/disambiguate-anchors-header-29449.rs index 0d829cf6fcf..38a4954fc13 100644 --- a/tests/rustdoc/issue-29449.rs +++ b/tests/rustdoc/disambiguate-anchors-header-29449.rs @@ -1,3 +1,6 @@ +// https://github.com/rust-lang/rust/issues/29449 +#![crate_name="issue_29449"] + // @has issue_29449/struct.Foo.html pub struct Foo; diff --git a/tests/rustdoc/issue-33069.rs b/tests/rustdoc/doc-hidden-trait-implementors-33069.rs index 0213a53cab5..35570668ea1 100644 --- a/tests/rustdoc/issue-33069.rs +++ b/tests/rustdoc/doc-hidden-trait-implementors-33069.rs @@ -1,3 +1,6 @@ +// https://github.com/rust-lang/rust/issues/33069 +#![crate_name="issue_33069"] + pub trait Bar {} #[doc(hidden)] diff --git a/tests/rustdoc/issue-30252.rs b/tests/rustdoc/doctest-cfg-feature-30252.rs index c3777362a66..ceb8076fe35 100644 --- a/tests/rustdoc/issue-30252.rs +++ b/tests/rustdoc/doctest-cfg-feature-30252.rs @@ -1,5 +1,8 @@ // compile-flags:--test --cfg feature="bar" +// https://github.com/rust-lang/rust/issues/30252 +#![crate_name="issue_30252"] + /// ```rust /// assert_eq!(cfg!(feature = "bar"), true); /// ``` diff --git a/tests/rustdoc/issue-32556.rs b/tests/rustdoc/doctest-ignore-32556.rs index e1cf1150997..99da9358bd6 100644 --- a/tests/rustdoc/issue-32556.rs +++ b/tests/rustdoc/doctest-ignore-32556.rs @@ -1,3 +1,6 @@ +// https://github.com/rust-lang/rust/issues/32556 +#![crate_name="issue_32556"] + /// Blah blah blah /// ```ignore (testing rustdoc's handling of ignore) /// bad_assert!(); diff --git a/tests/rustdoc/enum-variant-value.rs b/tests/rustdoc/enum-variant-value.rs index c306736bfe9..096f8cd4122 100644 --- a/tests/rustdoc/enum-variant-value.rs +++ b/tests/rustdoc/enum-variant-value.rs @@ -115,3 +115,77 @@ pub enum I { C = Self::B as isize + X + 3, D = -1, } + +// Testing `repr`. + +// @has 'foo/enum.J.html' +// @has - '//*[@class="rust item-decl"]/code' 'A = 0,' +// @has - '//*[@class="rust item-decl"]/code' 'B = 1,' +// @matches - '//*[@id="variant.A"]/h3' '^A = 0$' +// @matches - '//*[@id="variant.B"]/h3' '^B = 1$' +#[repr(C)] +pub enum J { + A, + B, +} + +// @has 'foo/enum.K.html' +// @has - '//*[@class="rust item-decl"]/code' 'A(u32),' +// @has - '//*[@class="rust item-decl"]/code' 'B,' +// @has - '//*[@id="variant.A"]/h3' 'A(u32)' +// @matches - '//*[@id="variant.B"]/h3' '^B$' +#[repr(C)] +pub enum K { + A(u32), + B, +} + +// @has 'foo/enum.L.html' +// @has - '//*[@class="rust item-decl"]/code' 'A = 0,' +// @has - '//*[@class="rust item-decl"]/code' 'B = 1,' +// @matches - '//*[@id="variant.A"]/h3' '^A = 0$' +// @matches - '//*[@id="variant.B"]/h3' '^B = 1$' +#[repr(u32)] +pub enum L { + A, + B, +} + +// @has 'foo/enum.M.html' +// @has - '//*[@class="rust item-decl"]/code' 'A(u32),' +// @has - '//*[@class="rust item-decl"]/code' 'B,' +// @has - '//*[@id="variant.A"]/h3' 'A(u32)' +// @matches - '//*[@id="variant.B"]/h3' '^B$' +#[repr(u32)] +pub enum M { + A(u32), + B, +} + +// @has 'foo/enum.N.html' +// @has - '//*[@class="rust item-decl"]/code' 'A = 0,' +// @has - '//*[@class="rust item-decl"]/code' 'B = 1,' +// @matches - '//*[@id="variant.A"]/h3' '^A = 0$' +// @matches - '//*[@id="variant.B"]/h3' '^B = 1$' +pub use bar::N; + +// @has 'foo/enum.O.html' +// @has - '//*[@class="rust item-decl"]/code' 'A(u32),' +// @has - '//*[@class="rust item-decl"]/code' 'B,' +// @has - '//*[@id="variant.A"]/h3' 'A(u32)' +// @matches - '//*[@id="variant.B"]/h3' '^B$' +pub use bar::O; + +// @has 'foo/enum.P.html' +// @has - '//*[@class="rust item-decl"]/code' 'A = 0,' +// @has - '//*[@class="rust item-decl"]/code' 'B = 1,' +// @matches - '//*[@id="variant.A"]/h3' '^A = 0$' +// @matches - '//*[@id="variant.B"]/h3' '^B = 1$' +pub use bar::P; + +// @has 'foo/enum.Q.html' +// @has - '//*[@class="rust item-decl"]/code' 'A(u32),' +// @has - '//*[@class="rust item-decl"]/code' 'B,' +// @has - '//*[@id="variant.A"]/h3' 'A(u32)' +// @matches - '//*[@id="variant.B"]/h3' '^B$' +pub use bar::Q; diff --git a/tests/rustdoc/generic-impl.rs b/tests/rustdoc/generic-impl.rs index 6f68b157499..f62540c6bf9 100644 --- a/tests/rustdoc/generic-impl.rs +++ b/tests/rustdoc/generic-impl.rs @@ -5,9 +5,9 @@ use std::fmt; // @!has foo/struct.Bar.html '//*[@id="impl-ToString-for-Bar"]' '' pub struct Bar; -// @has foo/struct.Foo.html '//*[@id="impl-ToString-for-Foo"]//h3[@class="code-header"]' 'impl<T> ToString for T' +// @has foo/struct.Foo.html '//*[@id="impl-ToString-for-T"]//h3[@class="code-header"]' 'impl<T> ToString for T' pub struct Foo; -// @has foo/struct.Foo.html '//*[@class="sidebar-elems"]//section//a[@href="#impl-ToString-for-Foo"]' 'ToString' +// @has foo/struct.Foo.html '//*[@class="sidebar-elems"]//section//a[@href="#impl-ToString-for-T"]' 'ToString' impl fmt::Display for Foo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/tests/rustdoc/issue-34025.rs b/tests/rustdoc/hidden-extern-34025.rs index 9b9f21cb316..81ccf2a0e5c 100644 --- a/tests/rustdoc/issue-34025.rs +++ b/tests/rustdoc/hidden-extern-34025.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/34025 #![crate_name = "foo"] // @!has 'foo/sys/index.html' diff --git a/tests/rustdoc/issue-33592.rs b/tests/rustdoc/impl-type-parameter-33592.rs index 7a128f0b897..77f53710e5e 100644 --- a/tests/rustdoc/issue-33592.rs +++ b/tests/rustdoc/impl-type-parameter-33592.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/33592 #![crate_name = "foo"] pub trait Foo<T> {} diff --git a/tests/rustdoc/inline_cross/attributes.rs b/tests/rustdoc/inline_cross/attributes.rs new file mode 100644 index 00000000000..c0b75c48fee --- /dev/null +++ b/tests/rustdoc/inline_cross/attributes.rs @@ -0,0 +1,7 @@ +// aux-crate:attributes=attributes.rs +// edition:2021 +#![crate_name = "user"] + +// @has 'user/struct.NonExhaustive.html' +// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[non_exhaustive]' +pub use attributes::NonExhaustive; diff --git a/tests/rustdoc/inline_cross/auxiliary/async-fn.rs b/tests/rustdoc/inline_cross/auxiliary/async-fn.rs index 767564ed145..564ca7d671e 100644 --- a/tests/rustdoc/inline_cross/auxiliary/async-fn.rs +++ b/tests/rustdoc/inline_cross/auxiliary/async-fn.rs @@ -1,4 +1,3 @@ -#![feature(async_fn_in_trait)] // edition: 2021 pub async fn load() -> i32 { diff --git a/tests/rustdoc/inline_cross/auxiliary/attributes.rs b/tests/rustdoc/inline_cross/auxiliary/attributes.rs new file mode 100644 index 00000000000..c6f155d4ba5 --- /dev/null +++ b/tests/rustdoc/inline_cross/auxiliary/attributes.rs @@ -0,0 +1,2 @@ +#[non_exhaustive] +pub struct NonExhaustive; diff --git a/tests/rustdoc/inline_cross/auxiliary/const-fn.rs b/tests/rustdoc/inline_cross/auxiliary/const-fn.rs new file mode 100644 index 00000000000..26332b419b6 --- /dev/null +++ b/tests/rustdoc/inline_cross/auxiliary/const-fn.rs @@ -0,0 +1,5 @@ +#![feature(effects)] + +pub const fn load() -> i32 { + 0 +} diff --git a/tests/rustdoc/auxiliary/issue-29584.rs b/tests/rustdoc/inline_cross/auxiliary/issue-29584.rs index a9b8796c0fe..a9b8796c0fe 100644 --- a/tests/rustdoc/auxiliary/issue-29584.rs +++ b/tests/rustdoc/inline_cross/auxiliary/issue-29584.rs diff --git a/tests/rustdoc/inline_cross/auxiliary/repr.rs b/tests/rustdoc/inline_cross/auxiliary/repr.rs index 4a6648a6439..35f08c11b7b 100644 --- a/tests/rustdoc/inline_cross/auxiliary/repr.rs +++ b/tests/rustdoc/inline_cross/auxiliary/repr.rs @@ -10,7 +10,7 @@ pub struct ReprSimd { } #[repr(transparent)] pub struct ReprTransparent { - field: u8, + pub field: u8, } #[repr(isize)] pub enum ReprIsize { @@ -20,3 +20,23 @@ pub enum ReprIsize { pub enum ReprU8 { Bla, } + +#[repr(transparent)] // private +pub struct ReprTransparentPrivField { + field: u32, // non-1-ZST field +} + +#[repr(transparent)] // public +pub struct ReprTransparentPriv1ZstFields { + marker0: Marker, + pub main: u64, // non-1-ZST field + marker1: Marker, +} + +#[repr(transparent)] // private +pub struct ReprTransparentPrivFieldPub1ZstFields { + main: [u16; 0], // non-1-ZST field + pub marker: Marker, +} + +pub struct Marker; // 1-ZST diff --git a/tests/rustdoc/inline_cross/auxiliary/ret-pos-impl-trait-in-trait.rs b/tests/rustdoc/inline_cross/auxiliary/ret-pos-impl-trait-in-trait.rs index c72f011152d..08a3f517671 100644 --- a/tests/rustdoc/inline_cross/auxiliary/ret-pos-impl-trait-in-trait.rs +++ b/tests/rustdoc/inline_cross/auxiliary/ret-pos-impl-trait-in-trait.rs @@ -1,5 +1,3 @@ -#![feature(return_position_impl_trait_in_trait)] - pub trait Trait { fn create() -> impl Iterator<Item = u64> { std::iter::empty() diff --git a/tests/rustdoc/inline_cross/const-fn.rs b/tests/rustdoc/inline_cross/const-fn.rs new file mode 100644 index 00000000000..24934b873c2 --- /dev/null +++ b/tests/rustdoc/inline_cross/const-fn.rs @@ -0,0 +1,10 @@ +// Regression test for issue #116629. +// Check that we render the correct generic params of const fn + +// aux-crate:const_fn=const-fn.rs +// edition: 2021 +#![crate_name = "user"] + +// @has user/fn.load.html +// @has - '//pre[@class="rust item-decl"]' "pub const fn load() -> i32" +pub use const_fn::load; diff --git a/tests/rustdoc/issue-29584.rs b/tests/rustdoc/inline_cross/doc-hidden-extern-trait-impl-29584.rs index 4364a9649b5..b246e94e048 100644 --- a/tests/rustdoc/issue-29584.rs +++ b/tests/rustdoc/inline_cross/doc-hidden-extern-trait-impl-29584.rs @@ -1,6 +1,9 @@ // aux-build:issue-29584.rs // ignore-cross-compile +// https://github.com/rust-lang/rust/issues/29584 +#![crate_name="issue_29584"] + extern crate issue_29584; // @has issue_29584/struct.Foo.html diff --git a/tests/rustdoc/inline_cross/repr.rs b/tests/rustdoc/inline_cross/repr.rs index 9e107cee9e9..2f3d8f00388 100644 --- a/tests/rustdoc/inline_cross/repr.rs +++ b/tests/rustdoc/inline_cross/repr.rs @@ -9,21 +9,32 @@ extern crate repr; // @has 'foo/struct.ReprC.html' // @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(C, align(8))]' -#[doc(inline)] pub use repr::ReprC; // @has 'foo/struct.ReprSimd.html' // @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(simd, packed(2))]' -#[doc(inline)] pub use repr::ReprSimd; // @has 'foo/struct.ReprTransparent.html' // @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' -#[doc(inline)] pub use repr::ReprTransparent; // @has 'foo/enum.ReprIsize.html' // @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(isize)]' -#[doc(inline)] pub use repr::ReprIsize; // @has 'foo/enum.ReprU8.html' // @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(u8)]' -#[doc(inline)] pub use repr::ReprU8; + +// Regression test for <https://github.com/rust-lang/rust/issues/90435>. +// Check that we show `#[repr(transparent)]` iff the non-1-ZST field is public or at least one +// field is public in case all fields are 1-ZST fields. + +// @has 'foo/struct.ReprTransparentPrivField.html' +// @!has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' +pub use repr::ReprTransparentPrivField; + +// @has 'foo/struct.ReprTransparentPriv1ZstFields.html' +// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' +pub use repr::ReprTransparentPriv1ZstFields; + +// @has 'foo/struct.ReprTransparentPrivFieldPub1ZstFields.html' +// @!has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' +pub use repr::ReprTransparentPrivFieldPub1ZstFields; diff --git a/tests/rustdoc/issue-78701.rs b/tests/rustdoc/issue-78701.rs index e3e46468f38..3f1638d5ffc 100644 --- a/tests/rustdoc/issue-78701.rs +++ b/tests/rustdoc/issue-78701.rs @@ -6,7 +6,7 @@ // @has 'foo/struct.AnotherStruct.html' // @count - '//*[@class="sidebar"]//a[@href="#impl-AnAmazingTrait-for-AnotherStruct%3C()%3E"]' 1 -// @count - '//*[@class="sidebar"]//a[@href="#impl-AnAmazingTrait-for-AnotherStruct%3CT%3E"]' 1 +// @count - '//*[@class="sidebar"]//a[@href="#impl-AnAmazingTrait-for-T"]' 1 pub trait Something {} diff --git a/tests/rustdoc/issue-33178.rs b/tests/rustdoc/link-extern-crate-33178.rs index ed643f5ae11..6a63712c4a7 100644 --- a/tests/rustdoc/issue-33178.rs +++ b/tests/rustdoc/link-extern-crate-33178.rs @@ -3,6 +3,9 @@ // build-aux-docs // ignore-cross-compile +// https://github.com/rust-lang/rust/issues/33178 +#![crate_name="issue_33178"] + // @has issue_33178/index.html // @has - '//a[@title="mod empty"][@href="../empty/index.html"]' empty pub extern crate empty; diff --git a/tests/rustdoc/issue-30109.rs b/tests/rustdoc/link-extern-crate-item-30109.rs index e9447538ad7..c83234352ad 100644 --- a/tests/rustdoc/issue-30109.rs +++ b/tests/rustdoc/link-extern-crate-item-30109.rs @@ -2,6 +2,9 @@ // aux-build:issue-30109-1.rs // ignore-cross-compile +// https://github.com/rust-lang/rust/issues/30109 +#![crate_name="issue_30109"] + pub mod quux { extern crate issue_30109_1 as bar; use self::bar::Bar; diff --git a/tests/rustdoc/issue-33178-1.rs b/tests/rustdoc/link-extern-crate-title-33178.rs index 4dc425346ab..d2f115a386e 100644 --- a/tests/rustdoc/issue-33178-1.rs +++ b/tests/rustdoc/link-extern-crate-title-33178.rs @@ -2,6 +2,9 @@ // aux-build:variant-struct.rs // ignore-cross-compile +// https://github.com/rust-lang/rust/issues/33178 +#![crate_name="issue_33178_1"] + // @has issue_33178_1/index.html // @!has - //a/@title empty pub extern crate empty; diff --git a/tests/rustdoc/logo-class-default.rs b/tests/rustdoc/logo-class-default.rs index d2d4391997f..6b46b46051f 100644 --- a/tests/rustdoc/logo-class-default.rs +++ b/tests/rustdoc/logo-class-default.rs @@ -1,4 +1,4 @@ -// Note: this test is paired with logo-class.rs. -// @has logo_class_default/struct.SomeStruct.html '//*[@class="logo-container"]/img[@class="rust-logo"]' '' -// @has src/logo_class_default/logo-class-default.rs.html '//*[@class="sub-logo-container"]/img[@class="rust-logo"]' '' +// Note: this test is paired with logo-class.rs and logo-class-rust.rs. +// @!has logo_class_default/struct.SomeStruct.html '//*[@class="logo-container"]/img' '' +// @!has src/logo_class_default/logo-class-default.rs.html '//*[@class="sub-logo-container"]/img' '' pub struct SomeStruct; diff --git a/tests/rustdoc/logo-class-rust.rs b/tests/rustdoc/logo-class-rust.rs new file mode 100644 index 00000000000..d4f6113c0c0 --- /dev/null +++ b/tests/rustdoc/logo-class-rust.rs @@ -0,0 +1,7 @@ +#![feature(rustdoc_internals)] +#![allow(internal_features)] +#![doc(rust_logo)] +// Note: this test is paired with logo-class.rs and logo-class-default.rs. +// @has logo_class_rust/struct.SomeStruct.html '//*[@class="logo-container"]/img[@class="rust-logo"]' '' +// @has src/logo_class_rust/logo-class-rust.rs.html '//*[@class="sub-logo-container"]/img[@class="rust-logo"]' '' +pub struct SomeStruct; diff --git a/tests/rustdoc/logo-class.rs b/tests/rustdoc/logo-class.rs index d3aa446dab9..d15ce134cd1 100644 --- a/tests/rustdoc/logo-class.rs +++ b/tests/rustdoc/logo-class.rs @@ -1,6 +1,6 @@ #![doc(html_logo_url = "https://raw.githubusercontent.com/sagebind/isahc/master/media/isahc.svg.png")] -// Note: this test is paired with logo-class-default.rs. +// Note: this test is paired with logo-class-default.rs and logo-class-rust.rs. // @has logo_class/struct.SomeStruct.html '//*[@class="logo-container"]/img[@src="https://raw.githubusercontent.com/sagebind/isahc/master/media/isahc.svg.png"]' '' // @!has logo_class/struct.SomeStruct.html '//*[@class="logo-container"]/img[@class="rust-logo"]' '' diff --git a/tests/rustdoc/primitive/primitive-generic-impl.rs b/tests/rustdoc/primitive/primitive-generic-impl.rs index 2da8ae6ff38..558336d7316 100644 --- a/tests/rustdoc/primitive/primitive-generic-impl.rs +++ b/tests/rustdoc/primitive/primitive-generic-impl.rs @@ -1,7 +1,7 @@ #![feature(rustc_attrs)] #![crate_name = "foo"] -// @has foo/primitive.i32.html '//*[@id="impl-ToString-for-i32"]//h3[@class="code-header"]' 'impl<T> ToString for T' +// @has foo/primitive.i32.html '//*[@id="impl-ToString-for-T"]//h3[@class="code-header"]' 'impl<T> ToString for T' #[rustc_doc_primitive = "i32"] /// Some useless docs, wouhou! diff --git a/tests/rustdoc/issue-32395.rs b/tests/rustdoc/render-enum-variant-structlike-32395.rs index 5552300f9fe..2200d8ec637 100644 --- a/tests/rustdoc/issue-32395.rs +++ b/tests/rustdoc/render-enum-variant-structlike-32395.rs @@ -2,6 +2,9 @@ // build-aux-docs // ignore-cross-compile +// https://github.com/rust-lang/rust/issues/32395 +#![crate_name="issue_32395"] + // @has variant_struct/enum.Foo.html // @!hasraw - 'pub qux' // @!hasraw - 'pub(crate) qux' diff --git a/tests/rustdoc/repr.rs b/tests/rustdoc/repr.rs new file mode 100644 index 00000000000..fbb46e126ba --- /dev/null +++ b/tests/rustdoc/repr.rs @@ -0,0 +1,29 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/90435>. +// Check that we show `#[repr(transparent)]` iff the non-1-ZST field is public or at least one +// field is public in case all fields are 1-ZST fields. + +// @has 'repr/struct.ReprTransparentPrivField.html' +// @!has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' +#[repr(transparent)] // private +pub struct ReprTransparentPrivField { + field: u32, // non-1-ZST field +} + +// @has 'repr/struct.ReprTransparentPriv1ZstFields.html' +// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' +#[repr(transparent)] // public +pub struct ReprTransparentPriv1ZstFields { + marker0: Marker, + pub main: u64, // non-1-ZST field + marker1: Marker, +} + +// @has 'repr/struct.ReprTransparentPub1ZstField.html' +// @has - '//*[@class="rust item-decl"]//*[@class="code-attribute"]' '#[repr(transparent)]' +#[repr(transparent)] // public +pub struct ReprTransparentPub1ZstField { + marker0: Marker, + pub marker1: Marker, +} + +struct Marker; // 1-ZST diff --git a/tests/rustdoc/sidebar-links-to-foreign-impl.rs b/tests/rustdoc/sidebar-links-to-foreign-impl.rs index caa17dfbb1c..733a18ad94a 100644 --- a/tests/rustdoc/sidebar-links-to-foreign-impl.rs +++ b/tests/rustdoc/sidebar-links-to-foreign-impl.rs @@ -7,8 +7,8 @@ // @has - '//h2[@id="foreign-impls"]' 'Implementations on Foreign Types' // @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo-for-u32"]' 'u32' // @has - '//*[@id="impl-Foo-for-u32"]//h3[@class="code-header"]' 'impl Foo for u32' -// @has - "//*[@class=\"sidebar-elems\"]//section//a[@href=\"#impl-Foo-for-%26'a+str\"]" "&'a str" -// @has - "//*[@id=\"impl-Foo-for-%26'a+str\"]//h3[@class=\"code-header\"]" "impl<'a> Foo for &'a str" +// @has - "//*[@class=\"sidebar-elems\"]//section//a[@href=\"#impl-Foo-for-%26str\"]" "&'a str" +// @has - "//*[@id=\"impl-Foo-for-%26str\"]//h3[@class=\"code-header\"]" "impl<'a> Foo for &'a str" pub trait Foo {} impl Foo for u32 {} diff --git a/tests/rustdoc/src-links-auto-impls.rs b/tests/rustdoc/src-links-auto-impls.rs index 1c8d1573192..08a497d4cf5 100644 --- a/tests/rustdoc/src-links-auto-impls.rs +++ b/tests/rustdoc/src-links-auto-impls.rs @@ -5,8 +5,8 @@ // @!has - '//*[@id="impl-Sized-for-Unsized"]//a[@class="src"]' 'source' // @has - '//*[@id="impl-Sync-for-Unsized"]/h3[@class="code-header"]' 'impl Sync for Unsized' // @!has - '//*[@id="impl-Sync-for-Unsized"]//a[@class="src"]' 'source' -// @has - '//*[@id="impl-Any-for-Unsized"]/h3[@class="code-header"]' 'impl<T> Any for T' -// @has - '//*[@id="impl-Any-for-Unsized"]//a[@class="src rightside"]' 'source' +// @has - '//*[@id="impl-Any-for-T"]/h3[@class="code-header"]' 'impl<T> Any for T' +// @has - '//*[@id="impl-Any-for-T"]//a[@class="src rightside"]' 'source' pub struct Unsized { data: [u8], } diff --git a/tests/rustdoc/issue-34274.rs b/tests/rustdoc/src-links-inlined-34274.rs index ce5be84a549..a3c9bf7e45c 100644 --- a/tests/rustdoc/issue-34274.rs +++ b/tests/rustdoc/src-links-inlined-34274.rs @@ -2,6 +2,7 @@ // build-aux-docs // ignore-cross-compile +// https://github.com/rust-lang/rust/issues/34274 #![crate_name = "foo"] extern crate issue_34274; diff --git a/tests/rustdoc/issue-32374.rs b/tests/rustdoc/staged-api-deprecated-unstable-32374.rs index 985bf03a121..d282dea907e 100644 --- a/tests/rustdoc/issue-32374.rs +++ b/tests/rustdoc/staged-api-deprecated-unstable-32374.rs @@ -1,6 +1,8 @@ +// https://github.com/rust-lang/rust/issues/32374 #![feature(staged_api)] #![doc(issue_tracker_base_url = "https://issue_url/")] #![unstable(feature = "test", issue = "32374")] +#![crate_name="issue_32374"] // @matches issue_32374/index.html '//*[@class="item-name"]/span[@class="stab deprecated"]' \ // 'Deprecated' diff --git a/tests/rustdoc/issue-31899.rs b/tests/rustdoc/summary-codeblock-31899.rs index 3eee374465d..c1b33058c9e 100644 --- a/tests/rustdoc/issue-31899.rs +++ b/tests/rustdoc/summary-codeblock-31899.rs @@ -1,3 +1,6 @@ +// https://github.com/rust-lang/rust/issues/31899 +#![crate_name="issue_31899"] + // @has issue_31899/index.html // @hasraw - 'Make this line a bit longer.' // @!hasraw - 'rust rust-example-rendered' diff --git a/tests/rustdoc/issue-30366.rs b/tests/rustdoc/summary-reference-link-30366.rs index c6274a058b0..5b9854c5390 100644 --- a/tests/rustdoc/issue-30366.rs +++ b/tests/rustdoc/summary-reference-link-30366.rs @@ -1,5 +1,8 @@ // @has issue_30366/index.html '//a/@href' 'http://www.rust-lang.org/' +// https://github.com/rust-lang/rust/issues/30366 +#![crate_name="issue_30366"] + /// Describe it. [Link somewhere][1]. /// /// [1]: http://www.rust-lang.org/ diff --git a/tests/rustdoc/titles.rs b/tests/rustdoc/titles.rs index f6a059de620..f9da5a81375 100644 --- a/tests/rustdoc/titles.rs +++ b/tests/rustdoc/titles.rs @@ -2,7 +2,8 @@ #![feature(rustc_attrs)] // @matches 'foo/index.html' '//h1' 'Crate foo' -// @matches 'foo/index.html' '//h2[@class="location"]' 'Crate foo' +// @matches 'foo/index.html' '//div[@class="sidebar-crate"]/h2/a' 'foo' +// @count 'foo/index.html' '//h2[@class="location"]' 0 // @matches 'foo/foo_mod/index.html' '//h1' 'Module foo::foo_mod' // @matches 'foo/foo_mod/index.html' '//h2[@class="location"]' 'Module foo_mod' diff --git a/tests/rustdoc/issue-32077-type-alias-impls.rs b/tests/rustdoc/type-alias-impls-32077.rs index ac486c36ad0..7bb763f86af 100644 --- a/tests/rustdoc/issue-32077-type-alias-impls.rs +++ b/tests/rustdoc/type-alias-impls-32077.rs @@ -1,5 +1,6 @@ // Regression test for <https://github.com/rust-lang/rust/issues/32077>. +// https://github.com/rust-lang/rust/issues/32077 #![crate_name = "foo"] pub struct GenericStruct<T>(T); @@ -22,7 +23,7 @@ impl Bar for GenericStruct<u32> {} // We check that "Aliased type" is also present as a title in the sidebar. // @has - '//*[@class="sidebar-elems"]//h3/a[@href="#aliased-type"]' 'Aliased type' // We check that we have the implementation of the type alias itself. -// @has - '//*[@id="impl-TypedefStruct"]/h3' 'impl TypedefStruct' +// @has - '//*[@id="impl-GenericStruct%3Cu8%3E"]/h3' 'impl TypedefStruct' // @has - '//*[@id="method.on_alias"]/h4' 'pub fn on_alias()' // @has - '//*[@id="impl-GenericStruct%3CT%3E"]/h3' 'impl<T> GenericStruct<T>' // @has - '//*[@id="method.on_gen"]/h4' 'pub fn on_gen(arg: T)' diff --git a/tests/rustdoc/where-clause-order.rs b/tests/rustdoc/where-clause-order.rs index b10f8f6856e..7261dfa7dd9 100644 --- a/tests/rustdoc/where-clause-order.rs +++ b/tests/rustdoc/where-clause-order.rs @@ -7,7 +7,7 @@ where } // @has 'foo/trait.SomeTrait.html' -// @has - "//*[@id='impl-SomeTrait%3C(A,+B,+C,+D,+E)%3E-for-(A,+B,+C,+D,+E)']/h3" "impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E)where A: PartialOrd<A> + PartialEq<A>, B: PartialOrd<B> + PartialEq<B>, C: PartialOrd<C> + PartialEq<C>, D: PartialOrd<D> + PartialEq<D>, E: PartialOrd<E> + PartialEq<E> + ?Sized, " +// @has - "//*[@id='impl-SomeTrait-for-(A,+B,+C,+D,+E)']/h3" "impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E)where A: PartialOrd<A> + PartialEq<A>, B: PartialOrd<B> + PartialEq<B>, C: PartialOrd<C> + PartialEq<C>, D: PartialOrd<D> + PartialEq<D>, E: PartialOrd<E> + PartialEq<E> + ?Sized, " impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E) where A: PartialOrd<A> + PartialEq<A>, @@ -17,3 +17,14 @@ where E: PartialOrd<E> + PartialEq<E> + ?Sized, { } + +// @has - "//*[@id='impl-SomeTrait%3C(A,+B,+C,+D)%3E-for-(A,+B,+C,+D,+E)']/h3" "impl<A, B, C, D, E> SomeTrait<(A, B, C, D)> for (A, B, C, D, E)where A: PartialOrd<A> + PartialEq<A>, B: PartialOrd<B> + PartialEq<B>, C: PartialOrd<C> + PartialEq<C>, D: PartialOrd<D> + PartialEq<D>, E: PartialOrd<E> + PartialEq<E> + ?Sized, " +impl<A, B, C, D, E> SomeTrait<(A, B, C, D)> for (A, B, C, D, E) +where + A: PartialOrd<A> + PartialEq<A>, + B: PartialOrd<B> + PartialEq<B>, + C: PartialOrd<C> + PartialEq<C>, + D: PartialOrd<D> + PartialEq<D>, + E: PartialOrd<E> + PartialEq<E> + ?Sized, +{ +} diff --git a/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs new file mode 100644 index 00000000000..39980ee7c67 --- /dev/null +++ b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs @@ -0,0 +1,13 @@ +// Test the `rustc::span_use_eq_ctxt` internal lint +// compile-flags: -Z unstable-options + +#![feature(rustc_private)] +#![deny(rustc::span_use_eq_ctxt)] +#![crate_type = "lib"] + +extern crate rustc_span; +use rustc_span::Span; + +pub fn f(s: Span, t: Span) -> bool { + s.ctxt() == t.ctxt() //~ ERROR use `.eq_ctxt()` instead of `.ctxt() == .ctxt()` +} diff --git a/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr new file mode 100644 index 00000000000..b33f6212545 --- /dev/null +++ b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.stderr @@ -0,0 +1,14 @@ +error: use `.eq_ctxt()` instead of `.ctxt() == .ctxt()` + --> $DIR/span_use_eq_ctxt.rs:12:5 + | +LL | s.ctxt() == t.ctxt() + | ^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/span_use_eq_ctxt.rs:5:9 + | +LL | #![deny(rustc::span_use_eq_ctxt)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index 4aa14aea650..8a812bd3265 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -58,7 +58,7 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { let foo_bar = get_item(&items, (DefKind::Fn, "foo_bar")).unwrap(); let body = foo_bar.body(); - assert_eq!(body.locals.len(), 7); + assert_eq!(body.locals.len(), 5); assert_eq!(body.blocks.len(), 4); let block = &body.blocks[0]; match &block.terminator.kind { diff --git a/tests/ui-fulldeps/stable-mir/instance.rs b/tests/ui-fulldeps/stable-mir/instance.rs new file mode 100644 index 00000000000..fe06d9b5cc9 --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/instance.rs @@ -0,0 +1,91 @@ +// run-pass +// Test that users are able to use stable mir APIs to retrieve monomorphized instances + +// ignore-stage1 +// ignore-cross-compile +// ignore-remote +// edition: 2021 + +#![feature(rustc_private)] +#![feature(assert_matches)] +#![feature(control_flow_enum)] + +extern crate rustc_middle; +extern crate rustc_smir; +extern crate stable_mir; + +use rustc_middle::ty::TyCtxt; + +use stable_mir::*; +use rustc_smir::rustc_internal; +use std::io::Write; +use std::ops::ControlFlow; + +const CRATE_NAME: &str = "input"; + +/// This function uses the Stable MIR APIs to get information about the test crate. +fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { + let items = stable_mir::all_local_items(); + + // Get all items and split generic vs monomorphic items. + let (generic, mono) : (Vec<_>, Vec<_>) = items.into_iter().partition(|item| { + item.requires_monomorphization() + }); + assert_eq!(mono.len(), 3, "Expected 2 mono functions and one constant"); + assert_eq!(generic.len(), 2, "Expected 2 generic functions"); + + // For all monomorphic items, get the correspondent instances. + let instances = mono.iter().filter_map(|item| { + mir::mono::Instance::try_from(*item).ok() + }).collect::<Vec<mir::mono::Instance>>(); + assert_eq!(instances.len(), mono.len()); + + // For all generic items, try_from should fail. + assert!(generic.iter().all(|item| mir::mono::Instance::try_from(*item).is_err())); + + ControlFlow::Continue(()) +} + + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "instance_input.rs"; + generate_input(&path).unwrap(); + let args = vec![ + "rustc".to_string(), + "--crate-type=lib".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + rustc_internal::StableMir::new(args, test_stable_mir).run().unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + pub fn ty_param<T>(t: &T) -> T where T: Clone {{ + t.clone() + }} + + pub fn const_param<const LEN: usize>(a: [bool; LEN]) -> bool {{ + LEN > 0 && a[0] + }} + + pub fn monomorphic() {{ + }} + + pub mod foo {{ + pub fn bar_mono(i: i32) -> i64 {{ + i as i64 + }} + }} + "# + )?; + Ok(()) +} diff --git a/tests/ui/associated-consts/associated-const-ambiguity-report.stderr b/tests/ui/associated-consts/associated-const-ambiguity-report.stderr index 5435f22321c..e39224f2c16 100644 --- a/tests/ui/associated-consts/associated-const-ambiguity-report.stderr +++ b/tests/ui/associated-consts/associated-const-ambiguity-report.stderr @@ -14,14 +14,12 @@ note: candidate #2 is defined in an impl of the trait `Bar` for the type `i32` | LL | const ID: i32 = 3; | ^^^^^^^^^^^^^ -help: disambiguate the associated constant for candidate #1 - | -LL | const X: i32 = <i32 as Foo>::ID; - | ~~~~~~~~~~~~~~ -help: disambiguate the associated constant for candidate #2 +help: use fully-qualified syntax to disambiguate | LL | const X: i32 = <i32 as Bar>::ID; | ~~~~~~~~~~~~~~ +LL | const X: i32 = <i32 as Foo>::ID; + | ~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr b/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr index 6f206f2b89c..866a53f57fc 100644 --- a/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr +++ b/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr @@ -33,7 +33,7 @@ error[E0223]: ambiguous associated type --> $DIR/issue-109071.rs:15:22 | LL | fn T() -> Option<Self::Item> {} - | ^^^^^^^^^^ help: use the fully-qualified path: `<Windows<T> as IntoIterator>::Item` + | ^^^^^^^^^^ help: use fully-qualified syntax: `<Windows<T> as IntoIterator>::Item` error: aborting due to 4 previous errors diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr index 88c72042ce2..9206b4f6db7 100644 --- a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr +++ b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr @@ -2,7 +2,7 @@ error[E0223]: ambiguous associated type --> $DIR/not-found-self-type-differs-shadowing-trait-item.rs:28:12 | LL | let _: S::<bool>::Pr = (); - | ^^^^^^^^^^^^^ help: use the fully-qualified path: `<S<bool> as Tr>::Pr` + | ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<S<bool> as Tr>::Pr` error: aborting due to previous error diff --git a/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr b/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr index 97088b79fd6..f7a47be8dc3 100644 --- a/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr +++ b/tests/ui/associated-item/ambiguous-associated-type-with-generics.stderr @@ -2,7 +2,7 @@ error[E0223]: ambiguous associated type --> $DIR/ambiguous-associated-type-with-generics.rs:13:13 | LL | let _x: <dyn Trait<i32>>::Ty; - | ^^^^^^^^^^^^^^^^^^^^ help: use the fully-qualified path: `<dyn Trait<i32> as Assoc>::Ty` + | ^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<dyn Trait<i32> as Assoc>::Ty` error: aborting due to previous error diff --git a/tests/ui/associated-item/associated-item-duplicate-names-3.stderr b/tests/ui/associated-item/associated-item-duplicate-names-3.stderr index d0c17062076..a2346e292ac 100644 --- a/tests/ui/associated-item/associated-item-duplicate-names-3.stderr +++ b/tests/ui/associated-item/associated-item-duplicate-names-3.stderr @@ -13,7 +13,7 @@ error[E0223]: ambiguous associated type --> $DIR/associated-item-duplicate-names-3.rs:18:12 | LL | let x: Baz::Bar = 5; - | ^^^^^^^^ help: use the fully-qualified path: `<Baz as Foo>::Bar` + | ^^^^^^^^ help: use fully-qualified syntax: `<Baz as Foo>::Bar` error: aborting due to 2 previous errors diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.current.stderr b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.current.stderr index b8be132e6b6..65f7a72fbff 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.current.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.current.stderr @@ -25,7 +25,7 @@ LL | fn bar<T: Trait<method() -> (): Send>>() {} warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/bad-inputs-and-output.rs:5:12 | -LL | #![feature(return_type_notation, async_fn_in_trait)] +LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.next.stderr b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.next.stderr index b8be132e6b6..65f7a72fbff 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.next.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.next.stderr @@ -25,7 +25,7 @@ LL | fn bar<T: Trait<method() -> (): Send>>() {} warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/bad-inputs-and-output.rs:5:12 | -LL | #![feature(return_type_notation, async_fn_in_trait)] +LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs index 58ce41d1a89..4f332fa13d0 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.rs @@ -1,6 +1,6 @@ // edition: 2021 -#![feature(return_type_notation, async_fn_in_trait)] +#![feature(return_type_notation)] //~^ WARN the feature `return_type_notation` is incomplete trait Trait { diff --git a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr index 95ef7d82fca..1714dac12db 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/bad-inputs-and-output.stderr @@ -25,7 +25,7 @@ LL | fn bar<T: Trait<method() -> (): Send>>() {} warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/bad-inputs-and-output.rs:3:12 | -LL | #![feature(return_type_notation, async_fn_in_trait)] +LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.current_with.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.current_with.stderr index 98c1a282779..c4dc5d36296 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.current_with.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.current_with.stderr @@ -1,7 +1,7 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/basic.rs:8:12 | -LL | #![feature(return_type_notation, async_fn_in_trait)] +LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.current_without.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.current_without.stderr index 1066c420c31..6c2645ae5bd 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.current_without.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.current_without.stderr @@ -1,7 +1,7 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/basic.rs:8:12 | -LL | #![feature(return_type_notation, async_fn_in_trait)] +LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.next_with.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.next_with.stderr index 98c1a282779..c4dc5d36296 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.next_with.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.next_with.stderr @@ -1,7 +1,7 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/basic.rs:8:12 | -LL | #![feature(return_type_notation, async_fn_in_trait)] +LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.next_without.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.next_without.stderr index 1066c420c31..6c2645ae5bd 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.next_without.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.next_without.stderr @@ -1,7 +1,7 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/basic.rs:8:12 | -LL | #![feature(return_type_notation, async_fn_in_trait)] +LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.rs b/tests/ui/associated-type-bounds/return-type-notation/basic.rs index 3dd9249a791..7f0647534f2 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.rs @@ -2,7 +2,7 @@ // edition: 2021 // [with] check-pass -#![feature(return_type_notation, async_fn_in_trait)] +#![feature(return_type_notation)] //~^ WARN the feature `return_type_notation` is incomplete trait Foo { diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.with.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.with.stderr index 9962f4706b3..9d4bb356caa 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.with.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.with.stderr @@ -1,7 +1,7 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/basic.rs:5:12 | -LL | #![feature(return_type_notation, async_fn_in_trait)] +LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr index edce1045e24..5b96676d037 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr @@ -1,7 +1,7 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/basic.rs:5:12 | -LL | #![feature(return_type_notation, async_fn_in_trait)] +LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.current.stderr b/tests/ui/associated-type-bounds/return-type-notation/equality.current.stderr index b631dd0ebb5..d2a445f3387 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/equality.current.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/equality.current.stderr @@ -1,7 +1,7 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/equality.rs:5:12 | -LL | #![feature(return_type_notation, async_fn_in_trait)] +LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.next.stderr b/tests/ui/associated-type-bounds/return-type-notation/equality.next.stderr index b631dd0ebb5..d2a445f3387 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/equality.next.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/equality.next.stderr @@ -1,7 +1,7 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/equality.rs:5:12 | -LL | #![feature(return_type_notation, async_fn_in_trait)] +LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.rs b/tests/ui/associated-type-bounds/return-type-notation/equality.rs index 6884305d7b3..d5a29616ac5 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/equality.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/equality.rs @@ -1,6 +1,6 @@ // edition: 2021 -#![feature(return_type_notation, async_fn_in_trait)] +#![feature(return_type_notation)] //~^ WARN the feature `return_type_notation` is incomplete use std::future::Future; diff --git a/tests/ui/associated-type-bounds/return-type-notation/equality.stderr b/tests/ui/associated-type-bounds/return-type-notation/equality.stderr index 490bfdc4c3c..1a2f8471524 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/equality.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/equality.stderr @@ -1,7 +1,7 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/equality.rs:3:12 | -LL | #![feature(return_type_notation, async_fn_in_trait)] +LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information diff --git a/tests/ui/associated-type-bounds/return-type-notation/missing.rs b/tests/ui/associated-type-bounds/return-type-notation/missing.rs index a52562d78f8..0679b96f6c5 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/missing.rs +++ b/tests/ui/associated-type-bounds/return-type-notation/missing.rs @@ -1,6 +1,6 @@ // edition: 2021 -#![feature(return_type_notation, async_fn_in_trait)] +#![feature(return_type_notation)] //~^ WARN the feature `return_type_notation` is incomplete trait Trait { diff --git a/tests/ui/associated-type-bounds/return-type-notation/missing.stderr b/tests/ui/associated-type-bounds/return-type-notation/missing.stderr index 5b1c4cb0b2c..fb6538fa05c 100644 --- a/tests/ui/associated-type-bounds/return-type-notation/missing.stderr +++ b/tests/ui/associated-type-bounds/return-type-notation/missing.stderr @@ -1,7 +1,7 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/missing.rs:3:12 | -LL | #![feature(return_type_notation, async_fn_in_trait)] +LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information diff --git a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.fixed b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.fixed new file mode 100644 index 00000000000..b9f26a40219 --- /dev/null +++ b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.fixed @@ -0,0 +1,14 @@ +// run-rustfix +trait O { + type M; +} +trait U<A: O> { + const N: A::M; +} +impl<D> O for D { + type M = u8; +} +impl<C: O<M = u8>> U<C> for u16 { + const N: C::M = 4u8; //~ ERROR mismatched types +} +fn main() {} diff --git a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.rs b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.rs new file mode 100644 index 00000000000..abff6af73e2 --- /dev/null +++ b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.rs @@ -0,0 +1,14 @@ +// run-rustfix +trait O { + type M; +} +trait U<A: O> { + const N: A::M; +} +impl<D> O for D { + type M = u8; +} +impl<C: O> U<C> for u16 { + const N: C::M = 4u8; //~ ERROR mismatched types +} +fn main() {} diff --git a/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr new file mode 100644 index 00000000000..b104f38ce90 --- /dev/null +++ b/tests/ui/associated-type-bounds/suggest-contraining-assoc-type-because-of-assoc-const.stderr @@ -0,0 +1,16 @@ +error[E0308]: mismatched types + --> $DIR/suggest-contraining-assoc-type-because-of-assoc-const.rs:12:21 + | +LL | const N: C::M = 4u8; + | ^^^ expected associated type, found `u8` + | + = note: expected associated type `<C as O>::M` + found type `u8` +help: consider constraining the associated type `<C as O>::M` to `u8` + | +LL | impl<C: O<M = u8>> U<C> for u16 { + | ++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.stderr b/tests/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.stderr index 236552baf92..df01e1e3768 100644 --- a/tests/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.stderr +++ b/tests/ui/associated-types/associated-type-projection-ambig-between-bound-and-where-clause.stderr @@ -10,11 +10,11 @@ LL | type Color; LL | fn a<C:Vehicle+Box>(_: C::Color) { | ^^^^^^^^ ambiguous associated type `Color` | -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | fn a<C:Vehicle+Box>(_: <C as Box>::Color) { | ~~~~~~~~~~~~ -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | fn a<C:Vehicle+Box>(_: <C as Vehicle>::Color) { | ~~~~~~~~~~~~~~~~ @@ -31,11 +31,11 @@ LL | type Color; LL | fn b<C>(_: C::Color) where C : Vehicle+Box { | ^^^^^^^^ ambiguous associated type `Color` | -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | fn b<C>(_: <C as Box>::Color) where C : Vehicle+Box { | ~~~~~~~~~~~~ -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | fn b<C>(_: <C as Vehicle>::Color) where C : Vehicle+Box { | ~~~~~~~~~~~~~~~~ @@ -52,11 +52,11 @@ LL | type Color; LL | fn c<C>(_: C::Color) where C : Vehicle, C : Box { | ^^^^^^^^ ambiguous associated type `Color` | -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | fn c<C>(_: <C as Box>::Color) where C : Vehicle, C : Box { | ~~~~~~~~~~~~ -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | fn c<C>(_: <C as Vehicle>::Color) where C : Vehicle, C : Box { | ~~~~~~~~~~~~~~~~ @@ -73,11 +73,11 @@ LL | type Color; LL | fn e(&self, _: X::Color) where X : Box; | ^^^^^^^^ ambiguous associated type `Color` | -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | fn e(&self, _: <X as Box>::Color) where X : Box; | ~~~~~~~~~~~~ -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | fn e(&self, _: <X as Vehicle>::Color) where X : Box; | ~~~~~~~~~~~~~~~~ @@ -94,11 +94,11 @@ LL | type Color; LL | fn f(&self, _: X::Color) where X : Box { } | ^^^^^^^^ ambiguous associated type `Color` | -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | fn f(&self, _: <X as Box>::Color) where X : Box { } | ~~~~~~~~~~~~ -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | fn f(&self, _: <X as Vehicle>::Color) where X : Box { } | ~~~~~~~~~~~~~~~~ @@ -115,11 +115,11 @@ LL | type Color; LL | fn d(&self, _: X::Color) where X : Box { } | ^^^^^^^^ ambiguous associated type `Color` | -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | fn d(&self, _: <X as Box>::Color) where X : Box { } | ~~~~~~~~~~~~ -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | fn d(&self, _: <X as Vehicle>::Color) where X : Box { } | ~~~~~~~~~~~~~~~~ diff --git a/tests/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr b/tests/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr index e765f932398..4f8954b80bc 100644 --- a/tests/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr +++ b/tests/ui/associated-types/associated-type-projection-from-multiple-supertraits.stderr @@ -18,11 +18,11 @@ LL | type Color; LL | fn dent<C:BoxCar>(c: C, color: C::Color) { | ^^^^^^^^ ambiguous associated type `Color` | -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | fn dent<C:BoxCar>(c: C, color: <C as Vehicle>::Color) { | ~~~~~~~~~~~~~~~~ -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | fn dent<C:BoxCar>(c: C, color: <C as Box>::Color) { | ~~~~~~~~~~~~ @@ -71,11 +71,11 @@ LL | type Color; LL | fn paint<C:BoxCar>(c: C, d: C::Color) { | ^^^^^^^^ ambiguous associated type `Color` | -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | fn paint<C:BoxCar>(c: C, d: <C as Vehicle>::Color) { | ~~~~~~~~~~~~~~~~ -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | fn paint<C:BoxCar>(c: C, d: <C as Box>::Color) { | ~~~~~~~~~~~~ diff --git a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr index 1ff6fd4b821..d361643f024 100644 --- a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr +++ b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr @@ -13,7 +13,7 @@ error[E0223]: ambiguous associated type --> $DIR/associated-types-in-ambiguous-context.rs:22:17 | LL | trait Foo where Foo::Assoc: Bar { - | ^^^^^^^^^^ help: use the fully-qualified path: `<Self as Foo>::Assoc` + | ^^^^^^^^^^ help: use fully-qualified syntax: `<Self as Foo>::Assoc` error[E0223]: ambiguous associated type --> $DIR/associated-types-in-ambiguous-context.rs:27:10 @@ -21,7 +21,7 @@ error[E0223]: ambiguous associated type LL | type X = std::ops::Deref::Target; | ^^^^^^^^^^^^^^^^^^^^^^^ | -help: use the fully-qualified path +help: use fully-qualified syntax | LL | type X = <CString as Deref>::Target; | ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -37,7 +37,7 @@ error[E0223]: ambiguous associated type --> $DIR/associated-types-in-ambiguous-context.rs:13:23 | LL | fn grab(&self) -> Grab::Value; - | ^^^^^^^^^^^ help: use the fully-qualified path: `<Self as Grab>::Value` + | ^^^^^^^^^^^ help: use fully-qualified syntax: `<Self as Grab>::Value` error[E0223]: ambiguous associated type --> $DIR/associated-types-in-ambiguous-context.rs:16:22 diff --git a/tests/ui/associated-types/associated-types-path-1.stderr b/tests/ui/associated-types/associated-types-path-1.stderr index a67f77e37c7..cab9dcec0b6 100644 --- a/tests/ui/associated-types/associated-types-path-1.stderr +++ b/tests/ui/associated-types/associated-types-path-1.stderr @@ -16,11 +16,11 @@ LL | type A; LL | pub fn f2<T: Foo + Bar>(a: T, x: T::A) {} | ^^^^ ambiguous associated type `A` | -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | pub fn f2<T: Foo + Bar>(a: T, x: <T as Bar>::A) {} | ~~~~~~~~~~~~ -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | pub fn f2<T: Foo + Bar>(a: T, x: <T as Foo>::A) {} | ~~~~~~~~~~~~ diff --git a/tests/ui/async-await/async-trait-fn.current.stderr b/tests/ui/async-await/async-trait-fn.current.stderr deleted file mode 100644 index 7ccf2f2301d..00000000000 --- a/tests/ui/async-await/async-trait-fn.current.stderr +++ /dev/null @@ -1,42 +0,0 @@ -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/async-trait-fn.rs:6:5 - | -LL | async fn foo() {} - | -----^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/async-trait-fn.rs:7:5 - | -LL | async fn bar(&self) {} - | -----^^^^^^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/async-trait-fn.rs:8:5 - | -LL | async fn baz() { - | -----^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0706`. diff --git a/tests/ui/async-await/async-trait-fn.next.stderr b/tests/ui/async-await/async-trait-fn.next.stderr deleted file mode 100644 index 7ccf2f2301d..00000000000 --- a/tests/ui/async-await/async-trait-fn.next.stderr +++ /dev/null @@ -1,42 +0,0 @@ -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/async-trait-fn.rs:6:5 - | -LL | async fn foo() {} - | -----^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/async-trait-fn.rs:7:5 - | -LL | async fn bar(&self) {} - | -----^^^^^^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/async-trait-fn.rs:8:5 - | -LL | async fn baz() { - | -----^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0706`. diff --git a/tests/ui/async-await/async-trait-fn.rs b/tests/ui/async-await/async-trait-fn.rs index 04123badb53..4e5e3ba83e4 100644 --- a/tests/ui/async-await/async-trait-fn.rs +++ b/tests/ui/async-await/async-trait-fn.rs @@ -1,9 +1,10 @@ // edition:2018 +// check-pass trait T { - async fn foo() {} //~ ERROR functions in traits cannot be declared `async` - async fn bar(&self) {} //~ ERROR functions in traits cannot be declared `async` - async fn baz() { //~ ERROR functions in traits cannot be declared `async` + async fn foo() {} + async fn bar(&self) {} + async fn baz() { // Nested item must not ICE. fn a() {} } diff --git a/tests/ui/async-await/async-trait-fn.stderr b/tests/ui/async-await/async-trait-fn.stderr deleted file mode 100644 index 68ebe3507ac..00000000000 --- a/tests/ui/async-await/async-trait-fn.stderr +++ /dev/null @@ -1,42 +0,0 @@ -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/async-trait-fn.rs:4:5 - | -LL | async fn foo() {} - | -----^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/async-trait-fn.rs:5:5 - | -LL | async fn bar(&self) {} - | -----^^^^^^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/async-trait-fn.rs:6:5 - | -LL | async fn baz() { - | -----^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0706`. diff --git a/tests/ui/async-await/edition-deny-async-fns-2015.current.stderr b/tests/ui/async-await/edition-deny-async-fns-2015.current.stderr deleted file mode 100644 index c47b99e657e..00000000000 --- a/tests/ui/async-await/edition-deny-async-fns-2015.current.stderr +++ /dev/null @@ -1,98 +0,0 @@ -error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:5:1 - | -LL | async fn foo() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 or later - | - = help: pass `--edition 2021` to `rustc` - = note: for more on editions, read https://doc.rust-lang.org/edition-guide - -error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:7:12 - | -LL | fn baz() { async fn foo() {} } - | ^^^^^ to use `async fn`, switch to Rust 2018 or later - | - = help: pass `--edition 2021` to `rustc` - = note: for more on editions, read https://doc.rust-lang.org/edition-guide - -error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:9:1 - | -LL | async fn async_baz() { - | ^^^^^ to use `async fn`, switch to Rust 2018 or later - | - = help: pass `--edition 2021` to `rustc` - = note: for more on editions, read https://doc.rust-lang.org/edition-guide - -error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:10:5 - | -LL | async fn bar() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 or later - | - = help: pass `--edition 2021` to `rustc` - = note: for more on editions, read https://doc.rust-lang.org/edition-guide - -error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:16:5 - | -LL | async fn foo() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 or later - | - = help: pass `--edition 2021` to `rustc` - = note: for more on editions, read https://doc.rust-lang.org/edition-guide - -error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:20:5 - | -LL | async fn foo() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 or later - | - = help: pass `--edition 2021` to `rustc` - = note: for more on editions, read https://doc.rust-lang.org/edition-guide - -error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:38:9 - | -LL | async fn bar() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 or later - | - = help: pass `--edition 2021` to `rustc` - = note: for more on editions, read https://doc.rust-lang.org/edition-guide - -error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:28:9 - | -LL | async fn foo() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 or later - | - = help: pass `--edition 2021` to `rustc` - = note: for more on editions, read https://doc.rust-lang.org/edition-guide - -error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:33:13 - | -LL | async fn bar() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 or later - | - = help: pass `--edition 2021` to `rustc` - = note: for more on editions, read https://doc.rust-lang.org/edition-guide - -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/edition-deny-async-fns-2015.rs:20:5 - | -LL | async fn foo() {} - | -----^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error: aborting due to 10 previous errors - -Some errors have detailed explanations: E0670, E0706. -For more information about an error, try `rustc --explain E0670`. diff --git a/tests/ui/async-await/edition-deny-async-fns-2015.next.stderr b/tests/ui/async-await/edition-deny-async-fns-2015.next.stderr deleted file mode 100644 index c47b99e657e..00000000000 --- a/tests/ui/async-await/edition-deny-async-fns-2015.next.stderr +++ /dev/null @@ -1,98 +0,0 @@ -error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:5:1 - | -LL | async fn foo() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 or later - | - = help: pass `--edition 2021` to `rustc` - = note: for more on editions, read https://doc.rust-lang.org/edition-guide - -error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:7:12 - | -LL | fn baz() { async fn foo() {} } - | ^^^^^ to use `async fn`, switch to Rust 2018 or later - | - = help: pass `--edition 2021` to `rustc` - = note: for more on editions, read https://doc.rust-lang.org/edition-guide - -error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:9:1 - | -LL | async fn async_baz() { - | ^^^^^ to use `async fn`, switch to Rust 2018 or later - | - = help: pass `--edition 2021` to `rustc` - = note: for more on editions, read https://doc.rust-lang.org/edition-guide - -error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:10:5 - | -LL | async fn bar() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 or later - | - = help: pass `--edition 2021` to `rustc` - = note: for more on editions, read https://doc.rust-lang.org/edition-guide - -error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:16:5 - | -LL | async fn foo() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 or later - | - = help: pass `--edition 2021` to `rustc` - = note: for more on editions, read https://doc.rust-lang.org/edition-guide - -error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:20:5 - | -LL | async fn foo() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 or later - | - = help: pass `--edition 2021` to `rustc` - = note: for more on editions, read https://doc.rust-lang.org/edition-guide - -error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:38:9 - | -LL | async fn bar() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 or later - | - = help: pass `--edition 2021` to `rustc` - = note: for more on editions, read https://doc.rust-lang.org/edition-guide - -error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:28:9 - | -LL | async fn foo() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 or later - | - = help: pass `--edition 2021` to `rustc` - = note: for more on editions, read https://doc.rust-lang.org/edition-guide - -error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:33:13 - | -LL | async fn bar() {} - | ^^^^^ to use `async fn`, switch to Rust 2018 or later - | - = help: pass `--edition 2021` to `rustc` - = note: for more on editions, read https://doc.rust-lang.org/edition-guide - -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/edition-deny-async-fns-2015.rs:20:5 - | -LL | async fn foo() {} - | -----^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error: aborting due to 10 previous errors - -Some errors have detailed explanations: E0670, E0706. -For more information about an error, try `rustc --explain E0670`. diff --git a/tests/ui/async-await/edition-deny-async-fns-2015.rs b/tests/ui/async-await/edition-deny-async-fns-2015.rs index 6bd6d879a4a..9059f99ba66 100644 --- a/tests/ui/async-await/edition-deny-async-fns-2015.rs +++ b/tests/ui/async-await/edition-deny-async-fns-2015.rs @@ -16,7 +16,6 @@ impl Foo { trait Bar { async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015 - //~^ ERROR functions in traits cannot be declared `async` } fn main() { diff --git a/tests/ui/async-await/edition-deny-async-fns-2015.stderr b/tests/ui/async-await/edition-deny-async-fns-2015.stderr index ba918eb28de..c40cdc5acec 100644 --- a/tests/ui/async-await/edition-deny-async-fns-2015.stderr +++ b/tests/ui/async-await/edition-deny-async-fns-2015.stderr @@ -53,7 +53,7 @@ LL | async fn foo() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:36:9 + --> $DIR/edition-deny-async-fns-2015.rs:35:9 | LL | async fn bar() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -62,7 +62,7 @@ LL | async fn bar() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:26:9 + --> $DIR/edition-deny-async-fns-2015.rs:25:9 | LL | async fn foo() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -71,7 +71,7 @@ LL | async fn foo() {} = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/edition-deny-async-fns-2015.rs:31:13 + --> $DIR/edition-deny-async-fns-2015.rs:30:13 | LL | async fn bar() {} | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -79,20 +79,6 @@ LL | async fn bar() {} = help: pass `--edition 2021` to `rustc` = note: for more on editions, read https://doc.rust-lang.org/edition-guide -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/edition-deny-async-fns-2015.rs:18:5 - | -LL | async fn foo() {} - | -----^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors -Some errors have detailed explanations: E0670, E0706. -For more information about an error, try `rustc --explain E0670`. +For more information about this error, try `rustc --explain E0670`. diff --git a/tests/ui/async-await/feature-gate-async_fn_in_trait.rs b/tests/ui/async-await/feature-gate-async_fn_in_trait.rs deleted file mode 100644 index 792f378cb57..00000000000 --- a/tests/ui/async-await/feature-gate-async_fn_in_trait.rs +++ /dev/null @@ -1,25 +0,0 @@ -// edition:2021 - -// RPITIT is not enough to allow use of async functions -#![allow(incomplete_features)] -#![feature(return_position_impl_trait_in_trait)] - -trait T { - async fn foo(); //~ ERROR functions in traits cannot be declared `async` -} - -// Both return_position_impl_trait_in_trait and async_fn_in_trait are required for this (see also -// feature-gate-return_position_impl_trait_in_trait.rs) -trait T2 { - async fn foo() -> impl Sized; //~ ERROR functions in traits cannot be declared `async` -} - -trait T3 { - fn foo() -> impl std::future::Future<Output = ()>; -} - -impl T3 for () { - async fn foo() {} //~ ERROR functions in traits cannot be declared `async` -} - -fn main() {} diff --git a/tests/ui/async-await/feature-gate-async_fn_in_trait.stderr b/tests/ui/async-await/feature-gate-async_fn_in_trait.stderr deleted file mode 100644 index 2a5fbd1ecd0..00000000000 --- a/tests/ui/async-await/feature-gate-async_fn_in_trait.stderr +++ /dev/null @@ -1,42 +0,0 @@ -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/feature-gate-async_fn_in_trait.rs:8:5 - | -LL | async fn foo(); - | -----^^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/feature-gate-async_fn_in_trait.rs:14:5 - | -LL | async fn foo() -> impl Sized; - | -----^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/feature-gate-async_fn_in_trait.rs:22:5 - | -LL | async fn foo() {} - | -----^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0706`. diff --git a/tests/ui/async-await/in-trait/async-associated-types.rs b/tests/ui/async-await/in-trait/async-associated-types.rs index 14f18811c1e..8d89500477b 100644 --- a/tests/ui/async-await/in-trait/async-associated-types.rs +++ b/tests/ui/async-await/in-trait/async-associated-types.rs @@ -1,9 +1,6 @@ // check-pass // edition: 2021 -#![feature(async_fn_in_trait)] -#![allow(incomplete_features)] - use std::fmt::Debug; trait MyTrait<'a, 'b, T> where Self: 'a, T: Debug + Sized + 'b { diff --git a/tests/ui/async-await/in-trait/async-default-fn-overridden.rs b/tests/ui/async-await/in-trait/async-default-fn-overridden.rs index 8143f0bca03..c8fd2d8f6c2 100644 --- a/tests/ui/async-await/in-trait/async-default-fn-overridden.rs +++ b/tests/ui/async-await/in-trait/async-default-fn-overridden.rs @@ -1,7 +1,6 @@ // run-pass // edition:2021 -#![feature(async_fn_in_trait)] use std::future::Future; diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs index 38ba297189c..3cc11d241f7 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs +++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.rs @@ -1,7 +1,5 @@ // edition: 2021 -#![feature(async_fn_in_trait)] -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] use std::future::Future; diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr index 3f1f1766eb5..e6dd83b6b0a 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr +++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed-in-trait.stderr @@ -1,11 +1,11 @@ error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/async-example-desugared-boxed-in-trait.rs:15:5 + --> $DIR/async-example-desugared-boxed-in-trait.rs:13:5 | LL | async fn foo(&self) -> i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Pin<Box<dyn Future<Output = i32>>>`, found future | note: type in trait - --> $DIR/async-example-desugared-boxed-in-trait.rs:11:22 + --> $DIR/async-example-desugared-boxed-in-trait.rs:9:22 | LL | fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed.rs b/tests/ui/async-await/in-trait/async-example-desugared-boxed.rs index 1b1b3cffd58..81d25ce27ae 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-boxed.rs +++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed.rs @@ -1,7 +1,5 @@ // edition: 2021 -#![feature(async_fn_in_trait)] -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] use std::future::Future; diff --git a/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr b/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr index 60fa534a64f..cd18790fdfb 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr +++ b/tests/ui/async-await/in-trait/async-example-desugared-boxed.stderr @@ -1,5 +1,5 @@ error: method `foo` should be async because the method from the trait is async - --> $DIR/async-example-desugared-boxed.rs:15:5 + --> $DIR/async-example-desugared-boxed.rs:13:5 | LL | async fn foo(&self) -> i32; | --------------------------- required because the trait method is async diff --git a/tests/ui/async-await/in-trait/async-example-desugared-extra.rs b/tests/ui/async-await/in-trait/async-example-desugared-extra.rs index 5d5aa817b4c..f0c59180fb5 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-extra.rs +++ b/tests/ui/async-await/in-trait/async-example-desugared-extra.rs @@ -1,8 +1,7 @@ // check-pass // edition: 2021 -#![feature(async_fn_in_trait)] -#![feature(return_position_impl_trait_in_trait, lint_reasons)] +#![feature(lint_reasons)] #![allow(incomplete_features)] use std::future::Future; diff --git a/tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs b/tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs index feeda719e03..deca28af853 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs +++ b/tests/ui/async-await/in-trait/async-example-desugared-in-trait.rs @@ -1,8 +1,6 @@ // check-pass // edition: 2021 -#![feature(async_fn_in_trait)] -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] use std::future::Future; diff --git a/tests/ui/async-await/in-trait/async-example-desugared-manual.rs b/tests/ui/async-await/in-trait/async-example-desugared-manual.rs index 71473e7455f..fdba4d93c77 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-manual.rs +++ b/tests/ui/async-await/in-trait/async-example-desugared-manual.rs @@ -1,7 +1,5 @@ // edition: 2021 -#![feature(async_fn_in_trait)] -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] use std::future::Future; diff --git a/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr b/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr index 567a36a86d1..463892f21bf 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr +++ b/tests/ui/async-await/in-trait/async-example-desugared-manual.stderr @@ -1,5 +1,5 @@ error: method `foo` should be async because the method from the trait is async - --> $DIR/async-example-desugared-manual.rs:23:5 + --> $DIR/async-example-desugared-manual.rs:21:5 | LL | async fn foo(&self) -> i32; | --------------------------- required because the trait method is async diff --git a/tests/ui/async-await/in-trait/async-example-desugared.rs b/tests/ui/async-await/in-trait/async-example-desugared.rs index 7987645c97b..7fc78f7da6d 100644 --- a/tests/ui/async-await/in-trait/async-example-desugared.rs +++ b/tests/ui/async-await/in-trait/async-example-desugared.rs @@ -1,8 +1,6 @@ // check-pass // edition: 2021 -#![feature(async_fn_in_trait)] -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] use std::future::Future; diff --git a/tests/ui/async-await/in-trait/async-example.rs b/tests/ui/async-await/in-trait/async-example.rs index 8c80c21eabe..62ed490bf05 100644 --- a/tests/ui/async-await/in-trait/async-example.rs +++ b/tests/ui/async-await/in-trait/async-example.rs @@ -1,7 +1,6 @@ // check-pass // edition: 2021 -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] trait MyTrait { diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.rs b/tests/ui/async-await/in-trait/async-generics-and-bounds.rs index a73d55adfec..4e859fb27a9 100644 --- a/tests/ui/async-await/in-trait/async-generics-and-bounds.rs +++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.rs @@ -2,7 +2,6 @@ // known-bug: #102682 // edition: 2021 -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] use std::fmt::Debug; diff --git a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr index 965c385e9bc..d7251a52863 100644 --- a/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr +++ b/tests/ui/async-await/in-trait/async-generics-and-bounds.stderr @@ -1,5 +1,5 @@ error[E0311]: the parameter type `U` may not live long enough - --> $DIR/async-generics-and-bounds.rs:12:5 + --> $DIR/async-generics-and-bounds.rs:11:5 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL | async fn foo<'a>(&'a self) -> &'a (T, U) where T: Debug + Sized, U: Has | ++++ ++ ++ +++++++ error[E0311]: the parameter type `T` may not live long enough - --> $DIR/async-generics-and-bounds.rs:12:5 + --> $DIR/async-generics-and-bounds.rs:11:5 | LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash; | ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/in-trait/async-generics.rs b/tests/ui/async-await/in-trait/async-generics.rs index 67000e5770e..2d342592848 100644 --- a/tests/ui/async-await/in-trait/async-generics.rs +++ b/tests/ui/async-await/in-trait/async-generics.rs @@ -2,7 +2,6 @@ // known-bug: #102682 // edition: 2021 -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] trait MyTrait<T, U> { diff --git a/tests/ui/async-await/in-trait/async-generics.stderr b/tests/ui/async-await/in-trait/async-generics.stderr index 20c2491e9d0..aec62d12201 100644 --- a/tests/ui/async-await/in-trait/async-generics.stderr +++ b/tests/ui/async-await/in-trait/async-generics.stderr @@ -1,5 +1,5 @@ error[E0311]: the parameter type `U` may not live long enough - --> $DIR/async-generics.rs:9:5 + --> $DIR/async-generics.rs:8:5 | LL | async fn foo(&self) -> &(T, U); | ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL | async fn foo<'a>(&'a self) -> &'a (T, U) where U: 'a; | ++++ ++ ++ +++++++++++ error[E0311]: the parameter type `T` may not live long enough - --> $DIR/async-generics.rs:9:5 + --> $DIR/async-generics.rs:8:5 | LL | async fn foo(&self) -> &(T, U); | ^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs b/tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs index 96cda4e35da..ea8330a4b52 100644 --- a/tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs +++ b/tests/ui/async-await/in-trait/async-lifetimes-and-bounds.rs @@ -1,7 +1,6 @@ // check-pass // edition: 2021 -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] use std::fmt::Debug; diff --git a/tests/ui/async-await/in-trait/async-lifetimes.rs b/tests/ui/async-await/in-trait/async-lifetimes.rs index 4b0264bc8d0..6e573b9cc8b 100644 --- a/tests/ui/async-await/in-trait/async-lifetimes.rs +++ b/tests/ui/async-await/in-trait/async-lifetimes.rs @@ -1,7 +1,6 @@ // check-pass // edition: 2021 -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] trait MyTrait<'a, 'b, T> { diff --git a/tests/ui/async-await/in-trait/async-recursive-generic.rs b/tests/ui/async-await/in-trait/async-recursive-generic.rs index 6839abd381c..34f1b09756e 100644 --- a/tests/ui/async-await/in-trait/async-recursive-generic.rs +++ b/tests/ui/async-await/in-trait/async-recursive-generic.rs @@ -1,6 +1,5 @@ // edition: 2021 -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] trait MyTrait<T> { diff --git a/tests/ui/async-await/in-trait/async-recursive-generic.stderr b/tests/ui/async-await/in-trait/async-recursive-generic.stderr index 6897bf1c999..7c2df6683f0 100644 --- a/tests/ui/async-await/in-trait/async-recursive-generic.stderr +++ b/tests/ui/async-await/in-trait/async-recursive-generic.stderr @@ -1,5 +1,5 @@ error[E0733]: recursion in an `async fn` requires boxing - --> $DIR/async-recursive-generic.rs:11:5 + --> $DIR/async-recursive-generic.rs:10:5 | LL | async fn foo_recursive(&self, n: usize) -> T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn` diff --git a/tests/ui/async-await/in-trait/async-recursive.rs b/tests/ui/async-await/in-trait/async-recursive.rs index 61119f8095b..ddf119b252f 100644 --- a/tests/ui/async-await/in-trait/async-recursive.rs +++ b/tests/ui/async-await/in-trait/async-recursive.rs @@ -1,6 +1,5 @@ // edition: 2021 -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] trait MyTrait { diff --git a/tests/ui/async-await/in-trait/async-recursive.stderr b/tests/ui/async-await/in-trait/async-recursive.stderr index c9b4784e3b4..1253252cc40 100644 --- a/tests/ui/async-await/in-trait/async-recursive.stderr +++ b/tests/ui/async-await/in-trait/async-recursive.stderr @@ -1,5 +1,5 @@ error[E0733]: recursion in an `async fn` requires boxing - --> $DIR/async-recursive.rs:11:5 + --> $DIR/async-recursive.rs:10:5 | LL | async fn foo_recursive(&self, n: usize) -> i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive `async fn` diff --git a/tests/ui/async-await/in-trait/auxiliary/foreign-async-fn.rs b/tests/ui/async-await/in-trait/auxiliary/foreign-async-fn.rs index bba886f175e..57c9b3ae8b3 100644 --- a/tests/ui/async-await/in-trait/auxiliary/foreign-async-fn.rs +++ b/tests/ui/async-await/in-trait/auxiliary/foreign-async-fn.rs @@ -1,7 +1,5 @@ // edition:2021 -#![feature(async_fn_in_trait)] - pub trait Foo { async fn test(); } diff --git a/tests/ui/async-await/in-trait/bad-signatures.rs b/tests/ui/async-await/in-trait/bad-signatures.rs index 98dddc126c5..5adede5b5cf 100644 --- a/tests/ui/async-await/in-trait/bad-signatures.rs +++ b/tests/ui/async-await/in-trait/bad-signatures.rs @@ -1,6 +1,5 @@ // edition:2021 -#![feature(async_fn_in_trait)] trait MyTrait { async fn bar(&abc self); diff --git a/tests/ui/async-await/in-trait/bad-signatures.stderr b/tests/ui/async-await/in-trait/bad-signatures.stderr index 7cbd96e2487..127a343a930 100644 --- a/tests/ui/async-await/in-trait/bad-signatures.stderr +++ b/tests/ui/async-await/in-trait/bad-signatures.stderr @@ -1,11 +1,11 @@ error: expected identifier, found keyword `self` - --> $DIR/bad-signatures.rs:6:23 + --> $DIR/bad-signatures.rs:5:23 | LL | async fn bar(&abc self); | ^^^^ expected identifier, found keyword error: expected one of `:`, `@`, or `|`, found keyword `self` - --> $DIR/bad-signatures.rs:6:23 + --> $DIR/bad-signatures.rs:5:23 | LL | async fn bar(&abc self); | -----^^^^ diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs index afd3db5e052..18b0fa4856d 100644 --- a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs +++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs @@ -1,7 +1,6 @@ // edition: 2021 // known-bug: #108309 -#![feature(async_fn_in_trait)] #![feature(min_specialization)] struct MyStruct; diff --git a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr index 4ba6d4cba0c..5e2be08623b 100644 --- a/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr +++ b/tests/ui/async-await/in-trait/dont-project-to-specializable-projection.stderr @@ -1,11 +1,11 @@ error[E0053]: method `foo` has an incompatible type for trait - --> $DIR/dont-project-to-specializable-projection.rs:14:5 + --> $DIR/dont-project-to-specializable-projection.rs:13:5 | LL | default async fn foo(_: T) -> &'static str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found future | note: type in trait - --> $DIR/dont-project-to-specializable-projection.rs:10:5 + --> $DIR/dont-project-to-specializable-projection.rs:9:5 | LL | async fn foo(_: T) -> &'static str; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -13,12 +13,12 @@ LL | async fn foo(_: T) -> &'static str; found signature `fn(_) -> impl Future<Output = &'static str>` error: async associated function in trait cannot be specialized - --> $DIR/dont-project-to-specializable-projection.rs:14:5 + --> $DIR/dont-project-to-specializable-projection.rs:13:5 | LL | default async fn foo(_: T) -> &'static str { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: specialization behaves in inconsistent and surprising ways with `#![feature(async_fn_in_trait)]`, and for now is disallowed + = note: specialization behaves in inconsistent and surprising ways with async functions in traits, and for now is disallowed error: aborting due to 2 previous errors diff --git a/tests/ui/async-await/in-trait/early-bound-1.rs b/tests/ui/async-await/in-trait/early-bound-1.rs index bc410cc2954..f79d6f23c93 100644 --- a/tests/ui/async-await/in-trait/early-bound-1.rs +++ b/tests/ui/async-await/in-trait/early-bound-1.rs @@ -1,7 +1,6 @@ // check-pass // edition:2021 -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] pub trait Foo { diff --git a/tests/ui/async-await/in-trait/early-bound-2.rs b/tests/ui/async-await/in-trait/early-bound-2.rs index 1974b1d9f7a..3eba5bf757f 100644 --- a/tests/ui/async-await/in-trait/early-bound-2.rs +++ b/tests/ui/async-await/in-trait/early-bound-2.rs @@ -1,7 +1,6 @@ // check-pass // edition:2021 -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] pub trait Foo { diff --git a/tests/ui/async-await/in-trait/fn-not-async-err.rs b/tests/ui/async-await/in-trait/fn-not-async-err.rs index 9598d53bce8..60077a7e00c 100644 --- a/tests/ui/async-await/in-trait/fn-not-async-err.rs +++ b/tests/ui/async-await/in-trait/fn-not-async-err.rs @@ -1,6 +1,5 @@ // edition: 2021 -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] trait MyTrait { diff --git a/tests/ui/async-await/in-trait/fn-not-async-err.stderr b/tests/ui/async-await/in-trait/fn-not-async-err.stderr index 579801d0f39..cd085074ae3 100644 --- a/tests/ui/async-await/in-trait/fn-not-async-err.stderr +++ b/tests/ui/async-await/in-trait/fn-not-async-err.stderr @@ -1,5 +1,5 @@ error: method `foo` should be async because the method from the trait is async - --> $DIR/fn-not-async-err.rs:11:5 + --> $DIR/fn-not-async-err.rs:10:5 | LL | async fn foo(&self) -> i32; | --------------------------- required because the trait method is async diff --git a/tests/ui/async-await/in-trait/fn-not-async-err2.rs b/tests/ui/async-await/in-trait/fn-not-async-err2.rs index e1703415dbd..ed626edc4c4 100644 --- a/tests/ui/async-await/in-trait/fn-not-async-err2.rs +++ b/tests/ui/async-await/in-trait/fn-not-async-err2.rs @@ -1,6 +1,6 @@ // edition: 2021 +// check-pass -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] use std::future::Future; @@ -11,7 +11,6 @@ trait MyTrait { impl MyTrait for i32 { fn foo(&self) -> impl Future<Output = i32> { - //~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types, not in `impl` method return types async { *self } } } diff --git a/tests/ui/async-await/in-trait/fn-not-async-err2.stderr b/tests/ui/async-await/in-trait/fn-not-async-err2.stderr deleted file mode 100644 index a7c897f786e..00000000000 --- a/tests/ui/async-await/in-trait/fn-not-async-err2.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `impl` method return types - --> $DIR/fn-not-async-err2.rs:13:22 - | -LL | fn foo(&self) -> impl Future<Output = i32> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/async-await/in-trait/generics-mismatch.rs b/tests/ui/async-await/in-trait/generics-mismatch.rs index fc29783c0e3..51fdc2fe8a8 100644 --- a/tests/ui/async-await/in-trait/generics-mismatch.rs +++ b/tests/ui/async-await/in-trait/generics-mismatch.rs @@ -1,6 +1,5 @@ // edition: 2021 -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] trait Foo { diff --git a/tests/ui/async-await/in-trait/generics-mismatch.stderr b/tests/ui/async-await/in-trait/generics-mismatch.stderr index 3518aa05cec..647cc698f9f 100644 --- a/tests/ui/async-await/in-trait/generics-mismatch.stderr +++ b/tests/ui/async-await/in-trait/generics-mismatch.stderr @@ -1,5 +1,5 @@ error[E0053]: method `foo` has an incompatible generic parameter for trait `Foo` - --> $DIR/generics-mismatch.rs:11:18 + --> $DIR/generics-mismatch.rs:10:18 | LL | trait Foo { | --- diff --git a/tests/ui/async-await/in-trait/implied-bounds.rs b/tests/ui/async-await/in-trait/implied-bounds.rs index 40eebad86c2..0d8177c8e60 100644 --- a/tests/ui/async-await/in-trait/implied-bounds.rs +++ b/tests/ui/async-await/in-trait/implied-bounds.rs @@ -1,7 +1,6 @@ // check-pass // edition: 2021 -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] trait TcpStack { diff --git a/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.rs b/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.rs index 2fe6b473df6..8443cbcf4ac 100644 --- a/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.rs +++ b/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.rs @@ -2,8 +2,6 @@ // build-fail //~^^ ERROR cycle detected when computing layout of -#![feature(async_fn_in_trait)] - fn main() { let _ = async { A.first().await.second().await; diff --git a/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr b/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr index 41e84466a14..ce02c1e9967 100644 --- a/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr +++ b/tests/ui/async-await/in-trait/indirect-recursion-issue-112047.stderr @@ -1,8 +1,8 @@ -error[E0391]: cycle detected when computing layout of `{async fn body@$DIR/indirect-recursion-issue-112047.rs:35:27: 37:6}` +error[E0391]: cycle detected when computing layout of `{async fn body@$DIR/indirect-recursion-issue-112047.rs:33:27: 35:6}` | = note: ...which requires computing layout of `<<A as First>::Second as Second>::{opaque#0}`... - = note: ...which again requires computing layout of `{async fn body@$DIR/indirect-recursion-issue-112047.rs:35:27: 37:6}`, completing the cycle - = note: cycle used when computing layout of `{async block@$DIR/indirect-recursion-issue-112047.rs:8:13: 10:6}` + = note: ...which again requires computing layout of `{async fn body@$DIR/indirect-recursion-issue-112047.rs:33:27: 35:6}`, completing the cycle + = note: cycle used when computing layout of `{async block@$DIR/indirect-recursion-issue-112047.rs:6:13: 8:6}` = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to previous error diff --git a/tests/ui/async-await/in-trait/issue-102138.rs b/tests/ui/async-await/in-trait/issue-102138.rs index 3d9cef0210f..221b830fc5f 100644 --- a/tests/ui/async-await/in-trait/issue-102138.rs +++ b/tests/ui/async-await/in-trait/issue-102138.rs @@ -1,7 +1,6 @@ // check-pass // edition:2021 -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] use std::future::Future; diff --git a/tests/ui/async-await/in-trait/issue-102219.rs b/tests/ui/async-await/in-trait/issue-102219.rs index 4a23e4be4f7..1f32cf691eb 100644 --- a/tests/ui/async-await/in-trait/issue-102219.rs +++ b/tests/ui/async-await/in-trait/issue-102219.rs @@ -2,7 +2,6 @@ // edition:2021 // check-pass -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] trait T { diff --git a/tests/ui/async-await/in-trait/issue-102310.rs b/tests/ui/async-await/in-trait/issue-102310.rs index 327d432a6a6..c6321dfcbe8 100644 --- a/tests/ui/async-await/in-trait/issue-102310.rs +++ b/tests/ui/async-await/in-trait/issue-102310.rs @@ -1,7 +1,6 @@ // check-pass // edition:2021 -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] pub trait SpiDevice { diff --git a/tests/ui/async-await/in-trait/issue-104678.rs b/tests/ui/async-await/in-trait/issue-104678.rs index 0a334707505..db2fa3026fc 100644 --- a/tests/ui/async-await/in-trait/issue-104678.rs +++ b/tests/ui/async-await/in-trait/issue-104678.rs @@ -1,7 +1,6 @@ // edition:2021 // check-pass -#![feature(async_fn_in_trait)] #![allow(incomplete_features)] use std::future::Future; diff --git a/tests/ui/async-await/in-trait/lifetime-mismatch.rs b/tests/ui/async-await/in-trait/lifetime-mismatch.rs index bb793df5d85..b45d1758da4 100644 --- a/tests/ui/async-await/in-trait/lifetime-mismatch.rs +++ b/tests/ui/async-await/in-trait/lifetime-mismatch.rs @@ -1,6 +1,5 @@ // edition:2021 -#![feature(async_fn_in_trait)] trait MyTrait { async fn foo<'a>(&self); diff --git a/tests/ui/async-await/in-trait/lifetime-mismatch.stderr b/tests/ui/async-await/in-trait/lifetime-mismatch.stderr index 86592269c02..3841ab9345f 100644 --- a/tests/ui/async-await/in-trait/lifetime-mismatch.stderr +++ b/tests/ui/async-await/in-trait/lifetime-mismatch.stderr @@ -1,5 +1,5 @@ error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration - --> $DIR/lifetime-mismatch.rs:11:17 + --> $DIR/lifetime-mismatch.rs:10:17 | LL | async fn foo<'a>(&self); | ---- lifetimes in impl do not match this method in trait diff --git a/tests/ui/async-await/in-trait/missing-feature-flag.rs b/tests/ui/async-await/in-trait/missing-feature-flag.rs index 34dd50a1c30..898299a7d9d 100644 --- a/tests/ui/async-await/in-trait/missing-feature-flag.rs +++ b/tests/ui/async-await/in-trait/missing-feature-flag.rs @@ -1,6 +1,5 @@ // edition:2018 -#![feature(async_fn_in_trait)] #![feature(min_specialization)] struct MyStruct; diff --git a/tests/ui/async-await/in-trait/missing-feature-flag.stderr b/tests/ui/async-await/in-trait/missing-feature-flag.stderr index 87a7e85bfbb..b7a9e98fc49 100644 --- a/tests/ui/async-await/in-trait/missing-feature-flag.stderr +++ b/tests/ui/async-await/in-trait/missing-feature-flag.stderr @@ -1,5 +1,5 @@ error[E0046]: not all trait items implemented, missing: `foo` - --> $DIR/missing-feature-flag.rs:12:1 + --> $DIR/missing-feature-flag.rs:11:1 | LL | async fn foo(_: T) -> &'static str; | ----------------------------------- `foo` from trait @@ -8,13 +8,13 @@ LL | impl<T> MyTrait<T> for MyStruct {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation error[E0308]: mismatched types - --> $DIR/missing-feature-flag.rs:16:42 + --> $DIR/missing-feature-flag.rs:15:42 | LL | async fn foo(_: i32) -> &'static str {} | ^^ expected `&str`, found `()` error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` - --> $DIR/missing-feature-flag.rs:16:5 + --> $DIR/missing-feature-flag.rs:15:5 | LL | impl<T> MyTrait<T> for MyStruct {} | ------------------------------- parent `impl` is here diff --git a/tests/ui/async-await/in-trait/missing-send-bound.rs b/tests/ui/async-await/in-trait/missing-send-bound.rs index dbcc6657618..596aece748d 100644 --- a/tests/ui/async-await/in-trait/missing-send-bound.rs +++ b/tests/ui/async-await/in-trait/missing-send-bound.rs @@ -1,6 +1,5 @@ // edition:2021 -#![feature(async_fn_in_trait)] trait Foo { async fn bar(); diff --git a/tests/ui/async-await/in-trait/missing-send-bound.stderr b/tests/ui/async-await/in-trait/missing-send-bound.stderr index 7e59d94d456..139bd06c7df 100644 --- a/tests/ui/async-await/in-trait/missing-send-bound.stderr +++ b/tests/ui/async-await/in-trait/missing-send-bound.stderr @@ -1,17 +1,17 @@ error: future cannot be sent between threads safely - --> $DIR/missing-send-bound.rs:14:20 + --> $DIR/missing-send-bound.rs:13:20 | LL | assert_is_send(test::<T>()); | ^^^^^^^^^^^ future returned by `test` is not `Send` | = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `impl Future<Output = ()>` note: future is not `Send` as it awaits another future which is not `Send` - --> $DIR/missing-send-bound.rs:10:5 + --> $DIR/missing-send-bound.rs:9:5 | LL | T::bar().await; | ^^^^^^^^ await occurs here on type `impl Future<Output = ()>`, which is not `Send` note: required by a bound in `assert_is_send` - --> $DIR/missing-send-bound.rs:18:27 + --> $DIR/missing-send-bound.rs:17:27 | LL | fn assert_is_send(_: impl Send) {} | ^^^^ required by this bound in `assert_is_send` diff --git a/tests/ui/async-await/in-trait/nested-rpit.rs b/tests/ui/async-await/in-trait/nested-rpit.rs index 8c43e1b07e2..ccae08accb6 100644 --- a/tests/ui/async-await/in-trait/nested-rpit.rs +++ b/tests/ui/async-await/in-trait/nested-rpit.rs @@ -1,8 +1,6 @@ // edition: 2021 // check-pass -#![feature(async_fn_in_trait)] -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] use std::future::Future; diff --git a/tests/ui/async-await/in-trait/normalize-opaque-with-bound-vars.rs b/tests/ui/async-await/in-trait/normalize-opaque-with-bound-vars.rs index f8fe0d1bde8..9eb396f3202 100644 --- a/tests/ui/async-await/in-trait/normalize-opaque-with-bound-vars.rs +++ b/tests/ui/async-await/in-trait/normalize-opaque-with-bound-vars.rs @@ -5,7 +5,6 @@ // We were not normalizing opaques with escaping bound vars during codegen, // leading to later errors during debuginfo computation. -#![feature(async_fn_in_trait)] #[derive(Clone, Copy)] pub struct SharedState {} diff --git a/tests/ui/async-await/in-trait/object-safety.rs b/tests/ui/async-await/in-trait/object-safety.rs index 441539e5dd4..5e5375b082b 100644 --- a/tests/ui/async-await/in-trait/object-safety.rs +++ b/tests/ui/async-await/in-trait/object-safety.rs @@ -1,6 +1,5 @@ // edition:2021 -#![feature(async_fn_in_trait)] trait Foo { async fn foo(&self); diff --git a/tests/ui/async-await/in-trait/object-safety.stderr b/tests/ui/async-await/in-trait/object-safety.stderr index ccdf9d88708..5b9fd98ac60 100644 --- a/tests/ui/async-await/in-trait/object-safety.stderr +++ b/tests/ui/async-await/in-trait/object-safety.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety.rs:10:12 + --> $DIR/object-safety.rs:9:12 | LL | let x: &dyn Foo = todo!(); | ^^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety.rs:6:14 + --> $DIR/object-safety.rs:5:14 | LL | trait Foo { | --- this trait cannot be made into an object... diff --git a/tests/ui/async-await/in-trait/return-not-existing-pair.rs b/tests/ui/async-await/in-trait/return-not-existing-pair.rs index a14dfceed75..2286316dd88 100644 --- a/tests/ui/async-await/in-trait/return-not-existing-pair.rs +++ b/tests/ui/async-await/in-trait/return-not-existing-pair.rs @@ -1,6 +1,5 @@ // edition:2021 -#![feature(async_fn_in_trait)] trait MyTrait<'a, 'b, T> { async fn foo(&'a self, key: &'b T) -> (&'a ConnImpl, &'b T); diff --git a/tests/ui/async-await/in-trait/return-not-existing-pair.stderr b/tests/ui/async-await/in-trait/return-not-existing-pair.stderr index e573b851706..4694e608097 100644 --- a/tests/ui/async-await/in-trait/return-not-existing-pair.stderr +++ b/tests/ui/async-await/in-trait/return-not-existing-pair.stderr @@ -1,5 +1,5 @@ error[E0726]: implicit elided lifetime not allowed here - --> $DIR/return-not-existing-pair.rs:10:20 + --> $DIR/return-not-existing-pair.rs:9:20 | LL | impl<'a, 'b, T, U> MyTrait<T> for U { | ^^^^^^^^^^ expected lifetime parameters @@ -10,13 +10,13 @@ LL | impl<'a, 'b, T, U> MyTrait<'_, '_, T> for U { | +++++++ error[E0412]: cannot find type `ConnImpl` in this scope - --> $DIR/return-not-existing-pair.rs:6:48 + --> $DIR/return-not-existing-pair.rs:5:48 | LL | async fn foo(&'a self, key: &'b T) -> (&'a ConnImpl, &'b T); | ^^^^^^^^ not found in this scope error[E0186]: method `foo` has a `&self` declaration in the trait, but not in the impl - --> $DIR/return-not-existing-pair.rs:12:5 + --> $DIR/return-not-existing-pair.rs:11:5 | LL | async fn foo(&'a self, key: &'b T) -> (&'a ConnImpl, &'b T); | ------------------------------------------------------------ `&self` used in trait @@ -25,7 +25,7 @@ LL | async fn foo(_: T) -> (&'a U, &'b T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&self` in impl error[E0308]: mismatched types - --> $DIR/return-not-existing-pair.rs:12:42 + --> $DIR/return-not-existing-pair.rs:11:42 | LL | async fn foo(_: T) -> (&'a U, &'b T) {} | ^^ expected `(&U, &T)`, found `()` diff --git a/tests/ui/async-await/in-trait/return-not-existing-type-wrapping-rpitit.rs b/tests/ui/async-await/in-trait/return-not-existing-type-wrapping-rpitit.rs index 254b9a7824f..d23ef093be1 100644 --- a/tests/ui/async-await/in-trait/return-not-existing-type-wrapping-rpitit.rs +++ b/tests/ui/async-await/in-trait/return-not-existing-type-wrapping-rpitit.rs @@ -1,6 +1,5 @@ // edition:2021 -#![feature(return_position_impl_trait_in_trait)] struct Wrapper<T>(T); diff --git a/tests/ui/async-await/in-trait/return-not-existing-type-wrapping-rpitit.stderr b/tests/ui/async-await/in-trait/return-not-existing-type-wrapping-rpitit.stderr index 059934d245c..a66dd13bb7a 100644 --- a/tests/ui/async-await/in-trait/return-not-existing-type-wrapping-rpitit.stderr +++ b/tests/ui/async-await/in-trait/return-not-existing-type-wrapping-rpitit.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `Missing` in this scope - --> $DIR/return-not-existing-type-wrapping-rpitit.rs:8:25 + --> $DIR/return-not-existing-type-wrapping-rpitit.rs:7:25 | LL | fn bar() -> Wrapper<Missing<impl Sized>>; | ^^^^^^^ not found in this scope diff --git a/tests/ui/async-await/in-trait/return-type-suggestion.rs b/tests/ui/async-await/in-trait/return-type-suggestion.rs index cdab4ea0f37..2b19b24cf7a 100644 --- a/tests/ui/async-await/in-trait/return-type-suggestion.rs +++ b/tests/ui/async-await/in-trait/return-type-suggestion.rs @@ -1,6 +1,5 @@ // edition: 2021 -#![feature(async_fn_in_trait)] trait A { async fn e() { diff --git a/tests/ui/async-await/in-trait/return-type-suggestion.stderr b/tests/ui/async-await/in-trait/return-type-suggestion.stderr index 179c9ed93db..363870619f0 100644 --- a/tests/ui/async-await/in-trait/return-type-suggestion.stderr +++ b/tests/ui/async-await/in-trait/return-type-suggestion.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/return-type-suggestion.rs:7:9 + --> $DIR/return-type-suggestion.rs:6:9 | LL | Ok(()) | ^^^^^^ expected `()`, found `Result<(), _>` diff --git a/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.fixed b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.fixed index 33c00587439..affe6cded8f 100644 --- a/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.fixed +++ b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.fixed @@ -1,7 +1,6 @@ // run-rustfix // edition: 2021 -#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] #![allow(unused)] trait Foo { diff --git a/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.rs b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.rs index 96b623d6988..02bfee1a25f 100644 --- a/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.rs +++ b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.rs @@ -1,7 +1,6 @@ // run-rustfix // edition: 2021 -#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] #![allow(unused)] trait Foo { diff --git a/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.stderr b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.stderr index 4319a14118b..da51f10af94 100644 --- a/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.stderr +++ b/tests/ui/async-await/in-trait/send-on-async-fn-in-trait.stderr @@ -1,5 +1,5 @@ error[E0277]: `impl Future<Output = ()>` cannot be sent between threads safely - --> $DIR/send-on-async-fn-in-trait.rs:14:16 + --> $DIR/send-on-async-fn-in-trait.rs:13:16 | LL | needs_send(T::test()); | ---------- ^^^^^^^^^ `impl Future<Output = ()>` cannot be sent between threads safely @@ -8,7 +8,7 @@ LL | needs_send(T::test()); | = help: the trait `Send` is not implemented for `impl Future<Output = ()>` note: required by a bound in `needs_send` - --> $DIR/send-on-async-fn-in-trait.rs:13:27 + --> $DIR/send-on-async-fn-in-trait.rs:12:27 | LL | fn needs_send(_: impl Send) {} | ^^^^ required by this bound in `needs_send` @@ -19,7 +19,7 @@ LL + fn test() -> impl std::future::Future<Output = ()> + Send { async {} } | error[E0277]: `impl Future<Output = i32>` cannot be sent between threads safely - --> $DIR/send-on-async-fn-in-trait.rs:16:16 + --> $DIR/send-on-async-fn-in-trait.rs:15:16 | LL | needs_send(T::test2()); | ---------- ^^^^^^^^^^ `impl Future<Output = i32>` cannot be sent between threads safely @@ -28,7 +28,7 @@ LL | needs_send(T::test2()); | = help: the trait `Send` is not implemented for `impl Future<Output = i32>` note: required by a bound in `needs_send` - --> $DIR/send-on-async-fn-in-trait.rs:13:27 + --> $DIR/send-on-async-fn-in-trait.rs:12:27 | LL | fn needs_send(_: impl Send) {} | ^^^^ required by this bound in `needs_send` diff --git a/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.rs b/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.rs index 83b69d72a96..f0d750714cd 100644 --- a/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.rs +++ b/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.rs @@ -1,8 +1,6 @@ // aux-build:foreign-async-fn.rs // edition:2021 -#![feature(async_fn_in_trait)] - extern crate foreign_async_fn; use foreign_async_fn::Foo; diff --git a/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.stderr b/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.stderr index f337a04ba19..482707351d7 100644 --- a/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.stderr +++ b/tests/ui/async-await/in-trait/send-on-foreign-async-fn-in-trait.stderr @@ -1,5 +1,5 @@ error[E0277]: `impl Future<Output = ()>` cannot be sent between threads safely - --> $DIR/send-on-foreign-async-fn-in-trait.rs:11:16 + --> $DIR/send-on-foreign-async-fn-in-trait.rs:9:16 | LL | needs_send(T::test()); | ---------- ^^^^^^^^^ `impl Future<Output = ()>` cannot be sent between threads safely @@ -8,12 +8,12 @@ LL | needs_send(T::test()); | = help: the trait `Send` is not implemented for `impl Future<Output = ()>` note: `<T as Foo>::test` is an `async fn` in trait, which does not automatically imply that its future is `Send` - --> $DIR/auxiliary/foreign-async-fn.rs:6:5 + --> $DIR/auxiliary/foreign-async-fn.rs:4:5 | LL | async fn test(); | ^^^^^^^^^^^^^^^^ note: required by a bound in `needs_send` - --> $DIR/send-on-foreign-async-fn-in-trait.rs:10:27 + --> $DIR/send-on-foreign-async-fn-in-trait.rs:8:27 | LL | fn needs_send(_: impl Send) {} | ^^^^ required by this bound in `needs_send` diff --git a/tests/ui/async-await/in-trait/warn.rs b/tests/ui/async-await/in-trait/warn.rs index 4f981c31f5c..71f3822dfb1 100644 --- a/tests/ui/async-await/in-trait/warn.rs +++ b/tests/ui/async-await/in-trait/warn.rs @@ -1,6 +1,5 @@ // edition: 2021 -#![feature(async_fn_in_trait)] #![deny(async_fn_in_trait)] pub trait Foo { diff --git a/tests/ui/async-await/in-trait/warn.stderr b/tests/ui/async-await/in-trait/warn.stderr index eac41a6e924..d0278628c97 100644 --- a/tests/ui/async-await/in-trait/warn.stderr +++ b/tests/ui/async-await/in-trait/warn.stderr @@ -1,16 +1,16 @@ error: use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified - --> $DIR/warn.rs:7:5 + --> $DIR/warn.rs:6:5 | LL | async fn not_send(); | ^^^^^ | = note: you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future` note: the lint level is defined here - --> $DIR/warn.rs:4:9 + --> $DIR/warn.rs:3:9 | LL | #![deny(async_fn_in_trait)] | ^^^^^^^^^^^^^^^^^ -help: you can alternatively desugar to a normal `fn` that returns `impl Future` and add any desired bounds such as `Send` +help: you can alternatively desugar to a normal `fn` that returns `impl Future` and add any desired bounds such as `Send`, but these cannot be relaxed without a breaking API change | LL - async fn not_send(); LL + fn not_send() -> impl std::future::Future<Output = ()> + Send; diff --git a/tests/ui/async-await/issues/issue-95307.rs b/tests/ui/async-await/issues/issue-95307.rs index f7e48070ccd..35dce2c6217 100644 --- a/tests/ui/async-await/issues/issue-95307.rs +++ b/tests/ui/async-await/issues/issue-95307.rs @@ -5,8 +5,7 @@ pub trait C { async fn new() -> [u8; _]; - //~^ ERROR: functions in traits cannot be declared `async` - //~| ERROR: using `_` for array lengths is unstable + //~^ ERROR: using `_` for array lengths is unstable //~| ERROR: in expressions, `_` can only be used on the left-hand side of an assignment } diff --git a/tests/ui/async-await/issues/issue-95307.stderr b/tests/ui/async-await/issues/issue-95307.stderr index a497cebe3c3..fdc6d5de1a8 100644 --- a/tests/ui/async-await/issues/issue-95307.stderr +++ b/tests/ui/async-await/issues/issue-95307.stderr @@ -1,16 +1,3 @@ -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/issue-95307.rs:7:5 - | -LL | async fn new() -> [u8; _]; - | -----^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - error: in expressions, `_` can only be used on the left-hand side of an assignment --> $DIR/issue-95307.rs:7:28 | @@ -26,7 +13,6 @@ LL | async fn new() -> [u8; _]; = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0658, E0706. -For more information about an error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.rs b/tests/ui/async-await/return-type-notation/issue-110963-early.rs index 0ecbca5c13b..07f2130bab5 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-early.rs +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.rs @@ -2,7 +2,6 @@ // known-bug: #110963 #![feature(return_type_notation)] -#![feature(async_fn_in_trait)] trait HealthCheck { async fn check<'a: 'a>(&'a mut self) -> bool; diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr b/tests/ui/async-await/return-type-notation/issue-110963-early.stderr index 98e3cbd0d7f..feae2698e8f 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.stderr @@ -8,7 +8,7 @@ LL | #![feature(return_type_notation)] = note: `#[warn(incomplete_features)]` on by default error[E0308]: mismatched types - --> $DIR/issue-110963-early.rs:15:5 + --> $DIR/issue-110963-early.rs:14:5 | LL | / spawn(async move { LL | | let mut hc = hc; @@ -21,13 +21,13 @@ LL | | }); = note: expected trait `Send` found trait `for<'a> Send` note: the lifetime requirement is introduced here - --> $DIR/issue-110963-early.rs:35:17 + --> $DIR/issue-110963-early.rs:34:17 | LL | F: Future + Send + 'static, | ^^^^ error[E0308]: mismatched types - --> $DIR/issue-110963-early.rs:15:5 + --> $DIR/issue-110963-early.rs:14:5 | LL | / spawn(async move { LL | | let mut hc = hc; @@ -40,7 +40,7 @@ LL | | }); = note: expected trait `Send` found trait `for<'a> Send` note: the lifetime requirement is introduced here - --> $DIR/issue-110963-early.rs:35:17 + --> $DIR/issue-110963-early.rs:34:17 | LL | F: Future + Send + 'static, | ^^^^ diff --git a/tests/ui/async-await/return-type-notation/issue-110963-late.rs b/tests/ui/async-await/return-type-notation/issue-110963-late.rs index 17b5d775d44..7533844fb43 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-late.rs +++ b/tests/ui/async-await/return-type-notation/issue-110963-late.rs @@ -3,7 +3,6 @@ #![feature(return_type_notation)] //~^ WARN the feature `return_type_notation` is incomplete -#![feature(async_fn_in_trait)] trait HealthCheck { async fn check(&mut self) -> bool; diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr index 8f45902035e..6a47f1ab983 100644 --- a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr +++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.current.stderr @@ -1,5 +1,5 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/normalizing-self-auto-trait-issue-109924.rs:8:12 + --> $DIR/normalizing-self-auto-trait-issue-109924.rs:7:12 | LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![feature(return_type_notation)] = note: `#[warn(incomplete_features)]` on by default error[E0277]: `impl Future<Output = ()> { <_ as Foo>::bar() }` cannot be sent between threads safely - --> $DIR/normalizing-self-auto-trait-issue-109924.rs:23:11 + --> $DIR/normalizing-self-auto-trait-issue-109924.rs:22:11 | LL | build(Bar); | ----- ^^^ `impl Future<Output = ()> { <_ as Foo>::bar() }` cannot be sent between threads safely @@ -17,7 +17,7 @@ LL | build(Bar); | = help: the trait `for<'a> Send` is not implemented for `impl Future<Output = ()> { <_ as Foo>::bar() }` note: this is a known limitation of the trait solver that will be lifted in the future - --> $DIR/normalizing-self-auto-trait-issue-109924.rs:23:11 + --> $DIR/normalizing-self-auto-trait-issue-109924.rs:22:11 | LL | build(Bar); | ------^^^- @@ -25,7 +25,7 @@ LL | build(Bar); | | the trait solver is unable to infer the generic types that should be inferred from this argument | add turbofish arguments to this call to specify the types manually, even if it's redundant note: required by a bound in `build` - --> $DIR/normalizing-self-auto-trait-issue-109924.rs:20:39 + --> $DIR/normalizing-self-auto-trait-issue-109924.rs:19:39 | LL | fn build<T>(_: T) where T: Foo<bar(): Send> {} | ^^^^ required by this bound in `build` diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr index 6fab7178767..4837815fad4 100644 --- a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr +++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.next.stderr @@ -1,5 +1,5 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/normalizing-self-auto-trait-issue-109924.rs:8:12 + --> $DIR/normalizing-self-auto-trait-issue-109924.rs:7:12 | LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs index b2cd9707db9..e581e5ffda7 100644 --- a/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs +++ b/tests/ui/async-await/return-type-notation/normalizing-self-auto-trait-issue-109924.rs @@ -4,7 +4,6 @@ //[next] compile-flags: -Ztrait-solver=next // edition:2021 -#![feature(async_fn_in_trait)] #![feature(return_type_notation)] //[next]~^ WARN the feature `return_type_notation` is incomplete diff --git a/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs index e55104ee968..0ceb62d449a 100644 --- a/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs +++ b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.rs @@ -1,7 +1,7 @@ // edition:2021 // check-pass -#![feature(async_fn_in_trait, return_position_impl_trait_in_trait, return_type_notation)] +#![feature(return_type_notation)] //~^ WARN the feature `return_type_notation` is incomplete use std::future::Future; diff --git a/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.stderr b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.stderr index 8626648b523..4a52e807bff 100644 --- a/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.stderr +++ b/tests/ui/async-await/return-type-notation/rtn-implied-in-supertrait.stderr @@ -1,8 +1,8 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/rtn-implied-in-supertrait.rs:4:68 + --> $DIR/rtn-implied-in-supertrait.rs:4:12 | -LL | #![feature(async_fn_in_trait, return_position_impl_trait_in_trait, return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information = note: `#[warn(incomplete_features)]` on by default diff --git a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs index 028e526b5f5..891b30638ee 100644 --- a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs +++ b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.rs @@ -1,6 +1,6 @@ // edition:2021 -#![feature(async_fn_in_trait, return_type_notation)] +#![feature(return_type_notation)] //~^ WARN the feature `return_type_notation` is incomplete trait Super1<'a> { diff --git a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr index 5bc8dbde4bc..d9caab5875a 100644 --- a/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr +++ b/tests/ui/async-await/return-type-notation/super-method-bound-ambig.stderr @@ -1,8 +1,8 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/super-method-bound-ambig.rs:3:31 + --> $DIR/super-method-bound-ambig.rs:3:12 | -LL | #![feature(async_fn_in_trait, return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information = note: `#[warn(incomplete_features)]` on by default diff --git a/tests/ui/async-await/return-type-notation/super-method-bound.current.stderr b/tests/ui/async-await/return-type-notation/super-method-bound.current.stderr index 891c802c5f4..5f482b60878 100644 --- a/tests/ui/async-await/return-type-notation/super-method-bound.current.stderr +++ b/tests/ui/async-await/return-type-notation/super-method-bound.current.stderr @@ -1,8 +1,7 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/super-method-bound.rs:6:31 | -LL | #![feature(async_fn_in_trait, return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information = note: `#[warn(incomplete_features)]` on by default diff --git a/tests/ui/async-await/return-type-notation/super-method-bound.next.stderr b/tests/ui/async-await/return-type-notation/super-method-bound.next.stderr index 891c802c5f4..5f482b60878 100644 --- a/tests/ui/async-await/return-type-notation/super-method-bound.next.stderr +++ b/tests/ui/async-await/return-type-notation/super-method-bound.next.stderr @@ -1,8 +1,7 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/super-method-bound.rs:6:31 | -LL | #![feature(async_fn_in_trait, return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information = note: `#[warn(incomplete_features)]` on by default diff --git a/tests/ui/async-await/return-type-notation/super-method-bound.rs b/tests/ui/async-await/return-type-notation/super-method-bound.rs index 58ea3578db6..6025cda2f5d 100644 --- a/tests/ui/async-await/return-type-notation/super-method-bound.rs +++ b/tests/ui/async-await/return-type-notation/super-method-bound.rs @@ -1,7 +1,7 @@ // edition:2021 // check-pass -#![feature(async_fn_in_trait, return_type_notation)] +#![feature(return_type_notation)] //~^ WARN the feature `return_type_notation` is incomplete trait Super<'a> { diff --git a/tests/ui/async-await/return-type-notation/super-method-bound.stderr b/tests/ui/async-await/return-type-notation/super-method-bound.stderr index ac0668d3c44..64fda71c1a1 100644 --- a/tests/ui/async-await/return-type-notation/super-method-bound.stderr +++ b/tests/ui/async-await/return-type-notation/super-method-bound.stderr @@ -1,8 +1,8 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/super-method-bound.rs:4:31 + --> $DIR/super-method-bound.rs:4:12 | -LL | #![feature(async_fn_in_trait, return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information = note: `#[warn(incomplete_features)]` on by default diff --git a/tests/ui/async-await/return-type-notation/supertrait-bound.current.stderr b/tests/ui/async-await/return-type-notation/supertrait-bound.current.stderr index 05cb0ca4abd..928b321697c 100644 --- a/tests/ui/async-await/return-type-notation/supertrait-bound.current.stderr +++ b/tests/ui/async-await/return-type-notation/supertrait-bound.current.stderr @@ -1,7 +1,7 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/supertrait-bound.rs:5:49 | -LL | #![feature(return_position_impl_trait_in_trait, return_type_notation)] +LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information diff --git a/tests/ui/async-await/return-type-notation/supertrait-bound.next.stderr b/tests/ui/async-await/return-type-notation/supertrait-bound.next.stderr index 05cb0ca4abd..928b321697c 100644 --- a/tests/ui/async-await/return-type-notation/supertrait-bound.next.stderr +++ b/tests/ui/async-await/return-type-notation/supertrait-bound.next.stderr @@ -1,7 +1,7 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/supertrait-bound.rs:5:49 | -LL | #![feature(return_position_impl_trait_in_trait, return_type_notation)] +LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information diff --git a/tests/ui/async-await/return-type-notation/supertrait-bound.rs b/tests/ui/async-await/return-type-notation/supertrait-bound.rs index 19bcfe3046b..a85596a9fee 100644 --- a/tests/ui/async-await/return-type-notation/supertrait-bound.rs +++ b/tests/ui/async-await/return-type-notation/supertrait-bound.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(return_position_impl_trait_in_trait, return_type_notation)] +#![feature(return_type_notation)] //~^ WARN the feature `return_type_notation` is incomplete and may not be safe to use trait IntFactory { diff --git a/tests/ui/async-await/return-type-notation/supertrait-bound.stderr b/tests/ui/async-await/return-type-notation/supertrait-bound.stderr index c8cec4946b4..eb6917fc7d5 100644 --- a/tests/ui/async-await/return-type-notation/supertrait-bound.stderr +++ b/tests/ui/async-await/return-type-notation/supertrait-bound.stderr @@ -1,8 +1,8 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/supertrait-bound.rs:3:49 + --> $DIR/supertrait-bound.rs:3:12 | -LL | #![feature(return_position_impl_trait_in_trait, return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information = note: `#[warn(incomplete_features)]` on by default diff --git a/tests/ui/async-await/return-type-notation/ty-or-ct-params.current.stderr b/tests/ui/async-await/return-type-notation/ty-or-ct-params.current.stderr index 1aa008fe469..e2bbb6013fc 100644 --- a/tests/ui/async-await/return-type-notation/ty-or-ct-params.current.stderr +++ b/tests/ui/async-await/return-type-notation/ty-or-ct-params.current.stderr @@ -1,8 +1,7 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/ty-or-ct-params.rs:5:31 | -LL | #![feature(async_fn_in_trait, return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information = note: `#[warn(incomplete_features)]` on by default diff --git a/tests/ui/async-await/return-type-notation/ty-or-ct-params.next.stderr b/tests/ui/async-await/return-type-notation/ty-or-ct-params.next.stderr index 1aa008fe469..e2bbb6013fc 100644 --- a/tests/ui/async-await/return-type-notation/ty-or-ct-params.next.stderr +++ b/tests/ui/async-await/return-type-notation/ty-or-ct-params.next.stderr @@ -1,8 +1,7 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/ty-or-ct-params.rs:5:31 | -LL | #![feature(async_fn_in_trait, return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![feature(return_type_notation)] | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information = note: `#[warn(incomplete_features)]` on by default diff --git a/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs b/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs index 7871a2fed03..ac320cfc679 100644 --- a/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs +++ b/tests/ui/async-await/return-type-notation/ty-or-ct-params.rs @@ -1,6 +1,6 @@ // edition: 2021 -#![feature(async_fn_in_trait, return_type_notation)] +#![feature(return_type_notation)] //~^ WARN the feature `return_type_notation` is incomplete trait Foo { diff --git a/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr b/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr index 76928c5d7a3..da94d9d1e6d 100644 --- a/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr +++ b/tests/ui/async-await/return-type-notation/ty-or-ct-params.stderr @@ -1,8 +1,8 @@ warning: the feature `return_type_notation` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/ty-or-ct-params.rs:3:31 + --> $DIR/ty-or-ct-params.rs:3:12 | -LL | #![feature(async_fn_in_trait, return_type_notation)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![feature(return_type_notation)] + | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information = note: `#[warn(incomplete_features)]` on by default diff --git a/tests/ui/check-cfg/allow-at-crate-level.rs b/tests/ui/check-cfg/allow-at-crate-level.rs index ce3383a2961..1629d2e0b67 100644 --- a/tests/ui/check-cfg/allow-at-crate-level.rs +++ b/tests/ui/check-cfg/allow-at-crate-level.rs @@ -1,7 +1,7 @@ // This test check that #![allow(unexpected_cfgs)] works with --cfg // // check-pass -// compile-flags: --cfg=unexpected --check-cfg=names() -Z unstable-options +// compile-flags: --cfg=unexpected --check-cfg=cfg() -Z unstable-options #![allow(unexpected_cfgs)] diff --git a/tests/ui/check-cfg/allow-macro-cfg.rs b/tests/ui/check-cfg/allow-macro-cfg.rs index 8016a4d190c..ea26355aca8 100644 --- a/tests/ui/check-cfg/allow-macro-cfg.rs +++ b/tests/ui/check-cfg/allow-macro-cfg.rs @@ -1,7 +1,7 @@ // This test check that local #[allow(unexpected_cfgs)] works // // check-pass -// compile-flags:--check-cfg=names() -Z unstable-options +// compile-flags: --check-cfg=cfg() -Z unstable-options #[allow(unexpected_cfgs)] fn foo() { diff --git a/tests/ui/check-cfg/allow-same-level.rs b/tests/ui/check-cfg/allow-same-level.rs index 6c869dc4202..29491e0b39e 100644 --- a/tests/ui/check-cfg/allow-same-level.rs +++ b/tests/ui/check-cfg/allow-same-level.rs @@ -1,7 +1,7 @@ // This test check that #[allow(unexpected_cfgs)] doesn't work if put on the same level // // check-pass -// compile-flags:--check-cfg=names() -Z unstable-options +// compile-flags: --check-cfg=cfg() -Z unstable-options #[allow(unexpected_cfgs)] #[cfg(FALSE)] diff --git a/tests/ui/check-cfg/allow-same-level.stderr b/tests/ui/check-cfg/allow-same-level.stderr index 7797de584b9..b0c459fabf8 100644 --- a/tests/ui/check-cfg/allow-same-level.stderr +++ b/tests/ui/check-cfg/allow-same-level.stderr @@ -1,9 +1,10 @@ -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `FALSE` --> $DIR/allow-same-level.rs:7:7 | LL | #[cfg(FALSE)] | ^^^^^ | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` = note: `#[warn(unexpected_cfgs)]` on by default warning: 1 warning emitted diff --git a/tests/ui/check-cfg/allow-top-level.rs b/tests/ui/check-cfg/allow-top-level.rs index d14b0eae5cc..df06f655d9a 100644 --- a/tests/ui/check-cfg/allow-top-level.rs +++ b/tests/ui/check-cfg/allow-top-level.rs @@ -1,7 +1,7 @@ // This test check that a top-level #![allow(unexpected_cfgs)] works // // check-pass -// compile-flags:--check-cfg=names() -Z unstable-options +// compile-flags: --check-cfg=cfg() -Z unstable-options #![allow(unexpected_cfgs)] diff --git a/tests/ui/check-cfg/allow-upper-level.rs b/tests/ui/check-cfg/allow-upper-level.rs index 04340694d9c..bd5c97815f2 100644 --- a/tests/ui/check-cfg/allow-upper-level.rs +++ b/tests/ui/check-cfg/allow-upper-level.rs @@ -1,7 +1,7 @@ // This test check that #[allow(unexpected_cfgs)] work if put on an upper level // // check-pass -// compile-flags:--check-cfg=names() -Z unstable-options +// compile-flags: --check-cfg=cfg() -Z unstable-options #[allow(unexpected_cfgs)] mod aa { diff --git a/tests/ui/check-cfg/compact-names.rs b/tests/ui/check-cfg/compact-names.rs index bff80740039..4f7168255cf 100644 --- a/tests/ui/check-cfg/compact-names.rs +++ b/tests/ui/check-cfg/compact-names.rs @@ -1,7 +1,7 @@ // This test check that we correctly emit an warning for compact cfg // // check-pass -// compile-flags:--check-cfg=names() -Z unstable-options +// compile-flags: --check-cfg=cfg() -Z unstable-options #![feature(cfg_target_compact)] diff --git a/tests/ui/check-cfg/compact-names.stderr b/tests/ui/check-cfg/compact-names.stderr index f1fc4285a71..b0228774b75 100644 --- a/tests/ui/check-cfg/compact-names.stderr +++ b/tests/ui/check-cfg/compact-names.stderr @@ -1,9 +1,10 @@ -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `target_architecture` --> $DIR/compact-names.rs:11:28 | LL | #[cfg(target(os = "linux", architecture = "arm"))] | ^^^^^^^^^^^^^^^^^^^^ | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` = note: `#[warn(unexpected_cfgs)]` on by default warning: 1 warning emitted diff --git a/tests/ui/check-cfg/compact-values.rs b/tests/ui/check-cfg/compact-values.rs index 1f17057840c..13c072fe920 100644 --- a/tests/ui/check-cfg/compact-values.rs +++ b/tests/ui/check-cfg/compact-values.rs @@ -1,7 +1,7 @@ // This test check that we correctly emit an warning for compact cfg // // check-pass -// compile-flags:--check-cfg=values() -Z unstable-options +// compile-flags: --check-cfg=cfg() -Z unstable-options #![feature(cfg_target_compact)] diff --git a/tests/ui/check-cfg/compact-values.stderr b/tests/ui/check-cfg/compact-values.stderr index b7269a652ea..bb2f4915b5e 100644 --- a/tests/ui/check-cfg/compact-values.stderr +++ b/tests/ui/check-cfg/compact-values.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `X` --> $DIR/compact-values.rs:11:28 | LL | #[cfg(target(os = "linux", arch = "X"))] diff --git a/tests/ui/check-cfg/concat-values.rs b/tests/ui/check-cfg/concat-values.rs new file mode 100644 index 00000000000..0f9178ce6a5 --- /dev/null +++ b/tests/ui/check-cfg/concat-values.rs @@ -0,0 +1,13 @@ +// check-pass +// compile-flags: -Z unstable-options +// compile-flags: --check-cfg=cfg(my_cfg,values("foo")) --check-cfg=cfg(my_cfg,values("bar")) + +#[cfg(my_cfg)] +//~^ WARNING unexpected `cfg` condition value +fn my_cfg() {} + +#[cfg(my_cfg = "unk")] +//~^ WARNING unexpected `cfg` condition value +fn my_cfg() {} + +fn main() {} diff --git a/tests/ui/check-cfg/concat-values.stderr b/tests/ui/check-cfg/concat-values.stderr new file mode 100644 index 00000000000..da2bd7d6ad9 --- /dev/null +++ b/tests/ui/check-cfg/concat-values.stderr @@ -0,0 +1,19 @@ +warning: unexpected `cfg` condition value: (none) + --> $DIR/concat-values.rs:5:7 + | +LL | #[cfg(my_cfg)] + | ^^^^^^ + | + = note: expected values for `my_cfg` are: `bar`, `foo` + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition value: `unk` + --> $DIR/concat-values.rs:9:7 + | +LL | #[cfg(my_cfg = "unk")] + | ^^^^^^^^^^^^^^ + | + = note: expected values for `my_cfg` are: `bar`, `foo` + +warning: 2 warnings emitted + diff --git a/tests/ui/check-cfg/diagnotics.rs b/tests/ui/check-cfg/diagnotics.rs index 49e127d079a..45875bddc17 100644 --- a/tests/ui/check-cfg/diagnotics.rs +++ b/tests/ui/check-cfg/diagnotics.rs @@ -1,5 +1,5 @@ // check-pass -// compile-flags: --check-cfg=names() --check-cfg=values(feature,"foo") --check-cfg=values(no_values) -Z unstable-options +// compile-flags: --check-cfg=cfg(feature,values("foo")) --check-cfg=cfg(no_values) -Z unstable-options #[cfg(featur)] //~^ WARNING unexpected `cfg` condition name diff --git a/tests/ui/check-cfg/diagnotics.stderr b/tests/ui/check-cfg/diagnotics.stderr index 8b9fef09d09..31c0db03a7e 100644 --- a/tests/ui/check-cfg/diagnotics.stderr +++ b/tests/ui/check-cfg/diagnotics.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `featur` --> $DIR/diagnotics.rs:4:7 | LL | #[cfg(featur)] @@ -7,19 +7,18 @@ LL | #[cfg(featur)] = help: expected values for `feature` are: `foo` = note: `#[warn(unexpected_cfgs)]` on by default -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `featur` --> $DIR/diagnotics.rs:8:7 | LL | #[cfg(featur = "foo")] | ^^^^^^^^^^^^^^ | - = help: expected values for `feature` are: `foo` help: there is a config with a similar name and value | LL | #[cfg(feature = "foo")] | ~~~~~~~ -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `featur` --> $DIR/diagnotics.rs:12:7 | LL | #[cfg(featur = "fo")] @@ -31,13 +30,13 @@ help: there is a config with a similar name and different values LL | #[cfg(feature = "foo")] | ~~~~~~~~~~~~~~~ -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `no_value` --> $DIR/diagnotics.rs:19:7 | LL | #[cfg(no_value)] | ^^^^^^^^ help: there is a config with a similar name: `no_values` -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `no_value` --> $DIR/diagnotics.rs:23:7 | LL | #[cfg(no_value = "foo")] @@ -48,7 +47,7 @@ help: there is a config with a similar name and no value LL | #[cfg(no_values)] | ~~~~~~~~~ -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `bar` --> $DIR/diagnotics.rs:27:7 | LL | #[cfg(no_values = "bar")] diff --git a/tests/ui/check-cfg/empty-names.rs b/tests/ui/check-cfg/empty-names.rs deleted file mode 100644 index 046ff0364e2..00000000000 --- a/tests/ui/check-cfg/empty-names.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Check warning for unexpected cfg -// -// check-pass -// compile-flags: --check-cfg=names() -Z unstable-options - -#[cfg(unknown_key = "value")] -//~^ WARNING unexpected `cfg` condition name -pub fn f() {} - -fn main() {} diff --git a/tests/ui/check-cfg/empty-names.stderr b/tests/ui/check-cfg/empty-names.stderr deleted file mode 100644 index f926d1133cc..00000000000 --- a/tests/ui/check-cfg/empty-names.stderr +++ /dev/null @@ -1,10 +0,0 @@ -warning: unexpected `cfg` condition name - --> $DIR/empty-names.rs:6:7 - | -LL | #[cfg(unknown_key = "value")] - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(unexpected_cfgs)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/check-cfg/empty-values.rs b/tests/ui/check-cfg/empty-values.rs deleted file mode 100644 index 9bda42e5d15..00000000000 --- a/tests/ui/check-cfg/empty-values.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Check warning for unexpected cfg value -// -// check-pass -// compile-flags: --check-cfg=values() -Z unstable-options - -#[cfg(test = "value")] -//~^ WARNING unexpected `cfg` condition value -pub fn f() {} - -fn main() {} diff --git a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr new file mode 100644 index 00000000000..53ccc0f4d31 --- /dev/null +++ b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr @@ -0,0 +1,25 @@ +warning: unexpected `cfg` condition name: `unknown_key` + --> $DIR/exhaustive-names-values.rs:12:7 + | +LL | #[cfg(unknown_key = "value")] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition value: `value` + --> $DIR/exhaustive-names-values.rs:16:7 + | +LL | #[cfg(test = "value")] + | ^^^^---------- + | | + | help: remove the value + | + = note: no expected value for `test` + +warning: unexpected `empty_cfg` as condition name + | + = help: was set with `--cfg` but isn't in the `--check-cfg` expected names + +warning: 3 warnings emitted + diff --git a/tests/ui/check-cfg/exhaustive-names-values.empty_names_values.stderr b/tests/ui/check-cfg/exhaustive-names-values.empty_names_values.stderr new file mode 100644 index 00000000000..5e8b74054ce --- /dev/null +++ b/tests/ui/check-cfg/exhaustive-names-values.empty_names_values.stderr @@ -0,0 +1,25 @@ +warning: unexpected `cfg` condition name: `unknown_key` + --> $DIR/exhaustive-names-values.rs:12:7 + | +LL | #[cfg(unknown_key = "value")] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition value: `value` + --> $DIR/exhaustive-names-values.rs:16:7 + | +LL | #[cfg(test = "value")] + | ^^^^---------- + | | + | help: remove the value + | + = note: no expected value for `test` + +warning: unexpected `empty_names_values` as condition name + | + = help: was set with `--cfg` but isn't in the `--check-cfg` expected names + +warning: 3 warnings emitted + diff --git a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr new file mode 100644 index 00000000000..7705a665eb7 --- /dev/null +++ b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr @@ -0,0 +1,33 @@ +warning: unexpected `cfg` condition name: `unknown_key` + --> $DIR/exhaustive-names-values.rs:12:7 + | +LL | #[cfg(unknown_key = "value")] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition value: `value` + --> $DIR/exhaustive-names-values.rs:16:7 + | +LL | #[cfg(test = "value")] + | ^^^^---------- + | | + | help: remove the value + | + = note: no expected value for `test` + +warning: unexpected `cfg` condition value: `unk` + --> $DIR/exhaustive-names-values.rs:20:7 + | +LL | #[cfg(feature = "unk")] + | ^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `std` + +warning: unexpected condition value `` for condition name `feature` + | + = help: was set with `--cfg` but isn't in the `--check-cfg` expected values + +warning: 4 warnings emitted + diff --git a/tests/ui/check-cfg/exhaustive-names-values.full.stderr b/tests/ui/check-cfg/exhaustive-names-values.full.stderr new file mode 100644 index 00000000000..f0224a2e33c --- /dev/null +++ b/tests/ui/check-cfg/exhaustive-names-values.full.stderr @@ -0,0 +1,33 @@ +warning: unexpected `cfg` condition name: `unknown_key` + --> $DIR/exhaustive-names-values.rs:12:7 + | +LL | #[cfg(unknown_key = "value")] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition value: `value` + --> $DIR/exhaustive-names-values.rs:16:7 + | +LL | #[cfg(test = "value")] + | ^^^^---------- + | | + | help: remove the value + | + = note: no expected value for `test` + +warning: unexpected `cfg` condition value: `unk` + --> $DIR/exhaustive-names-values.rs:20:7 + | +LL | #[cfg(feature = "unk")] + | ^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `std` + +warning: unexpected `full` as condition name + | + = help: was set with `--cfg` but isn't in the `--check-cfg` expected names + +warning: 4 warnings emitted + diff --git a/tests/ui/check-cfg/exhaustive-names-values.rs b/tests/ui/check-cfg/exhaustive-names-values.rs new file mode 100644 index 00000000000..f553d93cae2 --- /dev/null +++ b/tests/ui/check-cfg/exhaustive-names-values.rs @@ -0,0 +1,34 @@ +// Check warning for unexpected cfg in the code and in the CLI +// arguments (here the revision cfg). +// +// check-pass +// revisions: empty_names_values empty_cfg feature full +// compile-flags: -Z unstable-options +// [empty_names_values]compile-flags: --check-cfg=names() --check-cfg=values() +// [empty_cfg]compile-flags: --check-cfg=cfg() +// [feature]compile-flags: --check-cfg=cfg(feature,values("std")) +// [full]compile-flags: --check-cfg=cfg(feature,values("std")) --check-cfg=cfg() + +#[cfg(unknown_key = "value")] +//~^ WARNING unexpected `cfg` condition name +pub fn f() {} + +#[cfg(test = "value")] +//~^ WARNING unexpected `cfg` condition value +pub fn f() {} + +#[cfg(feature = "unk")] +//[feature]~^ WARNING unexpected `cfg` condition value +//[full]~^^ WARNING unexpected `cfg` condition value +pub fn feat() {} + +#[cfg(feature = "std")] +pub fn feat() {} + +#[cfg(windows)] +pub fn win() {} + +#[cfg(unix)] +pub fn unix() {} + +fn main() {} diff --git a/tests/ui/check-cfg/exhaustive-names.empty_names.stderr b/tests/ui/check-cfg/exhaustive-names.empty_names.stderr new file mode 100644 index 00000000000..6190ff71464 --- /dev/null +++ b/tests/ui/check-cfg/exhaustive-names.empty_names.stderr @@ -0,0 +1,15 @@ +warning: unexpected `cfg` condition name: `unknown_key` + --> $DIR/exhaustive-names.rs:8:7 + | +LL | #[cfg(unknown_key = "value")] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `empty_names` as condition name + | + = help: was set with `--cfg` but isn't in the `--check-cfg` expected names + +warning: 2 warnings emitted + diff --git a/tests/ui/check-cfg/exhaustive-names.exhaustive_names.stderr b/tests/ui/check-cfg/exhaustive-names.exhaustive_names.stderr new file mode 100644 index 00000000000..f338434cd29 --- /dev/null +++ b/tests/ui/check-cfg/exhaustive-names.exhaustive_names.stderr @@ -0,0 +1,15 @@ +warning: unexpected `cfg` condition name: `unknown_key` + --> $DIR/exhaustive-names.rs:8:7 + | +LL | #[cfg(unknown_key = "value")] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `exhaustive_names` as condition name + | + = help: was set with `--cfg` but isn't in the `--check-cfg` expected names + +warning: 2 warnings emitted + diff --git a/tests/ui/check-cfg/exhaustive-names.rs b/tests/ui/check-cfg/exhaustive-names.rs new file mode 100644 index 00000000000..b86a7f84eb4 --- /dev/null +++ b/tests/ui/check-cfg/exhaustive-names.rs @@ -0,0 +1,12 @@ +// Check warning for unexpected cfg +// +// check-pass +// revisions: empty_names exhaustive_names +// [empty_names]compile-flags: --check-cfg=names() -Z unstable-options +// [exhaustive_names]compile-flags: --check-cfg=cfg() -Z unstable-options + +#[cfg(unknown_key = "value")] +//~^ WARNING unexpected `cfg` condition name +pub fn f() {} + +fn main() {} diff --git a/tests/ui/check-cfg/exhaustive-values.empty_cfg.stderr b/tests/ui/check-cfg/exhaustive-values.empty_cfg.stderr new file mode 100644 index 00000000000..999b2702849 --- /dev/null +++ b/tests/ui/check-cfg/exhaustive-values.empty_cfg.stderr @@ -0,0 +1,17 @@ +warning: unexpected `cfg` condition value: `value` + --> $DIR/exhaustive-values.rs:9:7 + | +LL | #[cfg(test = "value")] + | ^^^^---------- + | | + | help: remove the value + | + = note: no expected value for `test` + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `empty_cfg` as condition name + | + = help: was set with `--cfg` but isn't in the `--check-cfg` expected names + +warning: 2 warnings emitted + diff --git a/tests/ui/check-cfg/empty-values.stderr b/tests/ui/check-cfg/exhaustive-values.empty_values.stderr index a0168b2caa8..77ddc35100a 100644 --- a/tests/ui/check-cfg/empty-values.stderr +++ b/tests/ui/check-cfg/exhaustive-values.empty_values.stderr @@ -1,5 +1,5 @@ -warning: unexpected `cfg` condition value - --> $DIR/empty-values.rs:6:7 +warning: unexpected `cfg` condition value: `value` + --> $DIR/exhaustive-values.rs:9:7 | LL | #[cfg(test = "value")] | ^^^^---------- diff --git a/tests/ui/check-cfg/exhaustive-values.rs b/tests/ui/check-cfg/exhaustive-values.rs new file mode 100644 index 00000000000..8a1689ba86b --- /dev/null +++ b/tests/ui/check-cfg/exhaustive-values.rs @@ -0,0 +1,13 @@ +// Check warning for unexpected cfg value +// +// check-pass +// revisions: empty_values empty_cfg without_names +// [empty_values]compile-flags: --check-cfg=values() -Z unstable-options +// [empty_cfg]compile-flags: --check-cfg=cfg() -Z unstable-options +// [without_names]compile-flags: --check-cfg=cfg(any()) -Z unstable-options + +#[cfg(test = "value")] +//~^ WARNING unexpected `cfg` condition value +pub fn f() {} + +fn main() {} diff --git a/tests/ui/check-cfg/exhaustive-values.without_names.stderr b/tests/ui/check-cfg/exhaustive-values.without_names.stderr new file mode 100644 index 00000000000..77ddc35100a --- /dev/null +++ b/tests/ui/check-cfg/exhaustive-values.without_names.stderr @@ -0,0 +1,13 @@ +warning: unexpected `cfg` condition value: `value` + --> $DIR/exhaustive-values.rs:9:7 + | +LL | #[cfg(test = "value")] + | ^^^^---------- + | | + | help: remove the value + | + = note: no expected value for `test` + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/check-cfg/invalid-arguments.anything_else.stderr b/tests/ui/check-cfg/invalid-arguments.anything_else.stderr index 850924d993a..925664bb3fc 100644 --- a/tests/ui/check-cfg/invalid-arguments.anything_else.stderr +++ b/tests/ui/check-cfg/invalid-arguments.anything_else.stderr @@ -1,2 +1,2 @@ -error: invalid `--check-cfg` argument: `anything_else(...)` (expected `names(name1, name2, ... nameN)` or `values(name, "value1", "value2", ... "valueN")`) +error: invalid `--check-cfg` argument: `anything_else(...)` (expected `cfg(name, values("value1", "value2", ... "valueN"))`) diff --git a/tests/ui/check-cfg/invalid-arguments.giberich.stderr b/tests/ui/check-cfg/invalid-arguments.giberich.stderr new file mode 100644 index 00000000000..d427033fcc2 --- /dev/null +++ b/tests/ui/check-cfg/invalid-arguments.giberich.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `cfg(...)` (expected `cfg(name, values("value1", "value2", ... "valueN"))`) + diff --git a/tests/ui/check-cfg/invalid-arguments.ident_in_values_1.stderr b/tests/ui/check-cfg/invalid-arguments.ident_in_values_1.stderr new file mode 100644 index 00000000000..0dc44d9ac76 --- /dev/null +++ b/tests/ui/check-cfg/invalid-arguments.ident_in_values_1.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `cfg(foo,values(bar))` (`values()` arguments must be string literals or `any()`) + diff --git a/tests/ui/check-cfg/invalid-arguments.ident_in_values_2.stderr b/tests/ui/check-cfg/invalid-arguments.ident_in_values_2.stderr new file mode 100644 index 00000000000..d0a1453e3c4 --- /dev/null +++ b/tests/ui/check-cfg/invalid-arguments.ident_in_values_2.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `cfg(foo,values("bar",bar,"bar"))` (`values()` arguments must be string literals or `any()`) + diff --git a/tests/ui/check-cfg/invalid-arguments.mixed_any.stderr b/tests/ui/check-cfg/invalid-arguments.mixed_any.stderr new file mode 100644 index 00000000000..9239f8cce94 --- /dev/null +++ b/tests/ui/check-cfg/invalid-arguments.mixed_any.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `cfg(any(),values(any()))` (`values()` cannot be specified before the names) + diff --git a/tests/ui/check-cfg/invalid-arguments.mixed_values_any.stderr b/tests/ui/check-cfg/invalid-arguments.mixed_values_any.stderr new file mode 100644 index 00000000000..4c406143d08 --- /dev/null +++ b/tests/ui/check-cfg/invalid-arguments.mixed_values_any.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `cfg(foo,values("bar",any()))` (`values()` arguments cannot specify string literals and `any()` at the same time) + diff --git a/tests/ui/check-cfg/invalid-arguments.multiple_any.stderr b/tests/ui/check-cfg/invalid-arguments.multiple_any.stderr new file mode 100644 index 00000000000..6f1db1b13c3 --- /dev/null +++ b/tests/ui/check-cfg/invalid-arguments.multiple_any.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `cfg(any(),any())` (`any()` cannot be specified multiple times) + diff --git a/tests/ui/check-cfg/invalid-arguments.multiple_values.stderr b/tests/ui/check-cfg/invalid-arguments.multiple_values.stderr new file mode 100644 index 00000000000..bce305b09c3 --- /dev/null +++ b/tests/ui/check-cfg/invalid-arguments.multiple_values.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `cfg(foo,values(),values())` (`values()` cannot be specified multiple times) + diff --git a/tests/ui/check-cfg/invalid-arguments.multiple_values_any.stderr b/tests/ui/check-cfg/invalid-arguments.multiple_values_any.stderr new file mode 100644 index 00000000000..748ce231af7 --- /dev/null +++ b/tests/ui/check-cfg/invalid-arguments.multiple_values_any.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `cfg(foo,values(any(),any()))` (`any()` in `values()` cannot be specified multiple times) + diff --git a/tests/ui/check-cfg/invalid-arguments.not_empty_any.stderr b/tests/ui/check-cfg/invalid-arguments.not_empty_any.stderr new file mode 100644 index 00000000000..daf38147fe5 --- /dev/null +++ b/tests/ui/check-cfg/invalid-arguments.not_empty_any.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `cfg(any(foo))` (`any()` must be empty) + diff --git a/tests/ui/check-cfg/invalid-arguments.not_empty_values_any.stderr b/tests/ui/check-cfg/invalid-arguments.not_empty_values_any.stderr new file mode 100644 index 00000000000..79f83e802ca --- /dev/null +++ b/tests/ui/check-cfg/invalid-arguments.not_empty_values_any.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `cfg(foo,values(any(bar)))` (`any()` must be empty) + diff --git a/tests/ui/check-cfg/invalid-arguments.rs b/tests/ui/check-cfg/invalid-arguments.rs index 5090ce3e845..79bef89c957 100644 --- a/tests/ui/check-cfg/invalid-arguments.rs +++ b/tests/ui/check-cfg/invalid-arguments.rs @@ -2,9 +2,33 @@ // // check-fail // revisions: anything_else names_simple_ident values_simple_ident values_string_literals -// [anything_else]compile-flags: -Z unstable-options --check-cfg=anything_else(...) -// [names_simple_ident]compile-flags: -Z unstable-options --check-cfg=names("NOT_IDENT") -// [values_simple_ident]compile-flags: -Z unstable-options --check-cfg=values("NOT_IDENT") -// [values_string_literals]compile-flags: -Z unstable-options --check-cfg=values(test,12) +// revisions: string_for_name_1 string_for_name_2 multiple_any multiple_values +// revisions: multiple_values_any not_empty_any not_empty_values_any +// revisions: values_any_missing_values values_any_before_ident ident_in_values_1 +// revisions: ident_in_values_2 unknown_meta_item_1 unknown_meta_item_2 unknown_meta_item_3 +// revisions: mixed_values_any mixed_any giberich +// +// compile-flags: -Z unstable-options +// [anything_else]compile-flags: --check-cfg=anything_else(...) +// [names_simple_ident]compile-flags: --check-cfg=names("NOT_IDENT") +// [values_simple_ident]compile-flags: --check-cfg=values("NOT_IDENT") +// [values_string_literals]compile-flags: --check-cfg=values(test,12) +// [string_for_name_1]compile-flags: --check-cfg=cfg("NOT_IDENT") +// [string_for_name_2]compile-flags: --check-cfg=cfg(foo,"NOT_IDENT",bar) +// [multiple_any]compile-flags: --check-cfg=cfg(any(),any()) +// [multiple_values]compile-flags: --check-cfg=cfg(foo,values(),values()) +// [multiple_values_any]compile-flags: --check-cfg=cfg(foo,values(any(),any())) +// [not_empty_any]compile-flags: --check-cfg=cfg(any(foo)) +// [not_empty_values_any]compile-flags: --check-cfg=cfg(foo,values(any(bar))) +// [values_any_missing_values]compile-flags: --check-cfg=cfg(foo,any()) +// [values_any_before_ident]compile-flags: --check-cfg=cfg(values(any()),foo) +// [ident_in_values_1]compile-flags: --check-cfg=cfg(foo,values(bar)) +// [ident_in_values_2]compile-flags: --check-cfg=cfg(foo,values("bar",bar,"bar")) +// [unknown_meta_item_1]compile-flags: --check-cfg=abc() +// [unknown_meta_item_2]compile-flags: --check-cfg=cfg(foo,test()) +// [unknown_meta_item_3]compile-flags: --check-cfg=cfg(foo,values(test())) +// [mixed_values_any]compile-flags: --check-cfg=cfg(foo,values("bar",any())) +// [mixed_any]compile-flags: --check-cfg=cfg(any(),values(any())) +// [giberich]compile-flags: --check-cfg=cfg(...) fn main() {} diff --git a/tests/ui/check-cfg/invalid-arguments.string_for_name_1.stderr b/tests/ui/check-cfg/invalid-arguments.string_for_name_1.stderr new file mode 100644 index 00000000000..c6f6834ffd3 --- /dev/null +++ b/tests/ui/check-cfg/invalid-arguments.string_for_name_1.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `cfg("NOT_IDENT")` (`cfg()` arguments must be simple identifiers, `any()` or `values(...)`) + diff --git a/tests/ui/check-cfg/invalid-arguments.string_for_name_2.stderr b/tests/ui/check-cfg/invalid-arguments.string_for_name_2.stderr new file mode 100644 index 00000000000..ab3dc86cd1a --- /dev/null +++ b/tests/ui/check-cfg/invalid-arguments.string_for_name_2.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `cfg(foo,"NOT_IDENT",bar)` (`cfg()` arguments must be simple identifiers, `any()` or `values(...)`) + diff --git a/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_1.stderr b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_1.stderr new file mode 100644 index 00000000000..c04b15ec265 --- /dev/null +++ b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_1.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `abc()` (expected `cfg(name, values("value1", "value2", ... "valueN"))`) + diff --git a/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_2.stderr b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_2.stderr new file mode 100644 index 00000000000..cee65f9887b --- /dev/null +++ b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_2.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `cfg(foo,test())` (`cfg()` arguments must be simple identifiers, `any()` or `values(...)`) + diff --git a/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_3.stderr b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_3.stderr new file mode 100644 index 00000000000..2441e2537b7 --- /dev/null +++ b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_3.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `cfg(foo,values(test()))` (`values()` arguments must be string literals or `any()`) + diff --git a/tests/ui/check-cfg/invalid-arguments.values_any_before_ident.stderr b/tests/ui/check-cfg/invalid-arguments.values_any_before_ident.stderr new file mode 100644 index 00000000000..fc93ec8fbdf --- /dev/null +++ b/tests/ui/check-cfg/invalid-arguments.values_any_before_ident.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `cfg(values(any()),foo)` (`values()` cannot be specified before the names) + diff --git a/tests/ui/check-cfg/invalid-arguments.values_any_missing_values.stderr b/tests/ui/check-cfg/invalid-arguments.values_any_missing_values.stderr new file mode 100644 index 00000000000..f41672fcbdb --- /dev/null +++ b/tests/ui/check-cfg/invalid-arguments.values_any_missing_values.stderr @@ -0,0 +1,2 @@ +error: invalid `--check-cfg` argument: `cfg(foo,any())` (`cfg(any())` can only be provided in isolation) + diff --git a/tests/ui/check-cfg/invalid-cfg-name.rs b/tests/ui/check-cfg/invalid-cfg-name.rs deleted file mode 100644 index 8499d3d4448..00000000000 --- a/tests/ui/check-cfg/invalid-cfg-name.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Check warning for invalid configuration name -// -// edition:2018 -// check-pass -// compile-flags: --check-cfg=names() -Z unstable-options - -#[cfg(widnows)] -//~^ WARNING unexpected `cfg` condition name -pub fn f() {} - -#[cfg(windows)] -pub fn g() {} - -pub fn main() {} diff --git a/tests/ui/check-cfg/invalid-cfg-value.rs b/tests/ui/check-cfg/invalid-cfg-value.rs deleted file mode 100644 index 9e428d367fd..00000000000 --- a/tests/ui/check-cfg/invalid-cfg-value.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Check warning for invalid configuration value -// -// edition:2018 -// check-pass -// compile-flags: --check-cfg=values(feature,"serde","full") --cfg=feature="rand" -Z unstable-options - -#[cfg(feature = "sedre")] -//~^ WARNING unexpected `cfg` condition value -pub fn f() {} - -#[cfg(feature = "serde")] -pub fn g() {} - -#[cfg(feature = "rand")] -//~^ WARNING unexpected `cfg` condition value -pub fn h() {} - -pub fn main() {} diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.cfg.stderr index 07c514aed52..daa200440cc 100644 --- a/tests/ui/check-cfg/mix.stderr +++ b/tests/ui/check-cfg/mix.cfg.stderr @@ -1,40 +1,42 @@ -warning: unexpected `cfg` condition name - --> $DIR/mix.rs:11:7 +warning: unexpected `cfg` condition name: `widnows` + --> $DIR/mix.rs:15:7 | LL | #[cfg(widnows)] | ^^^^^^^ help: there is a config with a similar name: `windows` | = note: `#[warn(unexpected_cfgs)]` on by default -warning: unexpected `cfg` condition value - --> $DIR/mix.rs:15:7 +warning: unexpected `cfg` condition value: (none) + --> $DIR/mix.rs:19:7 | LL | #[cfg(feature)] | ^^^^^^^- help: specify a config value: `= "foo"` | = note: expected values for `feature` are: `foo` -warning: unexpected `cfg` condition value - --> $DIR/mix.rs:22:7 +warning: unexpected `cfg` condition value: `bar` + --> $DIR/mix.rs:26:7 | LL | #[cfg(feature = "bar")] | ^^^^^^^^^^^^^^^ | = note: expected values for `feature` are: `foo` -warning: unexpected `cfg` condition value - --> $DIR/mix.rs:26:7 +warning: unexpected `cfg` condition value: `zebra` + --> $DIR/mix.rs:30:7 | LL | #[cfg(feature = "zebra")] | ^^^^^^^^^^^^^^^^^ | = note: expected values for `feature` are: `foo` -warning: unexpected `cfg` condition name - --> $DIR/mix.rs:30:12 +warning: unexpected `cfg` condition name: `uu` + --> $DIR/mix.rs:34:12 | LL | #[cfg_attr(uu, test)] | ^^ + | + = help: expected names are: `cfg`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `names_values`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected condition value `bar` for condition name `feature` | @@ -44,142 +46,142 @@ warning: unexpected `unknown_name` as condition name | = help: was set with `--cfg` but isn't in the `--check-cfg` expected names -warning: unexpected `cfg` condition name - --> $DIR/mix.rs:39:10 +warning: unexpected `cfg` condition name: `widnows` + --> $DIR/mix.rs:43:10 | LL | cfg!(widnows); | ^^^^^^^ help: there is a config with a similar name: `windows` -warning: unexpected `cfg` condition value - --> $DIR/mix.rs:42:10 +warning: unexpected `cfg` condition value: `bar` + --> $DIR/mix.rs:46:10 | LL | cfg!(feature = "bar"); | ^^^^^^^^^^^^^^^ | = note: expected values for `feature` are: `foo` -warning: unexpected `cfg` condition value - --> $DIR/mix.rs:44:10 +warning: unexpected `cfg` condition value: `zebra` + --> $DIR/mix.rs:48:10 | LL | cfg!(feature = "zebra"); | ^^^^^^^^^^^^^^^^^ | = note: expected values for `feature` are: `foo` -warning: unexpected `cfg` condition name - --> $DIR/mix.rs:46:10 +warning: unexpected `cfg` condition name: `xxx` + --> $DIR/mix.rs:50:10 | LL | cfg!(xxx = "foo"); | ^^^^^^^^^^^ -warning: unexpected `cfg` condition name - --> $DIR/mix.rs:48:10 +warning: unexpected `cfg` condition name: `xxx` + --> $DIR/mix.rs:52:10 | LL | cfg!(xxx); | ^^^ -warning: unexpected `cfg` condition name - --> $DIR/mix.rs:50:14 +warning: unexpected `cfg` condition name: `xxx` + --> $DIR/mix.rs:54:14 | LL | cfg!(any(xxx, windows)); | ^^^ -warning: unexpected `cfg` condition value - --> $DIR/mix.rs:52:14 +warning: unexpected `cfg` condition value: `bad` + --> $DIR/mix.rs:56:14 | LL | cfg!(any(feature = "bad", windows)); | ^^^^^^^^^^^^^^^ | = note: expected values for `feature` are: `foo` -warning: unexpected `cfg` condition name - --> $DIR/mix.rs:54:23 +warning: unexpected `cfg` condition name: `xxx` + --> $DIR/mix.rs:58:23 | LL | cfg!(any(windows, xxx)); | ^^^ -warning: unexpected `cfg` condition name - --> $DIR/mix.rs:56:20 +warning: unexpected `cfg` condition name: `xxx` + --> $DIR/mix.rs:60:20 | LL | cfg!(all(unix, xxx)); | ^^^ -warning: unexpected `cfg` condition name - --> $DIR/mix.rs:58:14 +warning: unexpected `cfg` condition name: `aa` + --> $DIR/mix.rs:62:14 | LL | cfg!(all(aa, bb)); | ^^ -warning: unexpected `cfg` condition name - --> $DIR/mix.rs:58:18 +warning: unexpected `cfg` condition name: `bb` + --> $DIR/mix.rs:62:18 | LL | cfg!(all(aa, bb)); | ^^ -warning: unexpected `cfg` condition name - --> $DIR/mix.rs:61:14 +warning: unexpected `cfg` condition name: `aa` + --> $DIR/mix.rs:65:14 | LL | cfg!(any(aa, bb)); | ^^ -warning: unexpected `cfg` condition name - --> $DIR/mix.rs:61:18 +warning: unexpected `cfg` condition name: `bb` + --> $DIR/mix.rs:65:18 | LL | cfg!(any(aa, bb)); | ^^ -warning: unexpected `cfg` condition value - --> $DIR/mix.rs:64:20 +warning: unexpected `cfg` condition value: `zebra` + --> $DIR/mix.rs:68:20 | LL | cfg!(any(unix, feature = "zebra")); | ^^^^^^^^^^^^^^^^^ | = note: expected values for `feature` are: `foo` -warning: unexpected `cfg` condition name - --> $DIR/mix.rs:66:14 +warning: unexpected `cfg` condition name: `xxx` + --> $DIR/mix.rs:70:14 | LL | cfg!(any(xxx, feature = "zebra")); | ^^^ -warning: unexpected `cfg` condition value - --> $DIR/mix.rs:66:19 +warning: unexpected `cfg` condition value: `zebra` + --> $DIR/mix.rs:70:19 | LL | cfg!(any(xxx, feature = "zebra")); | ^^^^^^^^^^^^^^^^^ | = note: expected values for `feature` are: `foo` -warning: unexpected `cfg` condition name - --> $DIR/mix.rs:69:14 +warning: unexpected `cfg` condition name: `xxx` + --> $DIR/mix.rs:73:14 | LL | cfg!(any(xxx, unix, xxx)); | ^^^ -warning: unexpected `cfg` condition name - --> $DIR/mix.rs:69:25 +warning: unexpected `cfg` condition name: `xxx` + --> $DIR/mix.rs:73:25 | LL | cfg!(any(xxx, unix, xxx)); | ^^^ -warning: unexpected `cfg` condition value - --> $DIR/mix.rs:72:14 +warning: unexpected `cfg` condition value: `zebra` + --> $DIR/mix.rs:76:14 | LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra")); | ^^^^^^^^^^^^^^^^^ | = note: expected values for `feature` are: `foo` -warning: unexpected `cfg` condition value - --> $DIR/mix.rs:72:33 +warning: unexpected `cfg` condition value: `zebra` + --> $DIR/mix.rs:76:33 | LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra")); | ^^^^^^^^^^^^^^^^^ | = note: expected values for `feature` are: `foo` -warning: unexpected `cfg` condition value - --> $DIR/mix.rs:72:52 +warning: unexpected `cfg` condition value: `zebra` + --> $DIR/mix.rs:76:52 | LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra")); | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/check-cfg/mix.names_values.stderr b/tests/ui/check-cfg/mix.names_values.stderr new file mode 100644 index 00000000000..daa200440cc --- /dev/null +++ b/tests/ui/check-cfg/mix.names_values.stderr @@ -0,0 +1,192 @@ +warning: unexpected `cfg` condition name: `widnows` + --> $DIR/mix.rs:15:7 + | +LL | #[cfg(widnows)] + | ^^^^^^^ help: there is a config with a similar name: `windows` + | + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition value: (none) + --> $DIR/mix.rs:19:7 + | +LL | #[cfg(feature)] + | ^^^^^^^- help: specify a config value: `= "foo"` + | + = note: expected values for `feature` are: `foo` + +warning: unexpected `cfg` condition value: `bar` + --> $DIR/mix.rs:26:7 + | +LL | #[cfg(feature = "bar")] + | ^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `foo` + +warning: unexpected `cfg` condition value: `zebra` + --> $DIR/mix.rs:30:7 + | +LL | #[cfg(feature = "zebra")] + | ^^^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `foo` + +warning: unexpected `cfg` condition name: `uu` + --> $DIR/mix.rs:34:12 + | +LL | #[cfg_attr(uu, test)] + | ^^ + | + = help: expected names are: `cfg`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `names_values`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + +warning: unexpected condition value `bar` for condition name `feature` + | + = help: was set with `--cfg` but isn't in the `--check-cfg` expected values + +warning: unexpected `unknown_name` as condition name + | + = help: was set with `--cfg` but isn't in the `--check-cfg` expected names + +warning: unexpected `cfg` condition name: `widnows` + --> $DIR/mix.rs:43:10 + | +LL | cfg!(widnows); + | ^^^^^^^ help: there is a config with a similar name: `windows` + +warning: unexpected `cfg` condition value: `bar` + --> $DIR/mix.rs:46:10 + | +LL | cfg!(feature = "bar"); + | ^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `foo` + +warning: unexpected `cfg` condition value: `zebra` + --> $DIR/mix.rs:48:10 + | +LL | cfg!(feature = "zebra"); + | ^^^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `foo` + +warning: unexpected `cfg` condition name: `xxx` + --> $DIR/mix.rs:50:10 + | +LL | cfg!(xxx = "foo"); + | ^^^^^^^^^^^ + +warning: unexpected `cfg` condition name: `xxx` + --> $DIR/mix.rs:52:10 + | +LL | cfg!(xxx); + | ^^^ + +warning: unexpected `cfg` condition name: `xxx` + --> $DIR/mix.rs:54:14 + | +LL | cfg!(any(xxx, windows)); + | ^^^ + +warning: unexpected `cfg` condition value: `bad` + --> $DIR/mix.rs:56:14 + | +LL | cfg!(any(feature = "bad", windows)); + | ^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `foo` + +warning: unexpected `cfg` condition name: `xxx` + --> $DIR/mix.rs:58:23 + | +LL | cfg!(any(windows, xxx)); + | ^^^ + +warning: unexpected `cfg` condition name: `xxx` + --> $DIR/mix.rs:60:20 + | +LL | cfg!(all(unix, xxx)); + | ^^^ + +warning: unexpected `cfg` condition name: `aa` + --> $DIR/mix.rs:62:14 + | +LL | cfg!(all(aa, bb)); + | ^^ + +warning: unexpected `cfg` condition name: `bb` + --> $DIR/mix.rs:62:18 + | +LL | cfg!(all(aa, bb)); + | ^^ + +warning: unexpected `cfg` condition name: `aa` + --> $DIR/mix.rs:65:14 + | +LL | cfg!(any(aa, bb)); + | ^^ + +warning: unexpected `cfg` condition name: `bb` + --> $DIR/mix.rs:65:18 + | +LL | cfg!(any(aa, bb)); + | ^^ + +warning: unexpected `cfg` condition value: `zebra` + --> $DIR/mix.rs:68:20 + | +LL | cfg!(any(unix, feature = "zebra")); + | ^^^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `foo` + +warning: unexpected `cfg` condition name: `xxx` + --> $DIR/mix.rs:70:14 + | +LL | cfg!(any(xxx, feature = "zebra")); + | ^^^ + +warning: unexpected `cfg` condition value: `zebra` + --> $DIR/mix.rs:70:19 + | +LL | cfg!(any(xxx, feature = "zebra")); + | ^^^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `foo` + +warning: unexpected `cfg` condition name: `xxx` + --> $DIR/mix.rs:73:14 + | +LL | cfg!(any(xxx, unix, xxx)); + | ^^^ + +warning: unexpected `cfg` condition name: `xxx` + --> $DIR/mix.rs:73:25 + | +LL | cfg!(any(xxx, unix, xxx)); + | ^^^ + +warning: unexpected `cfg` condition value: `zebra` + --> $DIR/mix.rs:76:14 + | +LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra")); + | ^^^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `foo` + +warning: unexpected `cfg` condition value: `zebra` + --> $DIR/mix.rs:76:33 + | +LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra")); + | ^^^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `foo` + +warning: unexpected `cfg` condition value: `zebra` + --> $DIR/mix.rs:76:52 + | +LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra")); + | ^^^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `foo` + +warning: 28 warnings emitted + diff --git a/tests/ui/check-cfg/mix.rs b/tests/ui/check-cfg/mix.rs index 9adf5c46e43..d7b3b4953b7 100644 --- a/tests/ui/check-cfg/mix.rs +++ b/tests/ui/check-cfg/mix.rs @@ -3,7 +3,11 @@ // we correctly lint on the `cfg!` macro and `cfg_attr` attribute. // // check-pass -// compile-flags: --check-cfg=names() --check-cfg=values(feature,"foo") --cfg feature="bar" --cfg unknown_name -Z unstable-options +// revisions: names_values cfg +// compile-flags: --cfg feature="bar" --cfg unknown_name -Z unstable-options +// compile-flags: --check-cfg=cfg(names_values,cfg) +// [names_values]compile-flags: --check-cfg=names() --check-cfg=values(feature,"foo") +// [cfg]compile-flags: --check-cfg=cfg(feature,values("foo")) #[cfg(windows)] fn do_windows_stuff() {} diff --git a/tests/ui/check-cfg/no-values.stderr b/tests/ui/check-cfg/no-expected-values.empty.stderr index ffa87dc58f2..5d261b2a5e6 100644 --- a/tests/ui/check-cfg/no-values.stderr +++ b/tests/ui/check-cfg/no-expected-values.empty.stderr @@ -1,5 +1,5 @@ -warning: unexpected `cfg` condition value - --> $DIR/no-values.rs:6:7 +warning: unexpected `cfg` condition value: `foo` + --> $DIR/no-expected-values.rs:12:7 | LL | #[cfg(feature = "foo")] | ^^^^^^^-------- @@ -9,8 +9,8 @@ LL | #[cfg(feature = "foo")] = note: no expected value for `feature` = note: `#[warn(unexpected_cfgs)]` on by default -warning: unexpected `cfg` condition value - --> $DIR/no-values.rs:10:7 +warning: unexpected `cfg` condition value: `foo` + --> $DIR/no-expected-values.rs:16:7 | LL | #[cfg(test = "foo")] | ^^^^-------- diff --git a/tests/ui/check-cfg/no-expected-values.mixed.stderr b/tests/ui/check-cfg/no-expected-values.mixed.stderr new file mode 100644 index 00000000000..5d261b2a5e6 --- /dev/null +++ b/tests/ui/check-cfg/no-expected-values.mixed.stderr @@ -0,0 +1,23 @@ +warning: unexpected `cfg` condition value: `foo` + --> $DIR/no-expected-values.rs:12:7 + | +LL | #[cfg(feature = "foo")] + | ^^^^^^^-------- + | | + | help: remove the value + | + = note: no expected value for `feature` + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition value: `foo` + --> $DIR/no-expected-values.rs:16:7 + | +LL | #[cfg(test = "foo")] + | ^^^^-------- + | | + | help: remove the value + | + = note: no expected value for `test` + +warning: 2 warnings emitted + diff --git a/tests/ui/check-cfg/no-expected-values.rs b/tests/ui/check-cfg/no-expected-values.rs new file mode 100644 index 00000000000..9e2a9f09aed --- /dev/null +++ b/tests/ui/check-cfg/no-expected-values.rs @@ -0,0 +1,20 @@ +// Check that we detect unexpected value when none are allowed +// +// check-pass +// revisions: values simple mixed empty +// compile-flags: -Z unstable-options +// compile-flags: --check-cfg=cfg(values,simple,mixed,empty) +// [values]compile-flags: --check-cfg=values(test) --check-cfg=values(feature) +// [simple]compile-flags: --check-cfg=cfg(test) --check-cfg=cfg(feature) +// [mixed]compile-flags: --check-cfg=cfg(test,feature) +// [empty]compile-flags: --check-cfg=cfg(test,feature,values()) + +#[cfg(feature = "foo")] +//~^ WARNING unexpected `cfg` condition value +fn do_foo() {} + +#[cfg(test = "foo")] +//~^ WARNING unexpected `cfg` condition value +fn do_foo() {} + +fn main() {} diff --git a/tests/ui/check-cfg/no-expected-values.simple.stderr b/tests/ui/check-cfg/no-expected-values.simple.stderr new file mode 100644 index 00000000000..5d261b2a5e6 --- /dev/null +++ b/tests/ui/check-cfg/no-expected-values.simple.stderr @@ -0,0 +1,23 @@ +warning: unexpected `cfg` condition value: `foo` + --> $DIR/no-expected-values.rs:12:7 + | +LL | #[cfg(feature = "foo")] + | ^^^^^^^-------- + | | + | help: remove the value + | + = note: no expected value for `feature` + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition value: `foo` + --> $DIR/no-expected-values.rs:16:7 + | +LL | #[cfg(test = "foo")] + | ^^^^-------- + | | + | help: remove the value + | + = note: no expected value for `test` + +warning: 2 warnings emitted + diff --git a/tests/ui/check-cfg/no-expected-values.values.stderr b/tests/ui/check-cfg/no-expected-values.values.stderr new file mode 100644 index 00000000000..5d261b2a5e6 --- /dev/null +++ b/tests/ui/check-cfg/no-expected-values.values.stderr @@ -0,0 +1,23 @@ +warning: unexpected `cfg` condition value: `foo` + --> $DIR/no-expected-values.rs:12:7 + | +LL | #[cfg(feature = "foo")] + | ^^^^^^^-------- + | | + | help: remove the value + | + = note: no expected value for `feature` + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition value: `foo` + --> $DIR/no-expected-values.rs:16:7 + | +LL | #[cfg(test = "foo")] + | ^^^^-------- + | | + | help: remove the value + | + = note: no expected value for `test` + +warning: 2 warnings emitted + diff --git a/tests/ui/check-cfg/no-values.rs b/tests/ui/check-cfg/no-values.rs deleted file mode 100644 index 8c80f56cb5a..00000000000 --- a/tests/ui/check-cfg/no-values.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Check that we detect unexpected value when none are allowed -// -// check-pass -// compile-flags: --check-cfg=values(test) --check-cfg=values(feature) -Z unstable-options - -#[cfg(feature = "foo")] -//~^ WARNING unexpected `cfg` condition value -fn do_foo() {} - -#[cfg(test = "foo")] -//~^ WARNING unexpected `cfg` condition value -fn do_foo() {} - -fn main() {} diff --git a/tests/ui/check-cfg/order-independant.names_after.stderr b/tests/ui/check-cfg/order-independant.names_after.stderr index 91b81428b38..a308358e485 100644 --- a/tests/ui/check-cfg/order-independant.names_after.stderr +++ b/tests/ui/check-cfg/order-independant.names_after.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: (none) --> $DIR/order-independant.rs:8:7 | LL | #[cfg(a)] @@ -7,7 +7,7 @@ LL | #[cfg(a)] = note: expected values for `a` are: `b` = note: `#[warn(unexpected_cfgs)]` on by default -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `unk` --> $DIR/order-independant.rs:12:7 | LL | #[cfg(a = "unk")] diff --git a/tests/ui/check-cfg/order-independant.names_before.stderr b/tests/ui/check-cfg/order-independant.names_before.stderr index 91b81428b38..a308358e485 100644 --- a/tests/ui/check-cfg/order-independant.names_before.stderr +++ b/tests/ui/check-cfg/order-independant.names_before.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: (none) --> $DIR/order-independant.rs:8:7 | LL | #[cfg(a)] @@ -7,7 +7,7 @@ LL | #[cfg(a)] = note: expected values for `a` are: `b` = note: `#[warn(unexpected_cfgs)]` on by default -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `unk` --> $DIR/order-independant.rs:12:7 | LL | #[cfg(a = "unk")] diff --git a/tests/ui/check-cfg/stmt-no-ice.rs b/tests/ui/check-cfg/stmt-no-ice.rs index cf76487ed46..383e830a1b2 100644 --- a/tests/ui/check-cfg/stmt-no-ice.rs +++ b/tests/ui/check-cfg/stmt-no-ice.rs @@ -1,7 +1,7 @@ // This test checks that there is no ICE with this code // // check-pass -// compile-flags:--check-cfg=names() -Z unstable-options +// compile-flags:--check-cfg=cfg() -Z unstable-options fn main() { #[cfg(crossbeam_loom)] diff --git a/tests/ui/check-cfg/stmt-no-ice.stderr b/tests/ui/check-cfg/stmt-no-ice.stderr index da65b596911..900ea4e4da0 100644 --- a/tests/ui/check-cfg/stmt-no-ice.stderr +++ b/tests/ui/check-cfg/stmt-no-ice.stderr @@ -1,9 +1,10 @@ -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `crossbeam_loom` --> $DIR/stmt-no-ice.rs:7:11 | LL | #[cfg(crossbeam_loom)] | ^^^^^^^^^^^^^^ | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` = note: `#[warn(unexpected_cfgs)]` on by default warning: 1 warning emitted diff --git a/tests/ui/check-cfg/invalid-cfg-name.stderr b/tests/ui/check-cfg/unexpected-cfg-name.exhaustive.stderr index ed09f8cb66d..513f7ac7fd1 100644 --- a/tests/ui/check-cfg/invalid-cfg-name.stderr +++ b/tests/ui/check-cfg/unexpected-cfg-name.exhaustive.stderr @@ -1,5 +1,5 @@ -warning: unexpected `cfg` condition name - --> $DIR/invalid-cfg-name.rs:7:7 +warning: unexpected `cfg` condition name: `widnows` + --> $DIR/unexpected-cfg-name.rs:9:7 | LL | #[cfg(widnows)] | ^^^^^^^ help: there is a config with a similar name: `windows` diff --git a/tests/ui/check-cfg/unexpected-cfg-name.names.stderr b/tests/ui/check-cfg/unexpected-cfg-name.names.stderr new file mode 100644 index 00000000000..513f7ac7fd1 --- /dev/null +++ b/tests/ui/check-cfg/unexpected-cfg-name.names.stderr @@ -0,0 +1,10 @@ +warning: unexpected `cfg` condition name: `widnows` + --> $DIR/unexpected-cfg-name.rs:9:7 + | +LL | #[cfg(widnows)] + | ^^^^^^^ help: there is a config with a similar name: `windows` + | + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/check-cfg/unexpected-cfg-name.rs b/tests/ui/check-cfg/unexpected-cfg-name.rs new file mode 100644 index 00000000000..15c3aa6e081 --- /dev/null +++ b/tests/ui/check-cfg/unexpected-cfg-name.rs @@ -0,0 +1,16 @@ +// Check warning for unexpected configuration name +// +// check-pass +// revisions: names exhaustive +// compile-flags: --check-cfg=cfg(names,exhaustive) +// [names]compile-flags: --check-cfg=names() -Z unstable-options +// [exhaustive]compile-flags: --check-cfg=cfg() -Z unstable-options + +#[cfg(widnows)] +//~^ WARNING unexpected `cfg` condition name +pub fn f() {} + +#[cfg(windows)] +pub fn g() {} + +pub fn main() {} diff --git a/tests/ui/check-cfg/invalid-cfg-value.stderr b/tests/ui/check-cfg/unexpected-cfg-value.cfg.stderr index 776d264a7ad..2ed7f900557 100644 --- a/tests/ui/check-cfg/invalid-cfg-value.stderr +++ b/tests/ui/check-cfg/unexpected-cfg-value.cfg.stderr @@ -1,5 +1,5 @@ -warning: unexpected `cfg` condition value - --> $DIR/invalid-cfg-value.rs:7:7 +warning: unexpected `cfg` condition value: `sedre` + --> $DIR/unexpected-cfg-value.rs:11:7 | LL | #[cfg(feature = "sedre")] | ^^^^^^^^^^------- @@ -9,8 +9,8 @@ LL | #[cfg(feature = "sedre")] = note: expected values for `feature` are: `full`, `serde` = note: `#[warn(unexpected_cfgs)]` on by default -warning: unexpected `cfg` condition value - --> $DIR/invalid-cfg-value.rs:14:7 +warning: unexpected `cfg` condition value: `rand` + --> $DIR/unexpected-cfg-value.rs:18:7 | LL | #[cfg(feature = "rand")] | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/check-cfg/unexpected-cfg-value.rs b/tests/ui/check-cfg/unexpected-cfg-value.rs new file mode 100644 index 00000000000..a84458071de --- /dev/null +++ b/tests/ui/check-cfg/unexpected-cfg-value.rs @@ -0,0 +1,22 @@ +// Check warning for invalid configuration value in the code and +// in the cli +// +// check-pass +// revisions: values cfg +// compile-flags: --cfg=feature="rand" -Z unstable-options +// compile-flags: --check-cfg=cfg(values,cfg) +// [values]compile-flags: --check-cfg=values(feature,"serde","full") +// [cfg]compile-flags: --check-cfg=cfg(feature,values("serde","full")) + +#[cfg(feature = "sedre")] +//~^ WARNING unexpected `cfg` condition value +pub fn f() {} + +#[cfg(feature = "serde")] +pub fn g() {} + +#[cfg(feature = "rand")] +//~^ WARNING unexpected `cfg` condition value +pub fn h() {} + +pub fn main() {} diff --git a/tests/ui/check-cfg/unexpected-cfg-value.values.stderr b/tests/ui/check-cfg/unexpected-cfg-value.values.stderr new file mode 100644 index 00000000000..2ed7f900557 --- /dev/null +++ b/tests/ui/check-cfg/unexpected-cfg-value.values.stderr @@ -0,0 +1,25 @@ +warning: unexpected `cfg` condition value: `sedre` + --> $DIR/unexpected-cfg-value.rs:11:7 + | +LL | #[cfg(feature = "sedre")] + | ^^^^^^^^^^------- + | | + | help: there is a expected value with a similar name: `"serde"` + | + = note: expected values for `feature` are: `full`, `serde` + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: unexpected `cfg` condition value: `rand` + --> $DIR/unexpected-cfg-value.rs:18:7 + | +LL | #[cfg(feature = "rand")] + | ^^^^^^^^^^^^^^^^ + | + = note: expected values for `feature` are: `full`, `serde` + +warning: unexpected condition value `rand` for condition name `feature` + | + = help: was set with `--cfg` but isn't in the `--check-cfg` expected values + +warning: 3 warnings emitted + diff --git a/tests/ui/check-cfg/unknown-values.rs b/tests/ui/check-cfg/unknown-values.rs new file mode 100644 index 00000000000..c082a2f25ac --- /dev/null +++ b/tests/ui/check-cfg/unknown-values.rs @@ -0,0 +1,17 @@ +// Check that no warning is emitted for unknown cfg value +// +// check-pass +// revisions: simple mixed with_values +// compile-flags: -Z unstable-options +// compile-flags: --check-cfg=cfg(simple,mixed,with_values) +// [simple]compile-flags: --check-cfg=cfg(foo,values(any())) +// [mixed]compile-flags: --check-cfg=cfg(foo) --check-cfg=cfg(foo,values(any())) +// [with_values]compile-flags:--check-cfg=cfg(foo,values(any())) --check-cfg=cfg(foo,values("aa")) + +#[cfg(foo = "value")] +pub fn f() {} + +#[cfg(foo)] +pub fn f() {} + +fn main() {} diff --git a/tests/ui/check-cfg/values-target-json.stderr b/tests/ui/check-cfg/values-target-json.stderr index c705152d9fc..e71149f337f 100644 --- a/tests/ui/check-cfg/values-target-json.stderr +++ b/tests/ui/check-cfg/values-target-json.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `linuz` --> $DIR/values-target-json.rs:13:7 | LL | #[cfg(target_os = "linuz")] diff --git a/tests/ui/check-cfg/well-known-names.rs b/tests/ui/check-cfg/well-known-names.rs index e57fb69a1e0..1dcb419b4a7 100644 --- a/tests/ui/check-cfg/well-known-names.rs +++ b/tests/ui/check-cfg/well-known-names.rs @@ -1,7 +1,7 @@ // This test checks that we lint on non well known names and that we don't lint on well known names // // check-pass -// compile-flags: --check-cfg=names() -Z unstable-options +// compile-flags: --check-cfg=cfg() -Z unstable-options #[cfg(target_oz = "linux")] //~^ WARNING unexpected `cfg` condition name diff --git a/tests/ui/check-cfg/well-known-names.stderr b/tests/ui/check-cfg/well-known-names.stderr index 34c5d6172d9..3001289b7e0 100644 --- a/tests/ui/check-cfg/well-known-names.stderr +++ b/tests/ui/check-cfg/well-known-names.stderr @@ -1,14 +1,16 @@ -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `target_oz` --> $DIR/well-known-names.rs:6:7 | LL | #[cfg(target_oz = "linux")] - | ---------^^^^^^^^^^ - | | - | help: there is a config with a similar name: `target_os` + | ^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(unexpected_cfgs)]` on by default +help: there is a config with a similar name and value + | +LL | #[cfg(target_os = "linux")] + | ~~~~~~~~~ -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `features` --> $DIR/well-known-names.rs:13:7 | LL | #[cfg(features = "foo")] @@ -16,7 +18,7 @@ LL | #[cfg(features = "foo")] | | | help: there is a config with a similar name: `feature` -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `uniw` --> $DIR/well-known-names.rs:20:7 | LL | #[cfg(uniw)] diff --git a/tests/ui/check-cfg/well-known-values.rs b/tests/ui/check-cfg/well-known-values.rs index 96375dc8d31..8b56c8729d8 100644 --- a/tests/ui/check-cfg/well-known-values.rs +++ b/tests/ui/check-cfg/well-known-values.rs @@ -2,7 +2,7 @@ // values // // check-pass -// compile-flags: --check-cfg=values() -Z unstable-options +// compile-flags: --check-cfg=cfg() -Z unstable-options #[cfg(target_os = "linuz")] //~^ WARNING unexpected `cfg` condition value diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index b381f5a4a0a..6877d8f5bb7 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `linuz` --> $DIR/well-known-values.rs:7:7 | LL | #[cfg(target_os = "linuz")] @@ -9,7 +9,7 @@ LL | #[cfg(target_os = "linuz")] = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous` = note: `#[warn(unexpected_cfgs)]` on by default -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `0` --> $DIR/well-known-values.rs:14:7 | LL | #[cfg(target_has_atomic = "0")] @@ -19,7 +19,7 @@ LL | #[cfg(target_has_atomic = "0")] | = note: expected values for `target_has_atomic` are: (none), `128`, `16`, `32`, `64`, `8`, `ptr` -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `aa` --> $DIR/well-known-values.rs:21:7 | LL | #[cfg(unix = "aa")] @@ -29,7 +29,7 @@ LL | #[cfg(unix = "aa")] | = note: no expected value for `unix` -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `miri` --> $DIR/well-known-values.rs:28:7 | LL | #[cfg(miri = "miri")] @@ -39,7 +39,7 @@ LL | #[cfg(miri = "miri")] | = note: no expected value for `miri` -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `linux` --> $DIR/well-known-values.rs:35:7 | LL | #[cfg(doc = "linux")] diff --git a/tests/ui/coherence/warn-when-cycle-is-error-in-coherence.stderr b/tests/ui/coherence/warn-when-cycle-is-error-in-coherence.stderr index ecc73d994f9..4f32639a631 100644 --- a/tests/ui/coherence/warn-when-cycle-is-error-in-coherence.stderr +++ b/tests/ui/coherence/warn-when-cycle-is-error-in-coherence.stderr @@ -24,3 +24,28 @@ LL | #![deny(coinductive_overlap_in_coherence)] error: aborting due to previous error +Future incompatibility report: Future breakage diagnostic: +error: implementations of `PartialEq<Interval<_>>` for `Interval<_>` will conflict in the future + --> $DIR/warn-when-cycle-is-error-in-coherence.rs:13:1 + | +LL | #[derive(PartialEq, Default)] + | --------- the second impl is here +... +LL | / impl<T, Q> PartialEq<Q> for Interval<T> +LL | | +LL | | +LL | | where +LL | | T: Borrow<Q>, +LL | | Q: ?Sized + PartialOrd, + | |___________________________^ the first impl is here + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #114040 <https://github.com/rust-lang/rust/issues/114040> + = note: impls that are not considered to overlap may be considered to overlap in the future + = note: `Interval<_>: PartialOrd` may be considered to hold in future releases, causing the impls to overlap +note: the lint level is defined here + --> $DIR/warn-when-cycle-is-error-in-coherence.rs:1:9 + | +LL | #![deny(coinductive_overlap_in_coherence)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/const-generics/generic_const_exprs/issue-80742.rs b/tests/ui/const-generics/generic_const_exprs/issue-80742.rs index 6b2a0153f51..5f612780f39 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-80742.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-80742.rs @@ -3,6 +3,7 @@ // failure-status: 101 // normalize-stderr-test "note: .*\n\n" -> "" // normalize-stderr-test "thread 'rustc' panicked.*\n" -> "" +// normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: " // rustc-env:RUST_BACKTRACE=0 // This test used to cause an ICE in rustc_mir::interpret::step::eval_rvalue_into_place diff --git a/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr b/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr index 25a455d3308..9b66fc502b7 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr @@ -1,9 +1,9 @@ -error: internal compiler error: compiler/rustc_const_eval/src/interpret/step.rs:272:21: SizeOf MIR operator called for unsized type dyn Debug +error: internal compiler error: compiler/rustc_const_eval/src/interpret/step.rs:LL:CC: SizeOf MIR operator called for unsized type dyn Debug --> $SRC_DIR/core/src/mem/mod.rs:LL:COL Box<dyn Any> query stack during panic: -#0 [eval_to_allocation_raw] const-evaluating + checking `<impl at $DIR/issue-80742.rs:25:1: 27:32>::{constant#0}` +#0 [eval_to_allocation_raw] const-evaluating + checking `<impl at $DIR/issue-80742.rs:26:1: 28:32>::{constant#0}` #1 [eval_to_valtree] evaluating type-level constant end of query stack error: aborting due to previous error diff --git a/tests/ui/const-generics/issues/issue-100313.stderr b/tests/ui/const-generics/issues/issue-100313.stderr index 796966b22d5..5832dbe1777 100644 --- a/tests/ui/const-generics/issues/issue-100313.stderr +++ b/tests/ui/const-generics/issues/issue-100313.stderr @@ -11,7 +11,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/issue-100313.rs:10:13 | LL | *(B as *const bool as *mut bool) = false; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to alloc7 which is read-only + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to ALLOC0 which is read-only | note: inside `T::<&true>::set_false` --> $DIR/issue-100313.rs:10:13 diff --git a/tests/ui/const-ptr/forbidden_slices.rs b/tests/ui/const-ptr/forbidden_slices.rs index 192b6a46de6..03d6499aefb 100644 --- a/tests/ui/const-ptr/forbidden_slices.rs +++ b/tests/ui/const-ptr/forbidden_slices.rs @@ -1,8 +1,7 @@ // Strip out raw byte dumps to make comparison platform-independent: // normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" -// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" -// normalize-stderr-test "alloc\d+" -> "allocN" -// error-pattern: could not evaluate static initializer +// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*A(LLOC)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" + #![feature( slice_from_ptr_range, const_slice_from_ptr_range, @@ -17,10 +16,13 @@ use std::{ // Null is never valid for reads pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) }; +//~^ ERROR: it is undefined behavior to use this value pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) }; +//~^ ERROR: it is undefined behavior to use this value // Out of bounds pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) }; +//~^ ERROR: it is undefined behavior to use this value // Reading uninitialized data pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; //~ ERROR: it is undefined behavior to use this value @@ -39,6 +41,7 @@ pub static S7: &[u16] = unsafe { // Unaligned read pub static S8: &[u64] = unsafe { + //~^ ERROR: it is undefined behavior to use this value let ptr = (&D4 as *const [u32; 2] as *const u32).byte_add(1).cast::<u64>(); from_raw_parts(ptr, 1) @@ -66,8 +69,9 @@ pub static R6: &[bool] = unsafe { from_ptr_range(ptr..ptr.add(4)) }; pub static R7: &[u16] = unsafe { + //~^ ERROR: it is undefined behavior to use this value let ptr = (&D2 as *const Struct as *const u16).byte_add(1); - from_ptr_range(ptr..ptr.add(4)) //~ inside `R7` + from_ptr_range(ptr..ptr.add(4)) }; pub static R8: &[u64] = unsafe { let ptr = (&D4 as *const [u32; 2] as *const u32).byte_add(1).cast::<u64>(); diff --git a/tests/ui/const-ptr/forbidden_slices.stderr b/tests/ui/const-ptr/forbidden_slices.stderr index 294bc77aa31..00230d59a37 100644 --- a/tests/ui/const-ptr/forbidden_slices.stderr +++ b/tests/ui/const-ptr/forbidden_slices.stderr @@ -1,44 +1,38 @@ -error[E0080]: could not evaluate static initializer - --> $SRC_DIR/core/src/slice/raw.rs:LL:COL - | - = note: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) - | -note: inside `std::slice::from_raw_parts::<'_, u32>` - --> $SRC_DIR/core/src/slice/raw.rs:LL:COL -note: inside `S0` - --> $DIR/forbidden_slices.rs:19:34 +error[E0080]: it is undefined behavior to use this value + --> $DIR/forbidden_slices.rs:18:1 | LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0080]: could not evaluate static initializer - --> $SRC_DIR/core/src/slice/raw.rs:LL:COL + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference | - = note: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) - | -note: inside `std::slice::from_raw_parts::<'_, ()>` - --> $SRC_DIR/core/src/slice/raw.rs:LL:COL -note: inside `S1` - --> $DIR/forbidden_slices.rs:20:33 - | -LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = 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]: could not evaluate static initializer - --> $SRC_DIR/core/src/slice/raw.rs:LL:COL +error[E0080]: it is undefined behavior to use this value + --> $DIR/forbidden_slices.rs:20:1 | - = note: dereferencing pointer failed: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds +LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) }; + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference | -note: inside `std::slice::from_raw_parts::<'_, u32>` - --> $SRC_DIR/core/src/slice/raw.rs:LL:COL -note: inside `S2` - --> $DIR/forbidden_slices.rs:23:34 + = 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/forbidden_slices.rs:24:1 | LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) }; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) + | + = 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/forbidden_slices.rs:26:1 + --> $DIR/forbidden_slices.rs:28: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 @@ -49,7 +43,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/forbidden_slices.rs:28:1 + --> $DIR/forbidden_slices.rs:30:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a pointer, but expected an integer @@ -62,7 +56,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size = 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/forbidden_slices.rs:30:1 + --> $DIR/forbidden_slices.rs:32: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 @@ -73,7 +67,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/forbidden_slices.rs:33:1 + --> $DIR/forbidden_slices.rs:35:1 | LL | pub static S7: &[u16] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[1]: encountered uninitialized memory, but expected an integer @@ -83,18 +77,16 @@ LL | pub static S7: &[u16] = unsafe { HEX_DUMP } -error[E0080]: could not evaluate static initializer - --> $SRC_DIR/core/src/slice/raw.rs:LL:COL - | - = note: dereferencing pointer failed: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds +error[E0080]: it is undefined behavior to use this value + --> $DIR/forbidden_slices.rs:43:1 | -note: inside `std::slice::from_raw_parts::<'_, u64>` - --> $SRC_DIR/core/src/slice/raw.rs:LL:COL -note: inside `S8` - --> $DIR/forbidden_slices.rs:44:5 +LL | pub static S8: &[u64] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) | -LL | from_raw_parts(ptr, 1) - | ^^^^^^^^^^^^^^^^^^^^^^ + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -106,7 +98,7 @@ note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr` note: inside `from_ptr_range::<'_, u32>` --> $SRC_DIR/core/src/slice/raw.rs:LL:COL note: inside `R0` - --> $DIR/forbidden_slices.rs:47:34 + --> $DIR/forbidden_slices.rs:50:34 | LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +113,7 @@ note: inside `ptr::const_ptr::<impl *const ()>::sub_ptr` note: inside `from_ptr_range::<'_, ()>` --> $SRC_DIR/core/src/slice/raw.rs:LL:COL note: inside `R1` - --> $DIR/forbidden_slices.rs:48:33 + --> $DIR/forbidden_slices.rs:51:33 | LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -130,18 +122,18 @@ LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: out-of-bounds pointer arithmetic: allocN has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds + = note: out-of-bounds pointer arithmetic: ALLOC10 has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds | note: inside `ptr::const_ptr::<impl *const u32>::add` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `R2` - --> $DIR/forbidden_slices.rs:51:25 + --> $DIR/forbidden_slices.rs:54:25 | LL | from_ptr_range(ptr..ptr.add(2)) | ^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:53:1 + --> $DIR/forbidden_slices.rs:56:1 | LL | pub static R4: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized memory, but expected an integer @@ -152,7 +144,7 @@ LL | pub static R4: &[u8] = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/forbidden_slices.rs:58:1 + --> $DIR/forbidden_slices.rs:61:1 | LL | pub static R5: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a pointer, but expected an integer @@ -165,7 +157,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/forbidden_slices.rs:63:1 + --> $DIR/forbidden_slices.rs:66:1 | LL | pub static R6: &[bool] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean @@ -175,30 +167,26 @@ LL | pub static R6: &[bool] = unsafe { HEX_DUMP } -error[E0080]: could not evaluate static initializer - --> $SRC_DIR/core/src/slice/raw.rs:LL:COL - | - = note: accessing memory with alignment 1, but alignment 2 is required +error[E0080]: it is undefined behavior to use this value + --> $DIR/forbidden_slices.rs:71:1 | -note: inside `std::slice::from_raw_parts::<'_, u16>` - --> $SRC_DIR/core/src/slice/raw.rs:LL:COL -note: inside `from_ptr_range::<'_, u16>` - --> $SRC_DIR/core/src/slice/raw.rs:LL:COL -note: inside `R7` - --> $DIR/forbidden_slices.rs:70:5 +LL | pub static R7: &[u16] = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) | -LL | from_ptr_range(ptr..ptr.add(4)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = 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]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: out-of-bounds pointer arithmetic: allocN has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds + = note: out-of-bounds pointer arithmetic: ALLOC11 has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds | note: inside `ptr::const_ptr::<impl *const u64>::add` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL note: inside `R8` - --> $DIR/forbidden_slices.rs:74:25 + --> $DIR/forbidden_slices.rs:78:25 | LL | from_ptr_range(ptr..ptr.add(1)) | ^^^^^^^^^^ @@ -213,7 +201,7 @@ note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr` note: inside `from_ptr_range::<'_, u32>` --> $SRC_DIR/core/src/slice/raw.rs:LL:COL note: inside `R9` - --> $DIR/forbidden_slices.rs:79:34 + --> $DIR/forbidden_slices.rs:83:34 | LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -228,7 +216,7 @@ note: inside `ptr::const_ptr::<impl *const u32>::sub_ptr` note: inside `from_ptr_range::<'_, u32>` --> $SRC_DIR/core/src/slice/raw.rs:LL:COL note: inside `R10` - --> $DIR/forbidden_slices.rs:80:35 + --> $DIR/forbidden_slices.rs:84:35 | LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/const-ptr/out_of_bounds_read.stderr b/tests/ui/const-ptr/out_of_bounds_read.stderr index c5c0a1cdefc..be75f76b26f 100644 --- a/tests/ui/const-ptr/out_of_bounds_read.stderr +++ b/tests/ui/const-ptr/out_of_bounds_read.stderr @@ -1,7 +1,7 @@ error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | - = note: dereferencing pointer failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds + = note: memory access failed: ALLOC0 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds | note: inside `std::ptr::read::<u32>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL @@ -14,7 +14,7 @@ LL | const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) }; error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | - = note: dereferencing pointer failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds + = note: memory access failed: ALLOC0 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds | note: inside `std::ptr::read::<u32>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL @@ -29,7 +29,7 @@ LL | const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() }; error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | - = note: dereferencing pointer failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds + = note: memory access failed: ALLOC0 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds | note: inside `std::ptr::read::<u32>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/tests/ui/consts/const-compare-bytes-ub.stderr b/tests/ui/consts/const-compare-bytes-ub.stderr index 54fafded07b..d8971eb9969 100644 --- a/tests/ui/consts/const-compare-bytes-ub.stderr +++ b/tests/ui/consts/const-compare-bytes-ub.stderr @@ -20,25 +20,25 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:22:9 | LL | compare_bytes([1, 2, 3].as_ptr(), [1, 2, 3, 4].as_ptr(), 4) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: alloc6 has size 3, so pointer to 4 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC0 has size 3, so pointer to 4 bytes starting at offset 0 is out-of-bounds error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:26:9 | LL | compare_bytes([1, 2, 3, 4].as_ptr(), [1, 2, 3].as_ptr(), 4) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: alloc13 has size 3, so pointer to 4 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC1 has size 3, so pointer to 4 bytes starting at offset 0 is out-of-bounds error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:30:9 | LL | compare_bytes(MaybeUninit::uninit().as_ptr(), [1].as_ptr(), 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at alloc17[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC2[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:34:9 | LL | compare_bytes([1].as_ptr(), MaybeUninit::uninit().as_ptr(), 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at alloc25[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC3[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:38:9 diff --git a/tests/ui/consts/const-deref-ptr.rs b/tests/ui/consts/const-deref-ptr.rs index 4aca75e3a17..2607d4de229 100644 --- a/tests/ui/consts/const-deref-ptr.rs +++ b/tests/ui/consts/const-deref-ptr.rs @@ -3,5 +3,6 @@ fn main() { static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; //~^ ERROR could not evaluate static initializer + //~| dangling pointer println!("{}", C); } diff --git a/tests/ui/consts/const-deref-ptr.stderr b/tests/ui/consts/const-deref-ptr.stderr index 22cb6451e87..16eb6b0162d 100644 --- a/tests/ui/consts/const-deref-ptr.stderr +++ b/tests/ui/consts/const-deref-ptr.stderr @@ -2,7 +2,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/const-deref-ptr.rs:4:29 | LL | static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0xdeadbeef[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: 0xdeadbeef[noalloc] is a dangling pointer (it has no provenance) error: aborting due to previous error diff --git a/tests/ui/consts/const-eval/const_fn_target_feature_wasm.rs b/tests/ui/consts/const-eval/const_fn_target_feature_wasm.rs new file mode 100644 index 00000000000..c1460fdd9ec --- /dev/null +++ b/tests/ui/consts/const-eval/const_fn_target_feature_wasm.rs @@ -0,0 +1,14 @@ +// only-wasm32 +// compile-flags:-C target-feature=-simd128 +// build-pass + +#![crate_type = "lib"] + +#[cfg(target_feature = "simd128")] +compile_error!("simd128 target feature should be disabled"); + +// Calling functions with `#[target_feature]` is not unsound on WASM, see #84988 +const A: () = simd128_fn(); + +#[target_feature(enable = "simd128")] +const fn simd128_fn() {} diff --git a/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr b/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr index e41dea873ac..e6cd25e42ff 100644 --- a/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr +++ b/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr @@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed --> $DIR/const_raw_ptr_ops2.rs:7:26 | LL | const Z2: i32 = unsafe { *(42 as *const i32) }; - | ^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0x2a[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^ memory access failed: 0x2a[noalloc] is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed --> $DIR/const_raw_ptr_ops2.rs:9:26 | LL | const Z3: i32 = unsafe { *(44 as *const i32) }; - | ^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0x2c[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^ memory access failed: 0x2c[noalloc] is a dangling pointer (it has no provenance) error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/dangling.rs b/tests/ui/consts/const-eval/dangling.rs deleted file mode 100644 index 4fcf879218b..00000000000 --- a/tests/ui/consts/const-eval/dangling.rs +++ /dev/null @@ -1,10 +0,0 @@ -use std::mem; - -// Make sure we error with the right kind of error on a too large slice. -const TEST: () = { unsafe { - let slice: *const [u8] = mem::transmute((1usize, usize::MAX)); - let _val = &*slice; //~ ERROR: evaluation of constant value failed - //~| slice is bigger than largest supported object -} }; - -fn main() {} diff --git a/tests/ui/consts/const-eval/dangling.stderr b/tests/ui/consts/const-eval/dangling.stderr deleted file mode 100644 index 92d70573d98..00000000000 --- a/tests/ui/consts/const-eval/dangling.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/dangling.rs:6:16 - | -LL | let _val = &*slice; - | ^^^^^^^ invalid metadata in wide pointer: slice is bigger than largest supported object - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr index a0f4519eaad..82de91effe7 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr @@ -6,7 +6,7 @@ LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - ╾─alloc2──╼ │ ╾──╼ + ╾ALLOC0╼ │ ╾──╼ } error: aborting due to previous error diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr index d2bffa42561..de23aafe05c 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr @@ -6,7 +6,7 @@ LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { - ╾───────alloc2────────╼ │ ╾──────╼ + ╾ALLOC0╼ │ ╾──────╼ } error: aborting due to previous error diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs index b6d89a58dce..a717a5f8292 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs @@ -5,10 +5,10 @@ use std::intrinsics; const _X: &'static u8 = unsafe { + //~^ error: dangling pointer in final constant let ptr = intrinsics::const_allocate(4, 4); intrinsics::const_deallocate(ptr, 4, 4); &*ptr - //~^ error: evaluation of constant value failed }; const _Y: u8 = unsafe { diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr index b50ef0c68a1..5f4630f6f4b 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr @@ -1,14 +1,14 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/dealloc_intrinsic_dangling.rs:10:5 +error: encountered dangling pointer in final constant + --> $DIR/dealloc_intrinsic_dangling.rs:7:1 | -LL | &*ptr - | ^^^^^ dereferencing pointer failed: alloc2 has been freed, so this pointer is dangling +LL | const _X: &'static u8 = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^ error[E0080]: evaluation of constant value failed --> $DIR/dealloc_intrinsic_dangling.rs:18:5 | LL | *reference - | ^^^^^^^^^^ dereferencing pointer failed: alloc4 has been freed, so this pointer is dangling + | ^^^^^^^^^^ memory access failed: ALLOC0 has been freed, so this pointer is dangling error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr index 0884ade45a7..916344a7b81 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/dealloc_intrinsic_duplicate.rs:9:5 | LL | intrinsics::const_deallocate(ptr, 4, 4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: alloc2 has been freed, so this pointer is dangling + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC0 has been freed, so this pointer is dangling error: aborting due to previous error diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr index 4c23957a1f8..4b1f0f686ca 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr @@ -2,19 +2,19 @@ error[E0080]: evaluation of constant value failed --> $DIR/dealloc_intrinsic_incorrect_layout.rs:8:5 | LL | intrinsics::const_deallocate(ptr, 4, 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: alloc2 has size 4 and alignment 4, but gave size 4 and alignment 2 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: ALLOC0 has size 4 and alignment 4, but gave size 4 and alignment 2 error[E0080]: evaluation of constant value failed --> $DIR/dealloc_intrinsic_incorrect_layout.rs:13:5 | LL | intrinsics::const_deallocate(ptr, 2, 4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: alloc4 has size 4 and alignment 4, but gave size 2 and alignment 4 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: ALLOC1 has size 4 and alignment 4, but gave size 2 and alignment 4 error[E0080]: evaluation of constant value failed --> $DIR/dealloc_intrinsic_incorrect_layout.rs:19:5 | LL | intrinsics::const_deallocate(ptr, 3, 4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: alloc6 has size 4 and alignment 4, but gave size 3 and alignment 4 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: ALLOC2 has size 4 and alignment 4, but gave size 3 and alignment 4 error[E0080]: evaluation of constant value failed --> $DIR/dealloc_intrinsic_incorrect_layout.rs:25:5 diff --git a/tests/ui/consts/const-eval/issue-114994-fail.rs b/tests/ui/consts/const-eval/issue-114994-fail.rs new file mode 100644 index 00000000000..72350464091 --- /dev/null +++ b/tests/ui/consts/const-eval/issue-114994-fail.rs @@ -0,0 +1,14 @@ +// This checks that function pointer signatures that are referenced mutably +// but contain a &mut T parameter still fail in a constant context: see issue #114994. +// +// check-fail + +const fn use_mut_const_fn(_f: &mut fn(&mut String)) { //~ ERROR mutable references are not allowed in constant functions + () +} + +const fn use_mut_const_tuple_fn(_f: (fn(), &mut u32)) { //~ ERROR mutable references are not allowed in constant functions + +} + +fn main() {} diff --git a/tests/ui/consts/const-eval/issue-114994-fail.stderr b/tests/ui/consts/const-eval/issue-114994-fail.stderr new file mode 100644 index 00000000000..4dae8ea9bca --- /dev/null +++ b/tests/ui/consts/const-eval/issue-114994-fail.stderr @@ -0,0 +1,21 @@ +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/issue-114994-fail.rs:6:27 + | +LL | const fn use_mut_const_fn(_f: &mut fn(&mut String)) { + | ^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/issue-114994-fail.rs:10:33 + | +LL | const fn use_mut_const_tuple_fn(_f: (fn(), &mut u32)) { + | ^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/const-eval/issue-114994.rs b/tests/ui/consts/const-eval/issue-114994.rs new file mode 100644 index 00000000000..a4cb2e61e5f --- /dev/null +++ b/tests/ui/consts/const-eval/issue-114994.rs @@ -0,0 +1,18 @@ +// This checks that function pointer signatures containing &mut T types +// work in a constant context: see issue #114994. +// +// check-pass + +const fn use_const_fn(_f: fn(&mut String)) { + () +} + +const fn get_some_fn() -> fn(&mut String) { + String::clear +} + +const fn some_const_fn() { + let _f: fn(&mut String) = String::clear; +} + +fn main() {} diff --git a/tests/ui/consts/const-eval/issue-49296.stderr b/tests/ui/consts/const-eval/issue-49296.stderr index 45ba0ea183e..2022a16e789 100644 --- a/tests/ui/consts/const-eval/issue-49296.stderr +++ b/tests/ui/consts/const-eval/issue-49296.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/issue-49296.rs:9:16 | LL | const X: u64 = *wat(42); - | ^^^^^^^^ dereferencing pointer failed: alloc3 has been freed, so this pointer is dangling + | ^^^^^^^^ memory access failed: ALLOC0 has been freed, so this pointer is dangling error: aborting due to previous error diff --git a/tests/ui/consts/const-eval/nonnull_as_ref_ub.rs b/tests/ui/consts/const-eval/nonnull_as_ref_ub.rs index 3b48e972923..19ab5239986 100644 --- a/tests/ui/consts/const-eval/nonnull_as_ref_ub.rs +++ b/tests/ui/consts/const-eval/nonnull_as_ref_ub.rs @@ -1,6 +1,6 @@ use std::ptr::NonNull; const NON_NULL: NonNull<u8> = unsafe { NonNull::dangling() }; -const _: () = assert!(42 == *unsafe { NON_NULL.as_ref() }); +const _: () = assert!(42 == *unsafe { NON_NULL.as_ref() }); //~ERROR: evaluation of constant value failed fn main() {} diff --git a/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr b/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr index de93cb0c3ca..e34f3f43c64 100644 --- a/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr +++ b/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr @@ -1,15 +1,8 @@ error[E0080]: evaluation of constant value failed - --> $SRC_DIR/core/src/ptr/non_null.rs:LL:COL - | - = note: dereferencing pointer failed: 0x1[noalloc] is a dangling pointer (it has no provenance) - | -note: inside `NonNull::<u8>::as_ref::<'_>` - --> $SRC_DIR/core/src/ptr/non_null.rs:LL:COL -note: inside `_` - --> $DIR/nonnull_as_ref_ub.rs:4:39 + --> $DIR/nonnull_as_ref_ub.rs:4:29 | LL | const _: () = assert!(42 == *unsafe { NON_NULL.as_ref() }); - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: 0x1[noalloc] is a dangling pointer (it has no provenance) error: aborting due to previous error diff --git a/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr b/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr index 13ca4379b7b..b948e07b92d 100644 --- a/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr +++ b/tests/ui/consts/const-eval/partial_ptr_overwrite.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/partial_ptr_overwrite.rs:8:9 | LL | *(ptr as *mut u8) = 123; - | ^^^^^^^^^^^^^^^^^^^^^^^ unable to overwrite parts of a pointer in memory at alloc4 + | ^^^^^^^^^^^^^^^^^^^^^^^ unable to overwrite parts of a pointer in memory at ALLOC0 | = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr index 042e7eeb31e..689ebf75223 100644 --- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr @@ -211,7 +211,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:106:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a function pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { @@ -385,7 +385,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:175:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -396,7 +396,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:179:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC19, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -418,7 +418,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:186: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 allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC22, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { @@ -451,7 +451,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:196:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr index 8426a95055c..3447a8ab432 100644 --- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr @@ -211,7 +211,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:106:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a function pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { @@ -385,7 +385,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:175:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -396,7 +396,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:179:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC19, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -418,7 +418,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:186: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 allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC22, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { @@ -451,7 +451,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/raw-bytes.rs:196:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { diff --git a/tests/ui/consts/const-eval/raw-bytes.rs b/tests/ui/consts/const-eval/raw-bytes.rs index 6c1238c0a06..e005922223a 100644 --- a/tests/ui/consts/const-eval/raw-bytes.rs +++ b/tests/ui/consts/const-eval/raw-bytes.rs @@ -1,8 +1,8 @@ // stderr-per-bitwidth // ignore-endian-big // ignore-tidy-linelength -// normalize-stderr-test "╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$2╼" -// normalize-stderr-test "alloc\d+" -> "allocN" +// 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)] #![allow(invalid_value)] diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.rs b/tests/ui/consts/const-eval/raw-pointer-ub.rs new file mode 100644 index 00000000000..9b79a0a7d34 --- /dev/null +++ b/tests/ui/consts/const-eval/raw-pointer-ub.rs @@ -0,0 +1,47 @@ +#![feature(const_pointer_byte_offsets)] +#![feature(pointer_byte_offsets)] +#![feature(const_mut_refs)] + + +const MISALIGNED_LOAD: () = unsafe { + let mem = [0u32; 8]; + let ptr = mem.as_ptr().byte_add(1); + let _val = *ptr; //~ERROR: evaluation of constant value failed + //~^NOTE: based on pointer with alignment 1, but alignment 4 is required +}; + +const MISALIGNED_STORE: () = unsafe { + let mut mem = [0u32; 8]; + let ptr = mem.as_mut_ptr().byte_add(1); + *ptr = 0; //~ERROR: evaluation of constant value failed + //~^NOTE: based on pointer with alignment 1, but alignment 4 is required +}; + +const MISALIGNED_COPY: () = unsafe { + let x = &[0_u8; 4]; + let y = x.as_ptr().cast::<u32>(); + let mut z = 123; + y.copy_to_nonoverlapping(&mut z, 1); + //~^NOTE + // The actual error points into the implementation of `copy_to_nonoverlapping`. +}; + +const MISALIGNED_FIELD: () = unsafe { + #[repr(align(16))] + struct Aligned(f32); + + let mem = [0f32; 8]; + let ptr = mem.as_ptr().cast::<Aligned>(); + // Accessing an f32 field but we still require the alignment of the pointer type. + let _val = (*ptr).0; //~ERROR: evaluation of constant value failed + //~^NOTE: based on pointer with alignment 4, but alignment 16 is required +}; + +const OOB: () = unsafe { + let mem = [0u32; 1]; + let ptr = mem.as_ptr().cast::<u64>(); + let _val = *ptr; //~ERROR: evaluation of constant value failed + //~^NOTE: size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.stderr b/tests/ui/consts/const-eval/raw-pointer-ub.stderr new file mode 100644 index 00000000000..f644e5f8748 --- /dev/null +++ b/tests/ui/consts/const-eval/raw-pointer-ub.stderr @@ -0,0 +1,42 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/raw-pointer-ub.rs:9:16 + | +LL | let _val = *ptr; + | ^^^^ accessing memory based on pointer with alignment 1, but alignment 4 is required + +error[E0080]: evaluation of constant value failed + --> $DIR/raw-pointer-ub.rs:16:5 + | +LL | *ptr = 0; + | ^^^^^^^^ accessing memory based on pointer with alignment 1, but alignment 4 is required + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + | + = note: accessing memory with alignment 1, but alignment 4 is required + | +note: inside `copy_nonoverlapping::<u32>` + --> $SRC_DIR/core/src/intrinsics.rs:LL:COL +note: inside `ptr::const_ptr::<impl *const u32>::copy_to_nonoverlapping` + --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL +note: inside `MISALIGNED_COPY` + --> $DIR/raw-pointer-ub.rs:24:5 + | +LL | y.copy_to_nonoverlapping(&mut z, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0080]: evaluation of constant value failed + --> $DIR/raw-pointer-ub.rs:36:16 + | +LL | let _val = (*ptr).0; + | ^^^^^^^^ accessing memory based on pointer with alignment 4, but alignment 16 is required + +error[E0080]: evaluation of constant value failed + --> $DIR/raw-pointer-ub.rs:43:16 + | +LL | let _val = *ptr; + | ^^^^ memory access failed: ALLOC0 has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr index 965256de21a..7b30233c025 100644 --- a/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.32bit.stderr @@ -1,46 +1,56 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/ub-incorrect-vtable.rs:19:14 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-incorrect-vtable.rs:18:1 + | +LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC1, but expected a vtable pointer | -LL | unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC0╼ ╾ALLOC1╼ │ ╾──╼╾──╼ + } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-incorrect-vtable.rs:24:14 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-incorrect-vtable.rs:23:1 + | +LL | const INVALID_VTABLE_SIZE: &dyn Trait = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a vtable pointer | -LL | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 4) { + ╾ALLOC2╼ ╾ALLOC3╼ │ ╾──╼╾──╼ + } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:33:1 | LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - ╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼ + ╾ALLOC4╼ ╾ALLOC5╼ │ ╾──╼╾──╼ } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:38:1 | LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC7, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - ╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼ + ╾ALLOC6╼ ╾ALLOC7╼ │ ╾──╼╾──╼ } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:44:1 | LL | const INVALID_VTABLE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC9, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - ╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼ + ╾ALLOC8╼ ╾ALLOC9╼ │ ╾──╼╾──╼ } error[E0080]: it is undefined behavior to use this value @@ -51,7 +61,7 @@ LL | const G: Wide = unsafe { Transmute { t: FOO }.u }; | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - ╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼ + ╾ALLOC10╼ ╾ALLOC11╼ │ ╾──╼╾──╼ } error: aborting due to 6 previous errors diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr index bd542a7a5f2..9330ae3c9a6 100644 --- a/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.64bit.stderr @@ -1,46 +1,56 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/ub-incorrect-vtable.rs:19:14 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-incorrect-vtable.rs:18:1 + | +LL | const INVALID_VTABLE_ALIGNMENT: &dyn Trait = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC1, but expected a vtable pointer | -LL | unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC0╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼ + } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-incorrect-vtable.rs:24:14 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-incorrect-vtable.rs:23:1 + | +LL | const INVALID_VTABLE_SIZE: &dyn Trait = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a vtable pointer | -LL | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 16, align: 8) { + ╾ALLOC2╼ ╾ALLOC3╼ │ ╾──────╼╾──────╼ + } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:33:1 | LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC5, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼ + ╾ALLOC4╼ ╾ALLOC5╼ │ ╾──────╼╾──────╼ } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:38:1 | LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC7, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼ + ╾ALLOC6╼ ╾ALLOC7╼ │ ╾──────╼╾──────╼ } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-incorrect-vtable.rs:44:1 | LL | const INVALID_VTABLE_UB: W<&dyn Trait> = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC9, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼ + ╾ALLOC8╼ ╾ALLOC9╼ │ ╾──────╼╾──────╼ } error[E0080]: it is undefined behavior to use this value @@ -51,7 +61,7 @@ LL | const G: Wide = unsafe { Transmute { t: FOO }.u }; | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼ + ╾ALLOC10╼ ╾ALLOC11╼ │ ╾──────╼╾──────╼ } error: aborting due to 6 previous errors diff --git a/tests/ui/consts/const-eval/ub-incorrect-vtable.rs b/tests/ui/consts/const-eval/ub-incorrect-vtable.rs index 4bb30b75bc8..7d1927253f2 100644 --- a/tests/ui/consts/const-eval/ub-incorrect-vtable.rs +++ b/tests/ui/consts/const-eval/ub-incorrect-vtable.rs @@ -11,19 +11,19 @@ // errors are emitted instead of ICEs. // stderr-per-bitwidth -// normalize-stderr-test "alloc\d+" -> "allocN" + trait Trait {} const INVALID_VTABLE_ALIGNMENT: &dyn Trait = unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; -//~^ ERROR evaluation of constant value failed -//~| does not point to a vtable +//~^^ ERROR it is undefined behavior to use this value +//~| expected a vtable pointer const INVALID_VTABLE_SIZE: &dyn Trait = unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; -//~^ ERROR evaluation of constant value failed -//~| does not point to a vtable +//~^^ ERROR it is undefined behavior to use this value +//~| expected a vtable pointer #[repr(transparent)] struct W<T>(T); diff --git a/tests/ui/consts/const-eval/ub-nonnull.rs b/tests/ui/consts/const-eval/ub-nonnull.rs index a64b3a74cf6..fe4ec4d23d0 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.rs +++ b/tests/ui/consts/const-eval/ub-nonnull.rs @@ -1,6 +1,6 @@ // Strip out raw byte dumps to make comparison platform-independent: // normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" -// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" +// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" #![feature(rustc_attrs, ptr_metadata)] #![allow(invalid_value)] // make sure we cannot allow away the errors tested here diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr index 96164870804..7822306b654 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.stderr +++ b/tests/ui/consts/const-eval/ub-nonnull.stderr @@ -10,10 +10,10 @@ LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) }; } error[E0080]: evaluation of constant value failed - --> $DIR/ub-nonnull.rs:20:30 + --> $DIR/ub-nonnull.rs:20:29 | LL | let out_of_bounds_ptr = &ptr[255]; - | ^^^^^^^^ dereferencing pointer failed: alloc11 has size 1, so pointer to 256 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC1 has size 1, so pointer to 255 bytes starting at offset 0 is out-of-bounds error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:24:1 diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.rs b/tests/ui/consts/const-eval/ub-ref-ptr.rs index a5d2ea01486..08d4dce4d17 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.rs +++ b/tests/ui/consts/const-eval/ub-ref-ptr.rs @@ -1,7 +1,7 @@ // ignore-tidy-linelength // Strip out raw byte dumps to make comparison platform-independent: // normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" -// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" +// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" #![allow(invalid_value)] use std::mem; diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr index 6d5c36cea7d..c608bad2a47 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr @@ -141,7 +141,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref-ptr.rs:59:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc39, but expected a function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC2, but expected a function pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -151,7 +151,7 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | - = note: accessing memory with alignment 1, but alignment 4 is required + = note: accessing memory based on pointer with alignment 1, but alignment 4 is required | note: inside `std::ptr::read::<u32>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/tests/ui/consts/const-eval/ub-upvars.32bit.stderr b/tests/ui/consts/const-eval/ub-upvars.32bit.stderr index f7898e55ee2..353a9b78224 100644 --- a/tests/ui/consts/const-eval/ub-upvars.32bit.stderr +++ b/tests/ui/consts/const-eval/ub-upvars.32bit.stderr @@ -6,7 +6,7 @@ LL | const BAD_UPVAR: &dyn FnOnce() = &{ | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - ╾─alloc3──╼ ╾─alloc4──╼ │ ╾──╼╾──╼ + ╾ALLOC0╼ ╾ALLOC1╼ │ ╾──╼╾──╼ } error: aborting due to previous error diff --git a/tests/ui/consts/const-eval/ub-upvars.64bit.stderr b/tests/ui/consts/const-eval/ub-upvars.64bit.stderr index 60432380e13..097f6b049dc 100644 --- a/tests/ui/consts/const-eval/ub-upvars.64bit.stderr +++ b/tests/ui/consts/const-eval/ub-upvars.64bit.stderr @@ -6,7 +6,7 @@ LL | const BAD_UPVAR: &dyn FnOnce() = &{ | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾───────alloc3────────╼ ╾───────alloc4────────╼ │ ╾──────╼╾──────╼ + ╾ALLOC0╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼ } error: aborting due to previous error diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.rs b/tests/ui/consts/const-eval/ub-wide-ptr.rs index a765dc71273..dc8d4c640c2 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.rs +++ b/tests/ui/consts/const-eval/ub-wide-ptr.rs @@ -5,11 +5,11 @@ use std::mem; // Strip out raw byte dumps to make comparison platform-independent: // normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" -// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" +// normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" // normalize-stderr-test "offset \d+" -> "offset N" -// normalize-stderr-test "alloc\d+" -> "allocN" // normalize-stderr-test "size \d+" -> "size N" + /// A newtype wrapper to prevent MIR generation from inserting reborrows that would affect the error /// message. #[repr(transparent)] @@ -122,14 +122,14 @@ const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4u //~^ ERROR it is undefined behavior to use this value //~| expected a vtable const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; -//~^ ERROR evaluation of constant value failed -//~| does not point to a vtable +//~^ ERROR it is undefined behavior to use this value +//~| expected a vtable const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; -//~^ ERROR evaluation of constant value failed -//~| does not point to a vtable +//~^ ERROR it is undefined behavior to use this value +//~| expected a vtable const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; -//~^ ERROR evaluation of constant value failed -//~| does not point to a vtable +//~^ ERROR it is undefined behavior to use this value +//~| expected a vtable const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; //~^ ERROR it is undefined behavior to use this value //~| expected a vtable @@ -148,12 +148,12 @@ const RAW_TRAIT_OBJ_CONTENT_INVALID: *const dyn Trait = unsafe { mem::transmute: // Const eval fails for these, so they need to be statics to error. static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe { +//~^ ERROR it is undefined behavior to use this value mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) - //~^ ERROR could not evaluate static initializer }; static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe { +//~^ ERROR it is undefined behavior to use this value mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) - //~^ ERROR could not evaluate static initializer }; fn main() {} diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr index d8add67fac1..b203794858a 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr @@ -189,7 +189,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:113:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC12, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -200,7 +200,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:117:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC14, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -218,29 +218,44 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u HEX_DUMP } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:124:57 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:124:1 | LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC17, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:127:57 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:127:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC19, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } -error[E0080]: evaluation of constant value failed - --> $DIR/ub-wide-ptr.rs:130:56 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:130:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC21, but expected a vtable pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { + HEX_DUMP + } error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:133:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC23, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { @@ -273,24 +288,34 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:145:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC28, but expected a vtable pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) { HEX_DUMP } -error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:151:5 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:150:1 + | +LL | static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer | -LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) + = 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]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:155:5 +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:154:1 + | +LL | static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC31, but expected a vtable pointer | -LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable + = 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 29 previous errors diff --git a/tests/ui/consts/const-eval/unused-broken-const-late.rs b/tests/ui/consts/const-eval/unused-broken-const-late.rs new file mode 100644 index 00000000000..a6528ec5fd6 --- /dev/null +++ b/tests/ui/consts/const-eval/unused-broken-const-late.rs @@ -0,0 +1,20 @@ +// build-fail +// compile-flags: -O +//! Make sure we detect erroneous constants post-monomorphization even when they are unused. This is +//! crucial, people rely on it for soundness. (https://github.com/rust-lang/rust/issues/112090) + +struct PrintName<T>(T); +impl<T> PrintName<T> { + const VOID: () = panic!(); //~ERROR evaluation of `PrintName::<i32>::VOID` failed +} + +fn no_codegen<T>() { + // Any function that is called is guaranteed to have all consts that syntactically + // appear in its body evaluated, even if they only appear in dead code. + if false { + let _ = PrintName::<T>::VOID; + } +} +pub fn main() { + no_codegen::<i32>(); +} diff --git a/tests/ui/consts/const-eval/unused-broken-const-late.stderr b/tests/ui/consts/const-eval/unused-broken-const-late.stderr new file mode 100644 index 00000000000..cdb70a69dfd --- /dev/null +++ b/tests/ui/consts/const-eval/unused-broken-const-late.stderr @@ -0,0 +1,11 @@ +error[E0080]: evaluation of `PrintName::<i32>::VOID` failed + --> $DIR/unused-broken-const-late.rs:8:22 + | +LL | const VOID: () = panic!(); + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/unused-broken-const-late.rs:8:22 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.32bit.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.32bit.stderr new file mode 100644 index 00000000000..33d4fec7016 --- /dev/null +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.32bit.stderr @@ -0,0 +1,20 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/mut_ref_in_final_dynamic_check.rs:17:1 + | +LL | const A: Option<&mut i32> = helper(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0: encountered mutable reference in a `const` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 4, align: 4) { + 2a 00 00 00 │ *... + } + +error: encountered dangling pointer in final constant + --> $DIR/mut_ref_in_final_dynamic_check.rs:24:1 + | +LL | const B: Option<&mut i32> = helper2(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.64bit.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.64bit.stderr new file mode 100644 index 00000000000..9eb2675856f --- /dev/null +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.64bit.stderr @@ -0,0 +1,20 @@ +error[E0080]: it is undefined behavior to use this value + --> $DIR/mut_ref_in_final_dynamic_check.rs:17:1 + | +LL | const A: Option<&mut i32> = helper(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<enum-variant(Some)>.0: encountered mutable reference in a `const` + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + = note: the raw bytes of the constant (size: 8, align: 8) { + 2a 00 00 00 00 00 00 00 │ *....... + } + +error: encountered dangling pointer in final constant + --> $DIR/mut_ref_in_final_dynamic_check.rs:24:1 + | +LL | const B: Option<&mut i32> = helper2(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs index 074beaab2c4..22e7a74e5fb 100644 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs +++ b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs @@ -1,3 +1,4 @@ +// stderr-per-bitwidth #![feature(const_mut_refs)] #![feature(raw_ref_op)] @@ -9,17 +10,15 @@ const fn helper() -> Option<&'static mut i32> { unsafe { // Undefined behaviour (integer as pointer), who doesn't love tests like this. - // This code never gets executed, because the static checks fail before that. - Some(&mut *(42 as *mut i32)) //~ ERROR evaluation of constant value failed - //~| 0x2a[noalloc] is a dangling pointer + Some(&mut *(42 as *mut i32)) } } // The error is an evaluation error and not a validation error, so the error is reported // directly at the site where it occurs. -const A: Option<&mut i32> = helper(); +const A: Option<&mut i32> = helper(); //~ ERROR it is undefined behavior to use this value +//~^ encountered mutable reference in a `const` const fn helper2() -> Option<&'static mut i32> { unsafe { // Undefined behaviour (dangling pointer), who doesn't love tests like this. - // This code never gets executed, because the static checks fail before that. Some(&mut *(&mut 42 as *mut i32)) } } const B: Option<&mut i32> = helper2(); //~ ERROR encountered dangling pointer in final constant diff --git a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr b/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr deleted file mode 100644 index 6e110dbdd64..00000000000 --- a/tests/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr +++ /dev/null @@ -1,26 +0,0 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/mut_ref_in_final_dynamic_check.rs:13:10 - | -LL | Some(&mut *(42 as *mut i32)) - | ^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0x2a[noalloc] is a dangling pointer (it has no provenance) - | -note: inside `helper` - --> $DIR/mut_ref_in_final_dynamic_check.rs:13:10 - | -LL | Some(&mut *(42 as *mut i32)) - | ^^^^^^^^^^^^^^^^^^^^^^ -note: inside `A` - --> $DIR/mut_ref_in_final_dynamic_check.rs:18:29 - | -LL | const A: Option<&mut i32> = helper(); - | ^^^^^^^^ - -error: encountered dangling pointer in final constant - --> $DIR/mut_ref_in_final_dynamic_check.rs:25:1 - | -LL | const B: Option<&mut i32> = helper2(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-points-to-static.32bit.stderr b/tests/ui/consts/const-points-to-static.32bit.stderr index c7a435a1ee3..12cc7fbb1fc 100644 --- a/tests/ui/consts/const-points-to-static.32bit.stderr +++ b/tests/ui/consts/const-points-to-static.32bit.stderr @@ -6,7 +6,7 @@ LL | const TEST: &u8 = &MY_STATIC; | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - ╾─alloc1──╼ │ ╾──╼ + ╾ALLOC0╼ │ ╾──╼ } warning: skipping const checks diff --git a/tests/ui/consts/const-points-to-static.64bit.stderr b/tests/ui/consts/const-points-to-static.64bit.stderr index 4d5b8eac541..86506e6ca01 100644 --- a/tests/ui/consts/const-points-to-static.64bit.stderr +++ b/tests/ui/consts/const-points-to-static.64bit.stderr @@ -6,7 +6,7 @@ LL | const TEST: &u8 = &MY_STATIC; | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { - ╾───────alloc1────────╼ │ ╾──────╼ + ╾ALLOC0╼ │ ╾──────╼ } warning: skipping const checks diff --git a/tests/ui/consts/const_in_pattern/issue-78057.rs b/tests/ui/consts/const_in_pattern/issue-78057.rs index 69cf8404da1..88b5d68cb60 100644 --- a/tests/ui/consts/const_in_pattern/issue-78057.rs +++ b/tests/ui/consts/const_in_pattern/issue-78057.rs @@ -12,6 +12,5 @@ fn main() { FOO => {}, //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => {} - //~^ ERROR unreachable pattern } } diff --git a/tests/ui/consts/const_in_pattern/issue-78057.stderr b/tests/ui/consts/const_in_pattern/issue-78057.stderr index df155bdb625..5ec68719a97 100644 --- a/tests/ui/consts/const_in_pattern/issue-78057.stderr +++ b/tests/ui/consts/const_in_pattern/issue-78057.stderr @@ -7,20 +7,5 @@ LL | FOO => {}, = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details -error: unreachable pattern - --> $DIR/issue-78057.rs:14:9 - | -LL | FOO => {}, - | --- matches any value -LL | -LL | _ => {} - | ^ unreachable pattern - | -note: the lint level is defined here - --> $DIR/issue-78057.rs:1:9 - | -LL | #![deny(unreachable_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/tests/ui/consts/copy-intrinsic.stderr b/tests/ui/consts/copy-intrinsic.stderr index be41c2db398..0e4e6a6ad6c 100644 --- a/tests/ui/consts/copy-intrinsic.stderr +++ b/tests/ui/consts/copy-intrinsic.stderr @@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed --> $DIR/copy-intrinsic.rs:27:5 | LL | copy_nonoverlapping(0x100 as *const i32, dangle, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: alloc5 has size 4, so pointer at offset 40 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC0 has size 4, so pointer at offset 40 is out-of-bounds error[E0080]: evaluation of constant value failed --> $DIR/copy-intrinsic.rs:34:5 | LL | copy_nonoverlapping(dangle, 0x100 as *mut i32, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: alloc7 has size 4, so pointer at offset 40 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC1 has size 4, so pointer at offset 40 is out-of-bounds error[E0080]: evaluation of constant value failed --> $DIR/copy-intrinsic.rs:41:5 diff --git a/tests/ui/consts/effect_param.rs b/tests/ui/consts/effect_param.rs new file mode 100644 index 00000000000..f11ec739fce --- /dev/null +++ b/tests/ui/consts/effect_param.rs @@ -0,0 +1,11 @@ +//! Ensure we don't allow accessing const effect parameters from stable Rust. + +fn main() { + i8::checked_sub::<true>(42, 43); + //~^ ERROR: method takes 0 generic arguments but 1 generic argument was supplied +} + +const FOO: () = { + i8::checked_sub::<false>(42, 43); + //~^ ERROR: method takes 0 generic arguments but 1 generic argument was supplied +}; diff --git a/tests/ui/consts/effect_param.stderr b/tests/ui/consts/effect_param.stderr new file mode 100644 index 00000000000..f8c4bfc02e5 --- /dev/null +++ b/tests/ui/consts/effect_param.stderr @@ -0,0 +1,19 @@ +error[E0107]: method takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/effect_param.rs:9:9 + | +LL | i8::checked_sub::<false>(42, 43); + | ^^^^^^^^^^^--------- help: remove these generics + | | + | expected 0 generic arguments + +error[E0107]: method takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/effect_param.rs:4:9 + | +LL | i8::checked_sub::<true>(42, 43); + | ^^^^^^^^^^^-------- help: remove these generics + | | + | expected 0 generic arguments + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/consts/extra-const-ub/detect-extra-ub.rs b/tests/ui/consts/extra-const-ub/detect-extra-ub.rs index 37b37e9659e..15c06908447 100644 --- a/tests/ui/consts/extra-const-ub/detect-extra-ub.rs +++ b/tests/ui/consts/extra-const-ub/detect-extra-ub.rs @@ -88,4 +88,15 @@ const PARTIAL_POINTER: () = unsafe { const VALID_ENUM1: E = { let e = E::A; e }; const VALID_ENUM2: Result<&'static [u8], ()> = { let e = Err(()); e }; +// Htting the (non-integer) array code in validation with an immediate local. +const VALID_ARRAY: [Option<i32>; 0] = { let e = [None; 0]; e }; + +// Detecting oversized references. +const OVERSIZED_REF: () = { unsafe { + let slice: *const [u8] = transmute((1usize, usize::MAX)); + let _val = &*slice; + //[with_flag]~^ ERROR: evaluation of constant value failed + //[with_flag]~| slice is bigger than largest supported object +} }; + fn main() {} diff --git a/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr b/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr index 4ee12d501e8..0100aafb6b7 100644 --- a/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr +++ b/tests/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr @@ -52,6 +52,12 @@ LL | let _val = *(&mem as *const Align as *const [*const u8; 2]); = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error: aborting due to 7 previous errors +error[E0080]: evaluation of constant value failed + --> $DIR/detect-extra-ub.rs:97:16 + | +LL | let _val = &*slice; + | ^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object + +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/invalid-union.32bit.stderr b/tests/ui/consts/invalid-union.32bit.stderr index 0c57751cbfa..32b67a13061 100644 --- a/tests/ui/consts/invalid-union.32bit.stderr +++ b/tests/ui/consts/invalid-union.32bit.stderr @@ -6,7 +6,7 @@ LL | fn main() { | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - ╾─alloc7──╼ │ ╾──╼ + ╾ALLOC0╼ │ ╾──╼ } note: erroneous constant encountered diff --git a/tests/ui/consts/invalid-union.64bit.stderr b/tests/ui/consts/invalid-union.64bit.stderr index 6c4d5882158..45f999eb23c 100644 --- a/tests/ui/consts/invalid-union.64bit.stderr +++ b/tests/ui/consts/invalid-union.64bit.stderr @@ -6,7 +6,7 @@ LL | fn main() { | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { - ╾───────alloc7────────╼ │ ╾──────╼ + ╾ALLOC0╼ │ ╾──────╼ } note: erroneous constant encountered diff --git a/tests/ui/consts/issue-63952.32bit.stderr b/tests/ui/consts/issue-63952.32bit.stderr index 755c7fb7d4d..5375ec1188a 100644 --- a/tests/ui/consts/issue-63952.32bit.stderr +++ b/tests/ui/consts/issue-63952.32bit.stderr @@ -6,7 +6,7 @@ LL | const SLICE_WAY_TOO_LONG: &[u8] = unsafe { | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 4) { - ╾─alloc4──╼ ff ff ff ff │ ╾──╼.... + ╾ALLOC0╼ ff ff ff ff │ ╾──╼.... } error: aborting due to previous error diff --git a/tests/ui/consts/issue-63952.64bit.stderr b/tests/ui/consts/issue-63952.64bit.stderr index abdb9a4f792..a6edbf9321b 100644 --- a/tests/ui/consts/issue-63952.64bit.stderr +++ b/tests/ui/consts/issue-63952.64bit.stderr @@ -6,7 +6,7 @@ LL | const SLICE_WAY_TOO_LONG: &[u8] = unsafe { | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾───────alloc4────────╼ ff ff ff ff ff ff ff ff │ ╾──────╼........ + ╾ALLOC0╼ ff ff ff ff ff ff ff ff │ ╾──────╼........ } error: aborting due to previous error diff --git a/tests/ui/consts/issue-79690.64bit.stderr b/tests/ui/consts/issue-79690.64bit.stderr index b8798a9755f..af59729d438 100644 --- a/tests/ui/consts/issue-79690.64bit.stderr +++ b/tests/ui/consts/issue-79690.64bit.stderr @@ -6,7 +6,7 @@ LL | const G: Fat = unsafe { Transmute { t: FOO }.u }; | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 16, align: 8) { - ╾───────alloc3────────╼ ╾───────alloc4────────╼ │ ╾──────╼╾──────╼ + ╾ALLOC0╼ ╾ALLOC1╼ │ ╾──────╼╾──────╼ } error: aborting due to previous error diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr index a6f467b9ef4..4a3344a5b04 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr @@ -24,7 +24,7 @@ LL | const REF_INTERIOR_MUT: &usize = { | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - ╾─alloc4──╼ │ ╾──╼ + ╾ALLOC0╼ │ ╾──╼ } error[E0080]: it is undefined behavior to use this value @@ -35,7 +35,7 @@ LL | const READ_IMMUT: &usize = { | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - ╾─alloc5──╼ │ ╾──╼ + ╾ALLOC1╼ │ ╾──╼ } warning: skipping const checks diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr index cfaf31a6e0c..7573bfa39ec 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr @@ -24,7 +24,7 @@ LL | const REF_INTERIOR_MUT: &usize = { | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { - ╾───────alloc4────────╼ │ ╾──────╼ + ╾ALLOC0╼ │ ╾──────╼ } error[E0080]: it is undefined behavior to use this value @@ -35,7 +35,7 @@ LL | const READ_IMMUT: &usize = { | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { - ╾───────alloc5────────╼ │ ╾──────╼ + ╾ALLOC1╼ │ ╾──────╼ } warning: skipping const checks diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr index e3a0d93f09b..de59d743b17 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr @@ -6,7 +6,7 @@ LL | const SLICE_MUT: &[u8; 1] = { | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - ╾─alloc1──╼ │ ╾──╼ + ╾ALLOC0╼ │ ╾──╼ } error: could not evaluate constant pattern @@ -23,7 +23,7 @@ LL | const U8_MUT: &u8 = { | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - ╾─alloc1──╼ │ ╾──╼ + ╾ALLOC0╼ │ ╾──╼ } error: could not evaluate constant pattern diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr index a323e9a05f0..e62520ef6ad 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr @@ -6,7 +6,7 @@ LL | const SLICE_MUT: &[u8; 1] = { | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { - ╾───────alloc1────────╼ │ ╾──────╼ + ╾ALLOC0╼ │ ╾──────╼ } error: could not evaluate constant pattern @@ -23,7 +23,7 @@ LL | const U8_MUT: &u8 = { | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { - ╾───────alloc1────────╼ │ ╾──────╼ + ╾ALLOC0╼ │ ╾──────╼ } error: could not evaluate constant pattern diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr b/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr index 0ea1792409b..c9da91a9597 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr @@ -6,7 +6,7 @@ LL | const MUH: Meh = Meh { | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - ╾─alloc3──╼ │ ╾──╼ + ╾ALLOC0╼ │ ╾──╼ } error[E0080]: it is undefined behavior to use this value @@ -17,7 +17,7 @@ LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | = 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) { - ╾─alloc7──╼ ╾─alloc8──╼ │ ╾──╼╾──╼ + ╾ALLOC1╼ ╾ALLOC2╼ │ ╾──╼╾──╼ } error[E0080]: it is undefined behavior to use this value @@ -28,7 +28,7 @@ LL | const BLUNT: &mut i32 = &mut 42; | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 4, align: 4) { - ╾─alloc10─╼ │ ╾──╼ + ╾ALLOC3╼ │ ╾──╼ } warning: skipping const checks diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr b/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr index 67959d25634..71be616b7ed 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr @@ -6,7 +6,7 @@ LL | const MUH: Meh = Meh { | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { - ╾───────alloc3────────╼ │ ╾──────╼ + ╾ALLOC0╼ │ ╾──────╼ } error[E0080]: it is undefined behavior to use this value @@ -17,7 +17,7 @@ LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | = 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) { - ╾───────alloc7────────╼ ╾───────alloc8────────╼ │ ╾──────╼╾──────╼ + ╾ALLOC1╼ ╾ALLOC2╼ │ ╾──────╼╾──────╼ } error[E0080]: it is undefined behavior to use this value @@ -28,7 +28,7 @@ LL | const BLUNT: &mut i32 = &mut 42; | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: the raw bytes of the constant (size: 8, align: 8) { - ╾───────alloc10───────╼ │ ╾──────╼ + ╾ALLOC3╼ │ ╾──────╼ } warning: skipping const checks diff --git a/tests/ui/consts/missing_span_in_backtrace.rs b/tests/ui/consts/missing_span_in_backtrace.rs index dd2b81c5af2..1ac3777f5fe 100644 --- a/tests/ui/consts/missing_span_in_backtrace.rs +++ b/tests/ui/consts/missing_span_in_backtrace.rs @@ -1,5 +1,5 @@ // compile-flags: -Z ui-testing=no -// normalize-stderr-test "alloc[0-9]+" -> "ALLOC_ID" + #![feature(const_swap)] #![feature(const_mut_refs)] diff --git a/tests/ui/consts/missing_span_in_backtrace.stderr b/tests/ui/consts/missing_span_in_backtrace.stderr index fcfb9fbb3f8..6860cee4184 100644 --- a/tests/ui/consts/missing_span_in_backtrace.stderr +++ b/tests/ui/consts/missing_span_in_backtrace.stderr @@ -1,7 +1,7 @@ error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | - = note: unable to copy parts of a pointer from memory at ALLOC_ID + = note: unable to copy parts of a pointer from memory at ALLOC0 | note: inside `std::ptr::read::<MaybeUninit<MaybeUninit<u8>>>` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/tests/ui/consts/offset_from_ub.stderr b/tests/ui/consts/offset_from_ub.stderr index 97ff6efdd79..1ef727e5b0f 100644 --- a/tests/ui/consts/offset_from_ub.stderr +++ b/tests/ui/consts/offset_from_ub.stderr @@ -39,19 +39,19 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:53:14 | LL | unsafe { ptr_offset_from(end_ptr, start_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: alloc17 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: ALLOC0 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:62:14 | LL | unsafe { ptr_offset_from(start_ptr, end_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: alloc20 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: ALLOC1 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:70:14 | LL | unsafe { ptr_offset_from(end_ptr, end_ptr) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: alloc23 has size 4, so pointer at offset 10 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: ALLOC2 has size 4, so pointer at offset 10 is out-of-bounds error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:79:14 diff --git a/tests/ui/consts/offset_ub.rs b/tests/ui/consts/offset_ub.rs index 1b01e4fd147..db28a6c6a2b 100644 --- a/tests/ui/consts/offset_ub.rs +++ b/tests/ui/consts/offset_ub.rs @@ -1,6 +1,6 @@ use std::ptr; -// normalize-stderr-test "alloc\d+" -> "allocN" + // normalize-stderr-test "0x7f+" -> "0x7f..f" diff --git a/tests/ui/consts/offset_ub.stderr b/tests/ui/consts/offset_ub.stderr index c0c851df507..8bc59d50ee4 100644 --- a/tests/ui/consts/offset_ub.stderr +++ b/tests/ui/consts/offset_ub.stderr @@ -14,7 +14,7 @@ LL | pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: out-of-bounds pointer arithmetic: allocN has size 1, so pointer to 2 bytes starting at offset 0 is out-of-bounds + = note: out-of-bounds pointer arithmetic: ALLOC0 has size 1, so pointer to 2 bytes starting at offset 0 is out-of-bounds | note: inside `ptr::const_ptr::<impl *const u8>::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -27,7 +27,7 @@ LL | pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: out-of-bounds pointer arithmetic: allocN has size 100, so pointer to 101 bytes starting at offset 0 is out-of-bounds + = note: out-of-bounds pointer arithmetic: ALLOC1 has size 100, so pointer to 101 bytes starting at offset 0 is out-of-bounds | note: inside `ptr::const_ptr::<impl *const u8>::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -92,7 +92,7 @@ LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).of error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: out-of-bounds pointer arithmetic: allocN has size 1, so pointer to 2 bytes starting at offset -4 is out-of-bounds + = note: out-of-bounds pointer arithmetic: ALLOC2 has size 1, so pointer to 2 bytes starting at offset -4 is out-of-bounds | note: inside `ptr::const_ptr::<impl *const u8>::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -105,7 +105,7 @@ LL | pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_ error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: out-of-bounds pointer arithmetic: allocN has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds + = note: out-of-bounds pointer arithmetic: ALLOC3 has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds | note: inside `ptr::const_ptr::<impl *const u8>::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs new file mode 100644 index 00000000000..35307586391 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs @@ -0,0 +1,22 @@ +#![feature(diagnostic_namespace)] + +#[diagnostic::on_unimplemented( + //~^WARN malformed `on_unimplemented` attribute + //~|WARN malformed `on_unimplemented` attribute + if(Self = ()), + message = "not used yet", + label = "not used yet", + note = "not used yet" +)] +#[diagnostic::on_unimplemented(message = "fallback!!")] +#[diagnostic::on_unimplemented(label = "fallback label")] +#[diagnostic::on_unimplemented(note = "fallback note")] +#[diagnostic::on_unimplemented(message = "fallback2!!")] +trait Foo {} + +fn takes_foo(_: impl Foo) {} + +fn main() { + takes_foo(()); + //~^ERROR fallback!! +} diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr new file mode 100644 index 00000000000..6a83d8e39c6 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr @@ -0,0 +1,52 @@ +warning: malformed `on_unimplemented` attribute + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:3:1 + | +LL | / #[diagnostic::on_unimplemented( +LL | | +LL | | +LL | | if(Self = ()), +... | +LL | | note = "not used yet" +LL | | )] + | |__^ + | + = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default + +warning: malformed `on_unimplemented` attribute + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:3:1 + | +LL | / #[diagnostic::on_unimplemented( +LL | | +LL | | +LL | | if(Self = ()), +... | +LL | | note = "not used yet" +LL | | )] + | |__^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: fallback!! + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:20:15 + | +LL | takes_foo(()); + | --------- ^^ fallback label + | | + | required by a bound introduced by this call + | + = help: the trait `Foo` is not implemented for `()` + = note: fallback note +help: this trait has no implementations, consider adding one + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:1 + | +LL | trait Foo {} + | ^^^^^^^^^ +note: required by a bound in `takes_foo` + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:17:22 + | +LL | fn takes_foo(_: impl Foo) {} + | ^^^ required by this bound in `takes_foo` + +error: aborting due to previous error; 2 warnings emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/did_you_mean/bad-assoc-ty.stderr b/tests/ui/did_you_mean/bad-assoc-ty.stderr index efa6bb66824..5c0c7a0b94f 100644 --- a/tests/ui/did_you_mean/bad-assoc-ty.stderr +++ b/tests/ui/did_you_mean/bad-assoc-ty.stderr @@ -191,7 +191,7 @@ error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:33:10 | LL | type H = Fn(u8) -> (u8)::Output; - | ^^^^^^^^^^^^^^^^^^^^^^ help: use the fully-qualified path: `<(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output` + | ^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output` error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:39:19 diff --git a/tests/ui/error-codes/E0030-teach.stderr b/tests/ui/error-codes/E0030-teach.stderr index 3f1ad4af3a9..9435cb204bd 100644 --- a/tests/ui/error-codes/E0030-teach.stderr +++ b/tests/ui/error-codes/E0030-teach.stderr @@ -2,7 +2,7 @@ error[E0030]: lower range bound must be less than or equal to upper --> $DIR/E0030-teach.rs:5:9 | LL | 1000 ..= 5 => {} - | ^^^^ lower bound larger than upper bound + | ^^^^^^^^^^ lower bound larger than upper bound | = note: When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range. diff --git a/tests/ui/error-codes/E0030.stderr b/tests/ui/error-codes/E0030.stderr index db8161d8fd5..1aeca291678 100644 --- a/tests/ui/error-codes/E0030.stderr +++ b/tests/ui/error-codes/E0030.stderr @@ -2,7 +2,7 @@ error[E0030]: lower range bound must be less than or equal to upper --> $DIR/E0030.rs:3:9 | LL | 1000 ..= 5 => {} - | ^^^^ lower bound larger than upper bound + | ^^^^^^^^^^ lower bound larger than upper bound error: aborting due to previous error diff --git a/tests/ui/error-codes/E0034.stderr b/tests/ui/error-codes/E0034.stderr index e2962170265..da6f221881c 100644 --- a/tests/ui/error-codes/E0034.stderr +++ b/tests/ui/error-codes/E0034.stderr @@ -14,12 +14,10 @@ note: candidate #2 is defined in an impl of the trait `Trait2` for the type `Tes | LL | fn foo() {} | ^^^^^^^^ -help: disambiguate the associated function for candidate #1 +help: use fully-qualified syntax to disambiguate | LL | <Test as Trait1>::foo() | ~~~~~~~~~~~~~~~~~~ -help: disambiguate the associated function for candidate #2 - | LL | <Test as Trait2>::foo() | ~~~~~~~~~~~~~~~~~~ diff --git a/tests/ui/error-codes/E0221.stderr b/tests/ui/error-codes/E0221.stderr index 5414d77ad7c..e600acf7834 100644 --- a/tests/ui/error-codes/E0221.stderr +++ b/tests/ui/error-codes/E0221.stderr @@ -10,11 +10,11 @@ LL | fn do_something() { LL | let _: Self::A; | ^^^^^^^ ambiguous associated type `A` | -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | let _: <Self as Foo>::A; | ~~~~~~~~~~~~~~~ -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | let _: <Self as Bar>::A; | ~~~~~~~~~~~~~~~ @@ -29,7 +29,7 @@ LL | let _: Self::Err; | ^^^^^^^^^ ambiguous associated type `Err` | = note: associated type `Self` could derive from `FromStr` -help: use fully qualified syntax to disambiguate +help: use fully-qualified syntax to disambiguate | LL | let _: <Self as My>::Err; | ~~~~~~~~~~~~~~ diff --git a/tests/ui/error-codes/E0223.stderr b/tests/ui/error-codes/E0223.stderr index 42945e42f6e..1299ba5f50c 100644 --- a/tests/ui/error-codes/E0223.stderr +++ b/tests/ui/error-codes/E0223.stderr @@ -2,7 +2,7 @@ error[E0223]: ambiguous associated type --> $DIR/E0223.rs:8:14 | LL | let foo: MyTrait::X; - | ^^^^^^^^^^ help: use the fully-qualified path: `<MyStruct as MyTrait>::X` + | ^^^^^^^^^^ help: use fully-qualified syntax: `<MyStruct as MyTrait>::X` error: aborting due to previous error diff --git a/tests/ui/error-codes/E0396-fixed.stderr b/tests/ui/error-codes/E0396-fixed.stderr index 2efbd6989ad..e77b2ce9a22 100644 --- a/tests/ui/error-codes/E0396-fixed.stderr +++ b/tests/ui/error-codes/E0396-fixed.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/E0396-fixed.rs:5:28 | LL | const VALUE: u8 = unsafe { *REG_ADDR }; - | ^^^^^^^^^ dereferencing pointer failed: 0x5f3759df[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^ memory access failed: 0x5f3759df[noalloc] is a dangling pointer (it has no provenance) error: aborting due to previous error diff --git a/tests/ui/expr/malformed_closure/missing_block_in_fn_call.fixed b/tests/ui/expr/malformed_closure/missing_block_in_fn_call.fixed new file mode 100644 index 00000000000..b81515cda9a --- /dev/null +++ b/tests/ui/expr/malformed_closure/missing_block_in_fn_call.fixed @@ -0,0 +1,10 @@ +// run-rustfix +fn main() { + let _ = vec![1, 2, 3].into_iter().map(|x| { + let y = x; //~ ERROR expected expression, found `let` statement + y + }); + let _: () = foo(); //~ ERROR mismatched types +} + +fn foo() {} diff --git a/tests/ui/expr/malformed_closure/missing_block_in_fn_call.rs b/tests/ui/expr/malformed_closure/missing_block_in_fn_call.rs new file mode 100644 index 00000000000..e47ad562fb0 --- /dev/null +++ b/tests/ui/expr/malformed_closure/missing_block_in_fn_call.rs @@ -0,0 +1,10 @@ +// run-rustfix +fn main() { + let _ = vec![1, 2, 3].into_iter().map(|x| + let y = x; //~ ERROR expected expression, found `let` statement + y + ); + let _: () = foo; //~ ERROR mismatched types +} + +fn foo() {} diff --git a/tests/ui/expr/malformed_closure/missing_block_in_fn_call.stderr b/tests/ui/expr/malformed_closure/missing_block_in_fn_call.stderr new file mode 100644 index 00000000000..fbb7e0e4df5 --- /dev/null +++ b/tests/ui/expr/malformed_closure/missing_block_in_fn_call.stderr @@ -0,0 +1,38 @@ +error: expected expression, found `let` statement + --> $DIR/missing_block_in_fn_call.rs:4:9 + | +LL | let _ = vec![1, 2, 3].into_iter().map(|x| + | --- while parsing the body of this closure +LL | let y = x; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +help: you might have meant to open the body of the closure + | +LL ~ let _ = vec![1, 2, 3].into_iter().map(|x| { +LL | let y = x; +LL | y +LL ~ }); + | + +error[E0308]: mismatched types + --> $DIR/missing_block_in_fn_call.rs:7:17 + | +LL | let _: () = foo; + | -- ^^^ expected `()`, found fn item + | | + | expected due to this +... +LL | fn foo() {} + | -------- function `foo` defined here + | + = note: expected unit type `()` + found fn item `fn() {foo}` +help: use parentheses to call this function + | +LL | let _: () = foo(); + | ++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/expr/malformed_closure/missing_block_in_let_binding.rs b/tests/ui/expr/malformed_closure/missing_block_in_let_binding.rs new file mode 100644 index 00000000000..1ee215d150d --- /dev/null +++ b/tests/ui/expr/malformed_closure/missing_block_in_let_binding.rs @@ -0,0 +1,6 @@ +fn main() { + let x = |x| + let y = x; //~ ERROR expected expression, found `let` statement + let _ = () + (); + y +} diff --git a/tests/ui/expr/malformed_closure/missing_block_in_let_binding.stderr b/tests/ui/expr/malformed_closure/missing_block_in_let_binding.stderr new file mode 100644 index 00000000000..d4640fba96c --- /dev/null +++ b/tests/ui/expr/malformed_closure/missing_block_in_let_binding.stderr @@ -0,0 +1,16 @@ +error: expected expression, found `let` statement + --> $DIR/missing_block_in_let_binding.rs:3:9 + | +LL | let x = |x| + | --- while parsing the body of this closure +LL | let y = x; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +help: you might have meant to open the body of the closure + | +LL | let x = |x| { + | + + +error: aborting due to previous error + diff --git a/tests/ui/expr/malformed_closure/ruby_style_closure_parse_error.fixed b/tests/ui/expr/malformed_closure/ruby_style_closure_parse_error.fixed new file mode 100644 index 00000000000..8014dc87c08 --- /dev/null +++ b/tests/ui/expr/malformed_closure/ruby_style_closure_parse_error.fixed @@ -0,0 +1,9 @@ +// run-rustfix +fn main() { + let _ = vec![1, 2, 3].into_iter().map(|x| { + let y = x; //~ ERROR expected expression, found `let` statement + y + }); + let _: () = foo(); //~ ERROR mismatched types +} +fn foo() {} diff --git a/tests/ui/expr/malformed_closure/ruby_style_closure_parse_error.rs b/tests/ui/expr/malformed_closure/ruby_style_closure_parse_error.rs new file mode 100644 index 00000000000..9e4aca888ad --- /dev/null +++ b/tests/ui/expr/malformed_closure/ruby_style_closure_parse_error.rs @@ -0,0 +1,9 @@ +// run-rustfix +fn main() { + let _ = vec![1, 2, 3].into_iter().map({|x| + let y = x; //~ ERROR expected expression, found `let` statement + y + }); + let _: () = foo; //~ ERROR mismatched types +} +fn foo() {} diff --git a/tests/ui/expr/malformed_closure/ruby_style_closure_parse_error.stderr b/tests/ui/expr/malformed_closure/ruby_style_closure_parse_error.stderr new file mode 100644 index 00000000000..5fc48d73b14 --- /dev/null +++ b/tests/ui/expr/malformed_closure/ruby_style_closure_parse_error.stderr @@ -0,0 +1,36 @@ +error: expected expression, found `let` statement + --> $DIR/ruby_style_closure_parse_error.rs:4:9 + | +LL | let _ = vec![1, 2, 3].into_iter().map({|x| + | --- while parsing the body of this closure +LL | let y = x; + | ^^^ + | + = note: only supported directly in conditions of `if` and `while` expressions +help: you might have meant to open the body of the closure, instead of enclosing the closure in a block + | +LL - let _ = vec![1, 2, 3].into_iter().map({|x| +LL + let _ = vec![1, 2, 3].into_iter().map(|x| { + | + +error[E0308]: mismatched types + --> $DIR/ruby_style_closure_parse_error.rs:7:17 + | +LL | let _: () = foo; + | -- ^^^ expected `()`, found fn item + | | + | expected due to this +LL | } +LL | fn foo() {} + | -------- function `foo` defined here + | + = note: expected unit type `()` + found fn item `fn() {foo}` +help: use parentheses to call this function + | +LL | let _: () = foo(); + | ++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/feature-gates/doc-rust-logo.rs b/tests/ui/feature-gates/doc-rust-logo.rs new file mode 100644 index 00000000000..e6a58512944 --- /dev/null +++ b/tests/ui/feature-gates/doc-rust-logo.rs @@ -0,0 +1,5 @@ +#![doc(rust_logo)] +//~^ ERROR the `#[doc(rust_logo)]` attribute is used for Rust branding +//! This is not an official rust crate + +fn main() {} diff --git a/tests/ui/feature-gates/doc-rust-logo.stderr b/tests/ui/feature-gates/doc-rust-logo.stderr new file mode 100644 index 00000000000..ff5855290d4 --- /dev/null +++ b/tests/ui/feature-gates/doc-rust-logo.stderr @@ -0,0 +1,12 @@ +error[E0658]: the `#[doc(rust_logo)]` attribute is used for Rust branding + --> $DIR/doc-rust-logo.rs:1:8 + | +LL | #![doc(rust_logo)] + | ^^^^^^^^^ + | + = note: see issue #90418 <https://github.com/rust-lang/rust/issues/90418> for more information + = help: add `#![feature(rustdoc_internals)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.rs b/tests/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.rs deleted file mode 100644 index a8d6365ca79..00000000000 --- a/tests/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.rs +++ /dev/null @@ -1,18 +0,0 @@ -// edition:2021 - -// async_fn_in_trait is not enough to allow use of RPITIT -#![allow(incomplete_features)] -#![feature(async_fn_in_trait)] - -trait Foo { - fn bar() -> impl Sized; //~ ERROR `impl Trait` only allowed in function and inherent method argument and return types, not in trait method return - fn baz() -> Box<impl std::fmt::Display>; //~ ERROR `impl Trait` only allowed in function and inherent method argument and return types, not in trait method return -} - -// Both return_position_impl_trait_in_trait and async_fn_in_trait are required for this (see also -// feature-gate-async_fn_in_trait.rs) -trait AsyncFoo { - async fn bar() -> impl Sized; //~ ERROR `impl Trait` only allowed in function and inherent method argument and return types, not in trait method return -} - -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.stderr b/tests/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.stderr deleted file mode 100644 index 86f138fabdb..00000000000 --- a/tests/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in trait method return types - --> $DIR/feature-gate-return_position_impl_trait_in_trait.rs:8:17 - | -LL | fn bar() -> impl Sized; - | ^^^^^^^^^^ - | - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable - -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in trait method return types - --> $DIR/feature-gate-return_position_impl_trait_in_trait.rs:9:21 - | -LL | fn baz() -> Box<impl std::fmt::Display>; - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable - -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in trait method return types - --> $DIR/feature-gate-return_position_impl_trait_in_trait.rs:15:23 - | -LL | async fn bar() -> impl Sized; - | ^^^^^^^^^^ - | - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr index f6230b76463..1bdb2574ead 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.cfg.stderr @@ -1,5 +1,5 @@ error[E0658]: return type notation is experimental - --> $DIR/feature-gate-return_type_notation.rs:15:17 + --> $DIR/feature-gate-return_type_notation.rs:14:17 | LL | fn foo<T: Trait<m(): Send>>() {} | ^^^^^^^^^ @@ -8,7 +8,7 @@ LL | fn foo<T: Trait<m(): Send>>() {} = help: add `#![feature(return_type_notation)]` to the crate attributes to enable error: parenthesized generic arguments cannot be used in associated type constraints - --> $DIR/feature-gate-return_type_notation.rs:15:17 + --> $DIR/feature-gate-return_type_notation.rs:14:17 | LL | fn foo<T: Trait<m(): Send>>() {} | ^-- @@ -16,7 +16,7 @@ LL | fn foo<T: Trait<m(): Send>>() {} | help: remove these parentheses error[E0220]: associated type `m` not found for `Trait` - --> $DIR/feature-gate-return_type_notation.rs:15:17 + --> $DIR/feature-gate-return_type_notation.rs:14:17 | LL | fn foo<T: Trait<m(): Send>>() {} | ^ associated type `m` not found diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr b/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr index c7f52d7cddc..dd6ebb61038 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.no.stderr @@ -1,5 +1,5 @@ warning: return type notation is experimental - --> $DIR/feature-gate-return_type_notation.rs:15:17 + --> $DIR/feature-gate-return_type_notation.rs:14:17 | LL | fn foo<T: Trait<m(): Send>>() {} | ^^^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-return_type_notation.rs b/tests/ui/feature-gates/feature-gate-return_type_notation.rs index c0c285cef3c..86e2c48e188 100644 --- a/tests/ui/feature-gates/feature-gate-return_type_notation.rs +++ b/tests/ui/feature-gates/feature-gate-return_type_notation.rs @@ -4,7 +4,6 @@ // [no] check-pass // Since we're not adding new syntax, `cfg`'d out RTN must pass. -#![feature(async_fn_in_trait)] trait Trait { #[allow(async_fn_in_trait)] diff --git a/tests/ui/hygiene/panic-location.run.stderr b/tests/ui/hygiene/panic-location.run.stderr index 5ed0d9fcf1e..1fd61084130 100644 --- a/tests/ui/hygiene/panic-location.run.stderr +++ b/tests/ui/hygiene/panic-location.run.stderr @@ -1,3 +1,3 @@ -thread 'main' panicked at library/alloc/src/raw_vec.rs:534:5: +thread 'main' panicked at library/alloc/src/raw_vec.rs:535:5: capacity overflow note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.rs b/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.rs new file mode 100644 index 00000000000..6863a3c73ba --- /dev/null +++ b/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.rs @@ -0,0 +1,25 @@ +// This test should never pass! + +#![feature(type_alias_impl_trait)] + +trait Captures<'a> {} +impl<T> Captures<'_> for T {} + +struct MyTy<'a, 'b>(Option<*mut &'a &'b ()>); +unsafe impl Send for MyTy<'_, 'static> {} + +fn step1<'a, 'b: 'a>() -> impl Sized + Captures<'b> + 'a { + MyTy::<'a, 'b>(None) +} + +fn step2<'a, 'b: 'a>() -> impl Sized + 'a { + step1::<'a, 'b>() + //~^ ERROR hidden type for `impl Sized + 'a` captures lifetime that does not appear in bounds +} + +fn step3<'a, 'b: 'a>() -> impl Send + 'a { + step2::<'a, 'b>() + // This should not be Send unless `'b: 'static` +} + +fn main() {} diff --git a/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.stderr b/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.stderr new file mode 100644 index 00000000000..168a5aa18ec --- /dev/null +++ b/tests/ui/impl-trait/alias-liveness/rpit-hidden-erased-unsoundness.stderr @@ -0,0 +1,18 @@ +error[E0700]: hidden type for `impl Sized + 'a` captures lifetime that does not appear in bounds + --> $DIR/rpit-hidden-erased-unsoundness.rs:16:5 + | +LL | fn step2<'a, 'b: 'a>() -> impl Sized + 'a { + | -- --------------- opaque type defined here + | | + | hidden type `impl Captures<'b> + 'a` captures the lifetime `'b` as defined here +LL | step1::<'a, 'b>() + | ^^^^^^^^^^^^^^^^^ + | +help: to declare that `impl Sized + 'a` captures `'b`, you can add an explicit `'b` lifetime bound + | +LL | fn step2<'a, 'b: 'a>() -> impl Sized + 'a + 'b { + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.rs b/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.rs new file mode 100644 index 00000000000..4de2ffbb808 --- /dev/null +++ b/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.rs @@ -0,0 +1,32 @@ +// This test should never pass! + +use std::cell::RefCell; +use std::rc::Rc; + +trait Swap: Sized { + fn swap(self, other: Self); +} + +impl<T> Swap for Rc<RefCell<T>> { + fn swap(self, other: Self) { + <RefCell<T>>::swap(&self, &other); + } +} + +fn hide<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a { + x + //~^ ERROR hidden type for `impl Swap + 'a` captures lifetime that does not appear in bounds +} + +fn dangle() -> &'static [i32; 3] { + let long = Rc::new(RefCell::new(&[4, 5, 6])); + let x = [1, 2, 3]; + let short = Rc::new(RefCell::new(&x)); + hide(long.clone()).swap(hide(short)); + let res: &'static [i32; 3] = *long.borrow(); + res +} + +fn main() { + println!("{:?}", dangle()); +} diff --git a/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.stderr b/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.stderr new file mode 100644 index 00000000000..cabba4bafaf --- /dev/null +++ b/tests/ui/impl-trait/alias-liveness/rpit-hide-lifetime-for-swap.stderr @@ -0,0 +1,18 @@ +error[E0700]: hidden type for `impl Swap + 'a` captures lifetime that does not appear in bounds + --> $DIR/rpit-hide-lifetime-for-swap.rs:17:5 + | +LL | fn hide<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a { + | -- -------------- opaque type defined here + | | + | hidden type `Rc<RefCell<&'b T>>` captures the lifetime `'b` as defined here +LL | x + | ^ + | +help: to declare that `impl Swap + 'a` captures `'b`, you can add an explicit `'b` lifetime bound + | +LL | fn hide<'a, 'b: 'a, T: 'static>(x: Rc<RefCell<&'b T>>) -> impl Swap + 'a + 'b { + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness.rs b/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness.rs new file mode 100644 index 00000000000..40efd941e33 --- /dev/null +++ b/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness.rs @@ -0,0 +1,28 @@ +// This test should never pass! + +#![feature(type_alias_impl_trait)] + +trait Captures<'a> {} +impl<T> Captures<'_> for T {} + +struct MyTy<'a, 'b>(Option<*mut &'a &'b ()>); +unsafe impl Send for MyTy<'_, 'static> {} + +fn step1<'a, 'b: 'a>() -> impl Sized + Captures<'b> + 'a { + MyTy::<'a, 'b>(None) +} + +mod tait { + type Tait<'a> = impl Sized + 'a; + pub(super) fn step2<'a, 'b: 'a>() -> Tait<'a> { + super::step1::<'a, 'b>() + //~^ ERROR hidden type for `Tait<'a>` captures lifetime that does not appear in bounds + } +} + +fn step3<'a, 'b: 'a>() -> impl Send + 'a { + tait::step2::<'a, 'b>() + // This should not be Send unless `'b: 'static` +} + +fn main() {} diff --git a/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness.stderr b/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness.stderr new file mode 100644 index 00000000000..baeec6d5892 --- /dev/null +++ b/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness.stderr @@ -0,0 +1,13 @@ +error[E0700]: hidden type for `Tait<'a>` captures lifetime that does not appear in bounds + --> $DIR/tait-hidden-erased-unsoundness.rs:18:9 + | +LL | type Tait<'a> = impl Sized + 'a; + | --------------- opaque type defined here +LL | pub(super) fn step2<'a, 'b: 'a>() -> Tait<'a> { + | -- hidden type `impl Captures<'b> + 'a` captures the lifetime `'b` as defined here +LL | super::step1::<'a, 'b>() + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/impl-trait/async_scope_creep.rs b/tests/ui/impl-trait/async_scope_creep.rs index 9a8831a299e..60975439a33 100644 --- a/tests/ui/impl-trait/async_scope_creep.rs +++ b/tests/ui/impl-trait/async_scope_creep.rs @@ -1,6 +1,6 @@ #![feature(type_alias_impl_trait)] // edition:2021 -//[rpit] check-pass +// check-pass // revisions: tait rpit struct Pending {} @@ -23,7 +23,7 @@ impl Pending { #[cfg(tait)] fn read_fut(&mut self) -> OpeningReadFuture<'_> { - self.read() //[tait]~ ERROR: cannot satisfy `impl AsyncRead + 'a == PendingReader<'a>` + self.read() } #[cfg(rpit)] diff --git a/tests/ui/impl-trait/async_scope_creep.tait.stderr b/tests/ui/impl-trait/async_scope_creep.tait.stderr deleted file mode 100644 index 165096a0574..00000000000 --- a/tests/ui/impl-trait/async_scope_creep.tait.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0284]: type annotations needed: cannot satisfy `impl AsyncRead + 'a == PendingReader<'a>` - --> $DIR/async_scope_creep.rs:26:9 - | -LL | self.read() - | ^^^^^^^^^^^ cannot satisfy `impl AsyncRead + 'a == PendingReader<'a>` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/impl-trait/auto-trait.stderr b/tests/ui/impl-trait/auto-trait-coherence.next.stderr index 81009413c9a..7833ac688ba 100644 --- a/tests/ui/impl-trait/auto-trait.stderr +++ b/tests/ui/impl-trait/auto-trait-coherence.next.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>` - --> $DIR/auto-trait.rs:21:1 + --> $DIR/auto-trait-coherence.rs:24:1 | LL | impl<T: Send> AnotherTrait for T {} | -------------------------------- first implementation here diff --git a/tests/ui/impl-trait/auto-trait-coherence.old.stderr b/tests/ui/impl-trait/auto-trait-coherence.old.stderr new file mode 100644 index 00000000000..7833ac688ba --- /dev/null +++ b/tests/ui/impl-trait/auto-trait-coherence.old.stderr @@ -0,0 +1,12 @@ +error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>` + --> $DIR/auto-trait-coherence.rs:24:1 + | +LL | impl<T: Send> AnotherTrait for T {} + | -------------------------------- first implementation here +... +LL | impl AnotherTrait for D<OpaqueType> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/impl-trait/auto-trait.rs b/tests/ui/impl-trait/auto-trait-coherence.rs index 35994e4a5ba..a5cd01a87ff 100644 --- a/tests/ui/impl-trait/auto-trait.rs +++ b/tests/ui/impl-trait/auto-trait-coherence.rs @@ -1,3 +1,6 @@ +// revisions: old next +//[next] compile-flags: -Ztrait-solver=next + // Tests that type alias impls traits do not leak auto-traits for // the purposes of coherence checking #![feature(type_alias_impl_trait)] diff --git a/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr b/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr new file mode 100644 index 00000000000..83791f0d3af --- /dev/null +++ b/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr @@ -0,0 +1,29 @@ +error: internal compiler error: no errors encountered even though `delay_span_bug` issued + +error: internal compiler error: {OpaqueTypeKey { def_id: DefId(rpit::{opaque#0}), args: [] }: OpaqueTypeDecl { hidden_type: OpaqueHiddenType { span: no-location (#0), ty: Alias(Opaque, AliasTy { args: [], def_id: DefId(foo::{opaque#0}) }) } }} + | + = + + +error: internal compiler error: error performing ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: ProvePredicate { predicate: Binder { value: ProjectionPredicate(AliasTy { args: [FnDef(DefId(rpit), []), ()], def_id: DefId(ops::function::FnOnce::Output) }, Term::Ty(Alias(Opaque, AliasTy { args: [], def_id: DefId(foo::{opaque#0}) }))), bound_vars: [] } } } + --> $DIR/equality-in-canonical-query.rs:19:5 + | +LL | same_output(foo, rpit); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + + --> $DIR/equality-in-canonical-query.rs:19:5 + | +LL | same_output(foo, rpit); + | ^^^^^^^^^^^^^^^^^^^^^^ + + + + + + + +query stack during panic: +end of query stack +error: aborting due to 3 previous errors + diff --git a/tests/ui/impl-trait/equality-in-canonical-query.rs b/tests/ui/impl-trait/equality-in-canonical-query.rs new file mode 100644 index 00000000000..672b1eeeab6 --- /dev/null +++ b/tests/ui/impl-trait/equality-in-canonical-query.rs @@ -0,0 +1,23 @@ +// issue: #116877 +// revisions: sized clone +//[sized] check-pass + +//[clone] known-bug: #108498 +//[clone] failure-status: 101 +//[clone] normalize-stderr-test: "DefId\(.*?\]::" -> "DefId(" +//[clone] normalize-stderr-test: "(?m)note: .*$" -> "" +//[clone] normalize-stderr-test: "(?m)^ *\d+: .*\n" -> "" +//[clone] normalize-stderr-test: "(?m)^ *at .*\n" -> "" + +#[cfg(sized)] fn rpit() -> impl Sized {} +#[cfg(clone)] fn rpit() -> impl Clone {} + +fn same_output<Out>(_: impl Fn() -> Out, _: impl Fn() -> Out) {} + +pub fn foo() -> impl Sized { + same_output(rpit, foo); + same_output(foo, rpit); + rpit() +} + +fn main () {} diff --git a/tests/ui/impl-trait/in-trait/anonymize-binders-for-refine.rs b/tests/ui/impl-trait/in-trait/anonymize-binders-for-refine.rs index e62662f2f07..09fbef2ec07 100644 --- a/tests/ui/impl-trait/in-trait/anonymize-binders-for-refine.rs +++ b/tests/ui/impl-trait/in-trait/anonymize-binders-for-refine.rs @@ -1,7 +1,6 @@ // compile-flags: --crate-type=lib // check-pass -#![feature(return_position_impl_trait_in_trait)] #![deny(refining_impl_trait)] pub trait Tr<T> { diff --git a/tests/ui/impl-trait/in-trait/assumed-wf-bounds-in-impl.rs b/tests/ui/impl-trait/in-trait/assumed-wf-bounds-in-impl.rs index 5de9c01e3e0..afb9992de49 100644 --- a/tests/ui/impl-trait/in-trait/assumed-wf-bounds-in-impl.rs +++ b/tests/ui/impl-trait/in-trait/assumed-wf-bounds-in-impl.rs @@ -2,7 +2,6 @@ // edition: 2021 // issue: 113796 -#![feature(async_fn_in_trait)] trait AsyncLendingIterator { type Item<'a> diff --git a/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs b/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs index 6e99402113a..a213994ff86 100644 --- a/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs +++ b/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs @@ -1,4 +1,4 @@ -#![feature(return_position_impl_trait_in_trait, lint_reasons)] +#![feature(lint_reasons)] use std::ops::Deref; diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.rs b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.rs index 3a93dfee57f..41d5f0f6449 100644 --- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.rs +++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.rs @@ -1,6 +1,5 @@ // issue: 114146 -#![feature(return_position_impl_trait_in_trait)] trait Foo { fn bar<'other: 'a>() -> impl Sized + 'a {} diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.stderr b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.stderr index 3a1f8f90837..b0832eb33ca 100644 --- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.stderr +++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.stderr @@ -1,5 +1,5 @@ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/bad-item-bound-within-rpitit-2.rs:6:20 + --> $DIR/bad-item-bound-within-rpitit-2.rs:5:20 | LL | fn bar<'other: 'a>() -> impl Sized + 'a {} | ^^ undeclared lifetime @@ -14,7 +14,7 @@ LL | trait Foo<'a> { | ++++ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/bad-item-bound-within-rpitit-2.rs:6:42 + --> $DIR/bad-item-bound-within-rpitit-2.rs:5:42 | LL | fn bar<'other: 'a>() -> impl Sized + 'a {} | ^^ undeclared lifetime diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs index fbbbb8585d1..5ddc97f1adc 100644 --- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs +++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.rs @@ -1,6 +1,5 @@ // issue: 114145 -#![feature(return_position_impl_trait_in_trait)] pub trait Iterable { type Item<'a> diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr index a5fb338ea4e..324eaa37a3d 100644 --- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr +++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit.stderr @@ -1,5 +1,5 @@ error[E0276]: impl has stricter requirements than trait - --> $DIR/bad-item-bound-within-rpitit.rs:16:13 + --> $DIR/bad-item-bound-within-rpitit.rs:15:13 | LL | type Item<'a> | ------------- definition of `Item` from trait @@ -13,7 +13,7 @@ LL | where Self: 'b; | ~~~~~~~~~~~~~~ warning: impl trait in impl method signature does not match trait method signature - --> $DIR/bad-item-bound-within-rpitit.rs:19:28 + --> $DIR/bad-item-bound-within-rpitit.rs:18:28 | LL | fn iter(&self) -> impl '_ + Iterator<Item = Self::Item<'_>>; | ----------------------------------------- return type from trait method defined here diff --git a/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.rs b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.rs index f5ee4690fa9..87eb7beb1ee 100644 --- a/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.rs +++ b/tests/ui/impl-trait/in-trait/box-coerce-span-in-default.rs @@ -1,6 +1,5 @@ // check-pass -#![feature(return_position_impl_trait_in_trait)] struct TestA {} struct TestB {} diff --git a/tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.rs b/tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.rs index 742537ffcc4..2845b401bd5 100644 --- a/tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.rs +++ b/tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.rs @@ -1,5 +1,3 @@ -#![feature(return_position_impl_trait_in_trait)] - struct Wrapper<G: Send>(G); trait Foo { diff --git a/tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.stderr b/tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.stderr index dee87d08238..1570b2ecd53 100644 --- a/tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.stderr +++ b/tests/ui/impl-trait/in-trait/check-wf-on-non-defaulted-rpitit.stderr @@ -1,12 +1,12 @@ error[E0277]: `impl Sized` cannot be sent between threads safely - --> $DIR/check-wf-on-non-defaulted-rpitit.rs:6:17 + --> $DIR/check-wf-on-non-defaulted-rpitit.rs:4:17 | LL | fn bar() -> Wrapper<impl Sized>; | ^^^^^^^^^^^^^^^^^^^ `impl Sized` cannot be sent between threads safely | = help: the trait `Send` is not implemented for `impl Sized` note: required by a bound in `Wrapper` - --> $DIR/check-wf-on-non-defaulted-rpitit.rs:3:19 + --> $DIR/check-wf-on-non-defaulted-rpitit.rs:1:19 | LL | struct Wrapper<G: Send>(G); | ^^^^ required by this bound in `Wrapper` diff --git a/tests/ui/impl-trait/in-trait/deep-match-works.rs b/tests/ui/impl-trait/in-trait/deep-match-works.rs index fc290f11f9d..8c992743862 100644 --- a/tests/ui/impl-trait/in-trait/deep-match-works.rs +++ b/tests/ui/impl-trait/in-trait/deep-match-works.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(return_position_impl_trait_in_trait, lint_reasons)] +#![feature(lint_reasons)] #![allow(incomplete_features)] pub struct Wrapper<T>(T); diff --git a/tests/ui/impl-trait/in-trait/deep-match.rs b/tests/ui/impl-trait/in-trait/deep-match.rs index 0cae88f349f..02889347ba4 100644 --- a/tests/ui/impl-trait/in-trait/deep-match.rs +++ b/tests/ui/impl-trait/in-trait/deep-match.rs @@ -1,4 +1,3 @@ -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] struct Wrapper<T>(T); diff --git a/tests/ui/impl-trait/in-trait/deep-match.stderr b/tests/ui/impl-trait/in-trait/deep-match.stderr index f0ad3c16e9c..9cfc54f5094 100644 --- a/tests/ui/impl-trait/in-trait/deep-match.stderr +++ b/tests/ui/impl-trait/in-trait/deep-match.stderr @@ -1,5 +1,5 @@ error[E0053]: method `bar` has an incompatible return type for trait - --> $DIR/deep-match.rs:11:17 + --> $DIR/deep-match.rs:10:17 | LL | fn bar() -> i32 { | ^^^ diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err-2.rs b/tests/ui/impl-trait/in-trait/default-body-type-err-2.rs index 45ae2b8ad3a..29bcbe16d83 100644 --- a/tests/ui/impl-trait/in-trait/default-body-type-err-2.rs +++ b/tests/ui/impl-trait/in-trait/default-body-type-err-2.rs @@ -1,7 +1,6 @@ // edition:2021 #![allow(incomplete_features)] -#![feature(async_fn_in_trait)] pub trait Foo { async fn woopsie_async(&self) -> String { diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr index cc3bdf0e571..fcace10cd01 100644 --- a/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr +++ b/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/default-body-type-err-2.rs:8:9 + --> $DIR/default-body-type-err-2.rs:7:9 | LL | 42 | ^^- help: try using a conversion method: `.to_string()` diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err.rs b/tests/ui/impl-trait/in-trait/default-body-type-err.rs index ac9baf91cae..977ff8111dd 100644 --- a/tests/ui/impl-trait/in-trait/default-body-type-err.rs +++ b/tests/ui/impl-trait/in-trait/default-body-type-err.rs @@ -1,5 +1,4 @@ #![allow(incomplete_features)] -#![feature(return_position_impl_trait_in_trait)] use std::ops::Deref; diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err.stderr index 4742eb37d3e..3d9ca62b0db 100644 --- a/tests/ui/impl-trait/in-trait/default-body-type-err.stderr +++ b/tests/ui/impl-trait/in-trait/default-body-type-err.stderr @@ -1,5 +1,5 @@ error[E0271]: type mismatch resolving `<&i32 as Deref>::Target == String` - --> $DIR/default-body-type-err.rs:7:22 + --> $DIR/default-body-type-err.rs:6:22 | LL | fn lol(&self) -> impl Deref<Target = String> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `String` diff --git a/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs b/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs index 9c60cf4e72a..1d1f555080c 100644 --- a/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs +++ b/tests/ui/impl-trait/in-trait/default-body-with-rpit.rs @@ -1,7 +1,6 @@ // edition:2021 // check-pass -#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] #![allow(incomplete_features)] use std::fmt::Debug; diff --git a/tests/ui/impl-trait/in-trait/default-body.rs b/tests/ui/impl-trait/in-trait/default-body.rs index d3ea9fbeabc..ff70f1e232d 100644 --- a/tests/ui/impl-trait/in-trait/default-body.rs +++ b/tests/ui/impl-trait/in-trait/default-body.rs @@ -1,7 +1,6 @@ // check-pass // edition:2021 -#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] #![allow(incomplete_features)] use std::fmt::Debug; diff --git a/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs b/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs index 817a4d7dbbe..ca41eb8bc71 100644 --- a/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs +++ b/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs @@ -1,6 +1,5 @@ // check-pass -#![feature(return_position_impl_trait_in_trait)] trait Trait { type Type; diff --git a/tests/ui/impl-trait/in-trait/default-method-constraint.rs b/tests/ui/impl-trait/in-trait/default-method-constraint.rs index 28d76241f27..8ab2e2797f1 100644 --- a/tests/ui/impl-trait/in-trait/default-method-constraint.rs +++ b/tests/ui/impl-trait/in-trait/default-method-constraint.rs @@ -2,7 +2,6 @@ // This didn't work in the previous default RPITIT method hack attempt -#![feature(return_position_impl_trait_in_trait)] trait Foo { fn bar(x: bool) -> impl Sized { diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs b/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs index bb4e0d44f3e..5a53c9a19b5 100644 --- a/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs +++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.rs @@ -1,4 +1,3 @@ -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] trait Foo { diff --git a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr b/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr index 7c56ffa10e1..cb9ecc7fa48 100644 --- a/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr +++ b/tests/ui/impl-trait/in-trait/doesnt-satisfy.stderr @@ -1,5 +1,5 @@ error[E0277]: `()` doesn't implement `std::fmt::Display` - --> $DIR/doesnt-satisfy.rs:9:17 + --> $DIR/doesnt-satisfy.rs:8:17 | LL | fn bar() -> () {} | ^^ `()` cannot be formatted with the default formatter @@ -7,7 +7,7 @@ LL | fn bar() -> () {} = help: the trait `std::fmt::Display` is not implemented for `()` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `Foo::{opaque#0}` - --> $DIR/doesnt-satisfy.rs:5:22 + --> $DIR/doesnt-satisfy.rs:4:22 | LL | fn bar() -> impl std::fmt::Display; | ^^^^^^^^^^^^^^^^^ required by this bound in `Foo::{opaque#0}` diff --git a/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.rs b/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.rs index 4719d5d3c67..fe0f011b6b0 100644 --- a/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.rs +++ b/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.rs @@ -1,5 +1,3 @@ -#![feature(return_position_impl_trait_in_trait)] - trait MyTrait { fn foo(&self) -> impl Sized; fn bar(&self) -> impl Sized; diff --git a/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.stderr b/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.stderr index 66ee142ccc4..830e663da37 100644 --- a/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.stderr +++ b/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.stderr @@ -1,5 +1,5 @@ error[E0046]: not all trait items implemented, missing: `foo` - --> $DIR/dont-project-to-rpitit-with-no-value.rs:8:1 + --> $DIR/dont-project-to-rpitit-with-no-value.rs:6:1 | LL | fn foo(&self) -> impl Sized; | ---------------------------- `foo` from trait diff --git a/tests/ui/impl-trait/in-trait/early.rs b/tests/ui/impl-trait/in-trait/early.rs index bb5718b4934..c4996674dd1 100644 --- a/tests/ui/impl-trait/in-trait/early.rs +++ b/tests/ui/impl-trait/in-trait/early.rs @@ -1,7 +1,6 @@ // check-pass // edition:2021 -#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] #![allow(incomplete_features)] pub trait Foo { diff --git a/tests/ui/impl-trait/in-trait/encode.rs b/tests/ui/impl-trait/in-trait/encode.rs index efb9f6498ba..4df26b0f297 100644 --- a/tests/ui/impl-trait/in-trait/encode.rs +++ b/tests/ui/impl-trait/in-trait/encode.rs @@ -1,7 +1,6 @@ // build-pass // compile-flags: --crate-type=lib -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] trait Foo { diff --git a/tests/ui/impl-trait/in-trait/gat-outlives.rs b/tests/ui/impl-trait/in-trait/gat-outlives.rs new file mode 100644 index 00000000000..83dd6cfce53 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/gat-outlives.rs @@ -0,0 +1,17 @@ +// edition: 2021 + +use std::future::Future; + +trait Trait { + type Gat<'a>; + //~^ ERROR missing required bound on `Gat` + async fn foo(&self) -> Self::Gat<'_>; +} + +trait Trait2 { + type Gat<'a>; + //~^ ERROR missing required bound on `Gat` + async fn foo(&self) -> impl Future<Output = Self::Gat<'_>>; +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/gat-outlives.stderr b/tests/ui/impl-trait/in-trait/gat-outlives.stderr new file mode 100644 index 00000000000..8ec4b0ab2ee --- /dev/null +++ b/tests/ui/impl-trait/in-trait/gat-outlives.stderr @@ -0,0 +1,24 @@ +error: missing required bound on `Gat` + --> $DIR/gat-outlives.rs:6:5 + | +LL | type Gat<'a>; + | ^^^^^^^^^^^^- + | | + | help: add the required where clause: `where Self: 'a` + | + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information + +error: missing required bound on `Gat` + --> $DIR/gat-outlives.rs:12:5 + | +LL | type Gat<'a>; + | ^^^^^^^^^^^^- + | | + | help: add the required where clause: `where Self: 'a` + | + = note: this bound is currently required to ensure that impls have maximum flexibility + = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information + +error: aborting due to 2 previous errors + diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.rs b/tests/ui/impl-trait/in-trait/generics-mismatch.rs index cc0fc720ebb..2e5373dbd5d 100644 --- a/tests/ui/impl-trait/in-trait/generics-mismatch.rs +++ b/tests/ui/impl-trait/in-trait/generics-mismatch.rs @@ -1,4 +1,3 @@ -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] struct U; diff --git a/tests/ui/impl-trait/in-trait/generics-mismatch.stderr b/tests/ui/impl-trait/in-trait/generics-mismatch.stderr index cd42683e022..3dbf2235c5e 100644 --- a/tests/ui/impl-trait/in-trait/generics-mismatch.stderr +++ b/tests/ui/impl-trait/in-trait/generics-mismatch.stderr @@ -1,5 +1,5 @@ error[E0049]: method `bar` has 1 type parameter but its trait declaration has 0 type parameters - --> $DIR/generics-mismatch.rs:11:12 + --> $DIR/generics-mismatch.rs:10:12 | LL | fn bar(&self) -> impl Sized; | - expected 0 type parameters diff --git a/tests/ui/impl-trait/in-trait/issue-102140.rs b/tests/ui/impl-trait/in-trait/issue-102140.rs index be1e012acb1..1132bd25f81 100644 --- a/tests/ui/impl-trait/in-trait/issue-102140.rs +++ b/tests/ui/impl-trait/in-trait/issue-102140.rs @@ -1,4 +1,3 @@ -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] trait Marker {} diff --git a/tests/ui/impl-trait/in-trait/issue-102140.stderr b/tests/ui/impl-trait/in-trait/issue-102140.stderr index 18bb63745d7..6d50d2f3a24 100644 --- a/tests/ui/impl-trait/in-trait/issue-102140.stderr +++ b/tests/ui/impl-trait/in-trait/issue-102140.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied - --> $DIR/issue-102140.rs:23:22 + --> $DIR/issue-102140.rs:22:22 | LL | MyTrait::foo(&self) | ------------ ^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait` @@ -13,7 +13,7 @@ LL + MyTrait::foo(self) | error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied - --> $DIR/issue-102140.rs:23:9 + --> $DIR/issue-102140.rs:22:9 | LL | MyTrait::foo(&self) | ^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait` @@ -21,7 +21,7 @@ LL | MyTrait::foo(&self) = help: the trait `MyTrait` is implemented for `Outer` error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied - --> $DIR/issue-102140.rs:23:9 + --> $DIR/issue-102140.rs:22:9 | LL | MyTrait::foo(&self) | ^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait` diff --git a/tests/ui/impl-trait/in-trait/issue-102301.rs b/tests/ui/impl-trait/in-trait/issue-102301.rs index a93714a658e..600a21b07be 100644 --- a/tests/ui/impl-trait/in-trait/issue-102301.rs +++ b/tests/ui/impl-trait/in-trait/issue-102301.rs @@ -1,6 +1,5 @@ // check-pass -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] trait Foo<T> { diff --git a/tests/ui/impl-trait/in-trait/issue-102571.rs b/tests/ui/impl-trait/in-trait/issue-102571.rs index ccb53031c44..4534753f0d2 100644 --- a/tests/ui/impl-trait/in-trait/issue-102571.rs +++ b/tests/ui/impl-trait/in-trait/issue-102571.rs @@ -1,4 +1,3 @@ -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] use std::fmt::Display; diff --git a/tests/ui/impl-trait/in-trait/issue-102571.stderr b/tests/ui/impl-trait/in-trait/issue-102571.stderr index 594b9ae9cd6..4d1a0feb22b 100644 --- a/tests/ui/impl-trait/in-trait/issue-102571.stderr +++ b/tests/ui/impl-trait/in-trait/issue-102571.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-102571.rs:12:9 + --> $DIR/issue-102571.rs:11:9 | LL | let () = t.bar(); | ^^ ------- this expression has type `impl Deref<Target = impl std::fmt::Display + ?Sized>` diff --git a/tests/ui/impl-trait/in-trait/lifetime-in-associated-trait-bound.rs b/tests/ui/impl-trait/in-trait/lifetime-in-associated-trait-bound.rs index 49d36d6c99c..4073ef8ac19 100644 --- a/tests/ui/impl-trait/in-trait/lifetime-in-associated-trait-bound.rs +++ b/tests/ui/impl-trait/in-trait/lifetime-in-associated-trait-bound.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(associated_type_bounds, return_position_impl_trait_in_trait)] +#![feature(associated_type_bounds)] trait Trait { type Type; diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr index 239c4b35c72..59139e4d5ae 100644 --- a/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr +++ b/tests/ui/impl-trait/in-trait/method-signature-matches.lt.stderr @@ -1,5 +1,5 @@ error[E0053]: method `early` has an incompatible type for trait - --> $DIR/method-signature-matches.rs:58:27 + --> $DIR/method-signature-matches.rs:57:27 | LL | fn early<'late, T>(_: &'late ()) {} | - ^^^^^^^^^ @@ -9,7 +9,7 @@ LL | fn early<'late, T>(_: &'late ()) {} | this type parameter | note: type in trait - --> $DIR/method-signature-matches.rs:53:28 + --> $DIR/method-signature-matches.rs:52:28 | LL | fn early<'early, T>(x: &'early T) -> impl Sized; | ^^^^^^^^^ diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr index d3183b92e84..e0bd1cc4f19 100644 --- a/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr +++ b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch.stderr @@ -1,5 +1,5 @@ error[E0053]: method `owo` has an incompatible type for trait - --> $DIR/method-signature-matches.rs:14:15 + --> $DIR/method-signature-matches.rs:13:15 | LL | fn owo(_: u8) {} | ^^ @@ -8,7 +8,7 @@ LL | fn owo(_: u8) {} | help: change the parameter type to match the trait: `()` | note: type in trait - --> $DIR/method-signature-matches.rs:9:15 + --> $DIR/method-signature-matches.rs:8:15 | LL | fn owo(x: ()) -> impl Sized; | ^^ diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr index 80fda1c9fe1..096e96c85c4 100644 --- a/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr +++ b/tests/ui/impl-trait/in-trait/method-signature-matches.mismatch_async.stderr @@ -1,5 +1,5 @@ error[E0053]: method `owo` has an incompatible type for trait - --> $DIR/method-signature-matches.rs:25:21 + --> $DIR/method-signature-matches.rs:24:21 | LL | async fn owo(_: u8) {} | ^^ @@ -8,7 +8,7 @@ LL | async fn owo(_: u8) {} | help: change the parameter type to match the trait: `()` | note: type in trait - --> $DIR/method-signature-matches.rs:20:21 + --> $DIR/method-signature-matches.rs:19:21 | LL | async fn owo(x: ()) {} | ^^ diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.rs b/tests/ui/impl-trait/in-trait/method-signature-matches.rs index 294f93b30d0..99ace66facb 100644 --- a/tests/ui/impl-trait/in-trait/method-signature-matches.rs +++ b/tests/ui/impl-trait/in-trait/method-signature-matches.rs @@ -1,7 +1,6 @@ // edition: 2021 // revisions: mismatch mismatch_async too_many too_few lt -#![feature(return_position_impl_trait_in_trait, async_fn_in_trait)] #![allow(incomplete_features)] #[cfg(mismatch)] diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.too_few.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.too_few.stderr index 24bcfeb748f..96eff1a5815 100644 --- a/tests/ui/impl-trait/in-trait/method-signature-matches.too_few.stderr +++ b/tests/ui/impl-trait/in-trait/method-signature-matches.too_few.stderr @@ -1,5 +1,5 @@ error[E0050]: method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3 - --> $DIR/method-signature-matches.rs:47:5 + --> $DIR/method-signature-matches.rs:46:5 | LL | fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized; | ---------------- trait requires 3 parameters diff --git a/tests/ui/impl-trait/in-trait/method-signature-matches.too_many.stderr b/tests/ui/impl-trait/in-trait/method-signature-matches.too_many.stderr index 616cbd2905c..0fc847051c9 100644 --- a/tests/ui/impl-trait/in-trait/method-signature-matches.too_many.stderr +++ b/tests/ui/impl-trait/in-trait/method-signature-matches.too_many.stderr @@ -1,5 +1,5 @@ error[E0050]: method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0 - --> $DIR/method-signature-matches.rs:36:28 + --> $DIR/method-signature-matches.rs:35:28 | LL | fn calm_down_please() -> impl Sized; | ------------------------------------ trait requires 0 parameters diff --git a/tests/ui/impl-trait/in-trait/missing-lt-outlives-in-rpitit-114274.rs b/tests/ui/impl-trait/in-trait/missing-lt-outlives-in-rpitit-114274.rs index abc845d3afa..6088dcc61d6 100644 --- a/tests/ui/impl-trait/in-trait/missing-lt-outlives-in-rpitit-114274.rs +++ b/tests/ui/impl-trait/in-trait/missing-lt-outlives-in-rpitit-114274.rs @@ -1,5 +1,3 @@ -#![feature(return_position_impl_trait_in_trait)] - trait Iterable { type Item<'a> where diff --git a/tests/ui/impl-trait/in-trait/missing-lt-outlives-in-rpitit-114274.stderr b/tests/ui/impl-trait/in-trait/missing-lt-outlives-in-rpitit-114274.stderr index 0d74c0b69ce..1fd678a1f3a 100644 --- a/tests/ui/impl-trait/in-trait/missing-lt-outlives-in-rpitit-114274.stderr +++ b/tests/ui/impl-trait/in-trait/missing-lt-outlives-in-rpitit-114274.stderr @@ -1,5 +1,5 @@ error[E0261]: use of undeclared lifetime name `'missing` - --> $DIR/missing-lt-outlives-in-rpitit-114274.rs:8:55 + --> $DIR/missing-lt-outlives-in-rpitit-114274.rs:6:55 | LL | fn iter(&self) -> impl Iterator<Item = Self::Item<'missing>>; | ^^^^^^^^ undeclared lifetime diff --git a/tests/ui/impl-trait/in-trait/nested-rpitit.rs b/tests/ui/impl-trait/in-trait/nested-rpitit.rs index 58ba1acaf14..58b79c99155 100644 --- a/tests/ui/impl-trait/in-trait/nested-rpitit.rs +++ b/tests/ui/impl-trait/in-trait/nested-rpitit.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(return_position_impl_trait_in_trait, lint_reasons)] +#![feature(lint_reasons)] #![allow(incomplete_features)] use std::fmt::Display; diff --git a/tests/ui/impl-trait/in-trait/object-safety-sized.rs b/tests/ui/impl-trait/in-trait/object-safety-sized.rs index f221cfbb176..35afe80c97f 100644 --- a/tests/ui/impl-trait/in-trait/object-safety-sized.rs +++ b/tests/ui/impl-trait/in-trait/object-safety-sized.rs @@ -2,7 +2,6 @@ // revisions: current next //[next] compile-flags: -Ztrait-solver=next -#![feature(return_position_impl_trait_in_trait)] fn main() { let vec: Vec<Box<dyn Trait>> = Vec::new(); diff --git a/tests/ui/impl-trait/in-trait/object-safety.rs b/tests/ui/impl-trait/in-trait/object-safety.rs index d1c9fba4e99..15634537dae 100644 --- a/tests/ui/impl-trait/in-trait/object-safety.rs +++ b/tests/ui/impl-trait/in-trait/object-safety.rs @@ -1,4 +1,3 @@ -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] use std::fmt::Debug; diff --git a/tests/ui/impl-trait/in-trait/object-safety.stderr b/tests/ui/impl-trait/in-trait/object-safety.stderr index 0170dc5d0fc..8d882391251 100644 --- a/tests/ui/impl-trait/in-trait/object-safety.stderr +++ b/tests/ui/impl-trait/in-trait/object-safety.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety.rs:17:33 + --> $DIR/object-safety.rs:16:33 | LL | let i = Box::new(42_u32) as Box<dyn Foo>; | ^^^^^^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety.rs:7:22 + --> $DIR/object-safety.rs:6:22 | LL | trait Foo { | --- this trait cannot be made into an object... @@ -14,13 +14,13 @@ LL | fn baz(&self) -> impl Debug; = help: consider moving `baz` to another trait error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety.rs:20:15 + --> $DIR/object-safety.rs:19:15 | LL | let s = i.baz(); | ^^^ `Foo` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety.rs:7:22 + --> $DIR/object-safety.rs:6:22 | LL | trait Foo { | --- this trait cannot be made into an object... @@ -29,13 +29,13 @@ LL | fn baz(&self) -> impl Debug; = help: consider moving `baz` to another trait error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety.rs:20:13 + --> $DIR/object-safety.rs:19:13 | LL | let s = i.baz(); | ^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety.rs:7:22 + --> $DIR/object-safety.rs:6:22 | LL | trait Foo { | --- this trait cannot be made into an object... @@ -44,13 +44,13 @@ LL | fn baz(&self) -> impl Debug; = help: consider moving `baz` to another trait error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/object-safety.rs:17:13 + --> $DIR/object-safety.rs:16:13 | LL | let i = Box::new(42_u32) as Box<dyn Foo>; | ^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety.rs:7:22 + --> $DIR/object-safety.rs:6:22 | LL | trait Foo { | --- this trait cannot be made into an object... diff --git a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs index 3ac264e8eba..fc708536b0f 100644 --- a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs +++ b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs @@ -1,4 +1,3 @@ -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] use std::fmt::Display; diff --git a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr index 15edda48340..99b62e80acd 100644 --- a/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr +++ b/tests/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/opaque-in-impl-is-opaque.rs:17:19 + --> $DIR/opaque-in-impl-is-opaque.rs:16:19 | LL | fn bar(&self) -> impl Display { | ------------ the found opaque type diff --git a/tests/ui/impl-trait/in-trait/opaque-in-impl.rs b/tests/ui/impl-trait/in-trait/opaque-in-impl.rs index 2e06629699a..3edd588a1b3 100644 --- a/tests/ui/impl-trait/in-trait/opaque-in-impl.rs +++ b/tests/ui/impl-trait/in-trait/opaque-in-impl.rs @@ -1,6 +1,5 @@ // check-pass -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] use std::fmt::Debug; diff --git a/tests/ui/impl-trait/in-trait/opaque-variances.rs b/tests/ui/impl-trait/in-trait/opaque-variances.rs new file mode 100644 index 00000000000..60bfab0deb5 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/opaque-variances.rs @@ -0,0 +1,14 @@ +// check-pass +// compile-flags: -Ztrait-solver=next + +fn foo<'a: 'a>(x: &'a Vec<i32>) -> impl Sized { + () +} + +fn main() { + // in NLL, we want to make sure that the `'a` subst of `foo` does not get + // related between `x` and the RHS of the assignment. That would require + // that the temp is live for the lifetime of the variable `x`, which of + // course is not necessary since `'a` is not captured by the RPIT. + let x = foo(&Vec::new()); +} diff --git a/tests/ui/impl-trait/in-trait/outlives-in-nested-rpit.rs b/tests/ui/impl-trait/in-trait/outlives-in-nested-rpit.rs index 6330242ceeb..317ff7fe853 100644 --- a/tests/ui/impl-trait/in-trait/outlives-in-nested-rpit.rs +++ b/tests/ui/impl-trait/in-trait/outlives-in-nested-rpit.rs @@ -1,6 +1,5 @@ // check-pass -#![feature(return_position_impl_trait_in_trait)] trait Foo { fn early<'a, T: 'a>(x: &'a T) -> impl Iterator<Item = impl Into<&'a T>>; diff --git a/tests/ui/impl-trait/in-trait/refine.rs b/tests/ui/impl-trait/in-trait/refine.rs index f00478b0bb9..100e6da06a8 100644 --- a/tests/ui/impl-trait/in-trait/refine.rs +++ b/tests/ui/impl-trait/in-trait/refine.rs @@ -1,4 +1,3 @@ -#![feature(return_position_impl_trait_in_trait, async_fn_in_trait)] #![deny(refining_impl_trait)] pub trait Foo { diff --git a/tests/ui/impl-trait/in-trait/refine.stderr b/tests/ui/impl-trait/in-trait/refine.stderr index 1d9852c682c..96a9bc059c8 100644 --- a/tests/ui/impl-trait/in-trait/refine.stderr +++ b/tests/ui/impl-trait/in-trait/refine.stderr @@ -1,5 +1,5 @@ error: impl trait in impl method signature does not match trait method signature - --> $DIR/refine.rs:10:22 + --> $DIR/refine.rs:9:22 | LL | fn bar() -> impl Sized; | ---------- return type from trait method defined here @@ -9,7 +9,7 @@ LL | fn bar() -> impl Copy {} | = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate note: the lint level is defined here - --> $DIR/refine.rs:2:9 + --> $DIR/refine.rs:1:9 | LL | #![deny(refining_impl_trait)] | ^^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | fn bar() -> impl Sized {} | ~~~~~~~~~~ error: impl trait in impl method signature does not match trait method signature - --> $DIR/refine.rs:16:5 + --> $DIR/refine.rs:15:5 | LL | fn bar() -> impl Sized; | ---------- return type from trait method defined here @@ -34,7 +34,7 @@ LL | fn bar()-> impl Sized {} | +++++++++++++ error: impl trait in impl method signature does not match trait method signature - --> $DIR/refine.rs:22:17 + --> $DIR/refine.rs:21:17 | LL | fn bar() -> impl Sized; | ---------- return type from trait method defined here @@ -49,7 +49,7 @@ LL | fn bar() -> impl Sized {} | ~~~~~~~~~~ error: impl trait in impl method signature does not match trait method signature - --> $DIR/refine.rs:44:27 + --> $DIR/refine.rs:43:27 | LL | fn bar<'a>(&'a self) -> impl Sized + 'a; | --------------- return type from trait method defined here diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs index 5d9a224ccd6..ad73b12feb5 100644 --- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.rs @@ -1,5 +1,3 @@ -#![feature(return_position_impl_trait_in_trait)] - trait Foo<T> { fn foo<F2>(self) -> impl Foo<T>; } diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr index 668fc6cbe7f..181d6a284da 100644 --- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr @@ -1,12 +1,12 @@ error[E0277]: the trait bound `impl Foo<u8>: Foo<char>` is not satisfied - --> $DIR/return-dont-satisfy-bounds.rs:10:34 + --> $DIR/return-dont-satisfy-bounds.rs:8:34 | LL | fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> { | ^^^^^^^^^^^^ the trait `Foo<char>` is not implemented for `impl Foo<u8>` | = help: the trait `Foo<char>` is implemented for `Bar` note: required by a bound in `Foo::{opaque#0}` - --> $DIR/return-dont-satisfy-bounds.rs:4:30 + --> $DIR/return-dont-satisfy-bounds.rs:2:30 | LL | fn foo<F2>(self) -> impl Foo<T>; | ^^^^^^ required by this bound in `Foo::{opaque#0}` diff --git a/tests/ui/impl-trait/in-trait/reveal.rs b/tests/ui/impl-trait/in-trait/reveal.rs index b1b46d75b8f..cc78ce8fea2 100644 --- a/tests/ui/impl-trait/in-trait/reveal.rs +++ b/tests/ui/impl-trait/in-trait/reveal.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(return_position_impl_trait_in_trait, lint_reasons)] +#![feature(lint_reasons)] #![allow(incomplete_features)] pub trait Foo { diff --git a/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.rs b/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.rs index 5e14a7f8e72..37b0b229776 100644 --- a/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.rs +++ b/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.rs @@ -1,5 +1,3 @@ -#![feature(return_position_impl_trait_in_trait)] - trait Extend { fn extend<'a: 'a>(_: &'a str) -> (impl Sized + 'a, &'static str); } diff --git a/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.stderr b/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.stderr index 1d947310e12..afc59cc5b58 100644 --- a/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.stderr +++ b/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf-via-param.stderr @@ -1,12 +1,12 @@ error[E0491]: in type `&'static &'a ()`, reference has a longer lifetime than the data it references - --> $DIR/rpitit-hidden-types-self-implied-wf-via-param.rs:8:38 + --> $DIR/rpitit-hidden-types-self-implied-wf-via-param.rs:6:38 | LL | fn extend<'a: 'a>(s: &'a str) -> (Option<&'static &'a ()>, &'static str) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the pointer is valid for the static lifetime note: but the referenced data is only valid for the lifetime `'a` as defined here - --> $DIR/rpitit-hidden-types-self-implied-wf-via-param.rs:8:15 + --> $DIR/rpitit-hidden-types-self-implied-wf-via-param.rs:6:15 | LL | fn extend<'a: 'a>(s: &'a str) -> (Option<&'static &'a ()>, &'static str) | ^^ diff --git a/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf.rs b/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf.rs index c1885af4e5e..bacd5007768 100644 --- a/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf.rs +++ b/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf.rs @@ -1,5 +1,3 @@ -#![feature(return_position_impl_trait_in_trait)] - trait Extend { fn extend(_: &str) -> (impl Sized + '_, &'static str); } diff --git a/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf.stderr b/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf.stderr index 7b63e72acbf..7e1a8f083ac 100644 --- a/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf.stderr +++ b/tests/ui/impl-trait/in-trait/rpitit-hidden-types-self-implied-wf.stderr @@ -1,12 +1,12 @@ error[E0491]: in type `&'static &()`, reference has a longer lifetime than the data it references - --> $DIR/rpitit-hidden-types-self-implied-wf.rs:8:27 + --> $DIR/rpitit-hidden-types-self-implied-wf.rs:6:27 | LL | fn extend(s: &str) -> (Option<&'static &'_ ()>, &'static str) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the pointer is valid for the static lifetime note: but the referenced data is only valid for the anonymous lifetime defined here - --> $DIR/rpitit-hidden-types-self-implied-wf.rs:8:18 + --> $DIR/rpitit-hidden-types-self-implied-wf.rs:6:18 | LL | fn extend(s: &str) -> (Option<&'static &'_ ()>, &'static str) { | ^^^^ diff --git a/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs b/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs index 44a2b430344..b9fe8d8bfc5 100644 --- a/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs +++ b/tests/ui/impl-trait/in-trait/rpitit-shadowed-by-missing-adt.rs @@ -1,6 +1,6 @@ // issue: 113903 -#![feature(return_position_impl_trait_in_trait, lint_reasons)] +#![feature(lint_reasons)] use std::ops::Deref; diff --git a/tests/ui/impl-trait/in-trait/sibling-function-constraint.rs b/tests/ui/impl-trait/in-trait/sibling-function-constraint.rs new file mode 100644 index 00000000000..fe162e6cf80 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/sibling-function-constraint.rs @@ -0,0 +1,21 @@ +// Checks that a sibling function (i.e. `foo`) cannot constrain +// an RPITIT from another function (`bar`). + +trait Trait { + fn foo(); + + fn bar() -> impl Sized; +} + +impl Trait for () { + fn foo() { + let _: String = Self::bar(); + //~^ ERROR mismatched types + } + + fn bar() -> impl Sized { + loop {} + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/sibling-function-constraint.stderr b/tests/ui/impl-trait/in-trait/sibling-function-constraint.stderr new file mode 100644 index 00000000000..729963a8141 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/sibling-function-constraint.stderr @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/sibling-function-constraint.rs:12:25 + | +LL | let _: String = Self::bar(); + | ------ ^^^^^^^^^^^ expected `String`, found opaque type + | | + | expected due to this +... +LL | fn bar() -> impl Sized { + | ---------- the found opaque type + | + = note: expected struct `String` + found opaque type `impl Sized` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.rs b/tests/ui/impl-trait/in-trait/signature-mismatch.rs index 685c0f06e88..d85ee5fc704 100644 --- a/tests/ui/impl-trait/in-trait/signature-mismatch.rs +++ b/tests/ui/impl-trait/in-trait/signature-mismatch.rs @@ -2,7 +2,7 @@ // revisions: success failure //[success] check-pass -#![feature(return_position_impl_trait_in_trait, lint_reasons)] +#![feature(lint_reasons)] use std::future::Future; diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.rs b/tests/ui/impl-trait/in-trait/specialization-broken.rs index 2fcffdf3f9a..a06cd814f7c 100644 --- a/tests/ui/impl-trait/in-trait/specialization-broken.rs +++ b/tests/ui/impl-trait/in-trait/specialization-broken.rs @@ -2,7 +2,6 @@ // But we fixed an ICE anyways. #![feature(specialization)] -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] trait Foo { diff --git a/tests/ui/impl-trait/in-trait/specialization-broken.stderr b/tests/ui/impl-trait/in-trait/specialization-broken.stderr index dc621d6b8a8..1d169b5d690 100644 --- a/tests/ui/impl-trait/in-trait/specialization-broken.stderr +++ b/tests/ui/impl-trait/in-trait/specialization-broken.stderr @@ -1,5 +1,5 @@ error[E0053]: method `bar` has an incompatible type for trait - --> $DIR/specialization-broken.rs:16:22 + --> $DIR/specialization-broken.rs:15:22 | LL | default impl<U> Foo for U | - this type parameter @@ -11,7 +11,7 @@ LL | fn bar(&self) -> U { | help: change the output type to match the trait: `impl Sized` | note: type in trait - --> $DIR/specialization-broken.rs:9:22 + --> $DIR/specialization-broken.rs:8:22 | LL | fn bar(&self) -> impl Sized; | ^^^^^^^^^^ @@ -19,12 +19,12 @@ LL | fn bar(&self) -> impl Sized; found signature `fn(&U) -> U` error: method with return-position `impl Trait` in trait cannot be specialized - --> $DIR/specialization-broken.rs:16:5 + --> $DIR/specialization-broken.rs:15:5 | LL | fn bar(&self) -> U { | ^^^^^^^^^^^^^^^^^^ | - = note: specialization behaves in inconsistent and surprising ways with `#![feature(return_position_impl_trait_in_trait)]`, and for now is disallowed + = note: specialization behaves in inconsistent and surprising ways with return position `impl Trait` in traits, and for now is disallowed error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs b/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs index 41fc285883a..05386632758 100644 --- a/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs +++ b/tests/ui/impl-trait/in-trait/specialization-substs-remap.rs @@ -1,7 +1,7 @@ // check-pass #![feature(specialization)] -#![feature(return_position_impl_trait_in_trait, lint_reasons)] +#![feature(lint_reasons)] #![allow(incomplete_features)] pub trait Foo { diff --git a/tests/ui/impl-trait/in-trait/success.rs b/tests/ui/impl-trait/in-trait/success.rs index 7d415ea17a4..eb2349feb29 100644 --- a/tests/ui/impl-trait/in-trait/success.rs +++ b/tests/ui/impl-trait/in-trait/success.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(return_position_impl_trait_in_trait, lint_reasons)] +#![feature(lint_reasons)] #![allow(incomplete_features)] use std::fmt::Display; diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed b/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed index 58d83384a23..8dc8e045d47 100644 --- a/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed @@ -1,8 +1,6 @@ // edition:2021 // run-rustfix -#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] - trait Trait { #[allow(async_fn_in_trait)] async fn foo(); diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.rs b/tests/ui/impl-trait/in-trait/suggest-missing-item.rs index c27229806e1..30b04d87b9a 100644 --- a/tests/ui/impl-trait/in-trait/suggest-missing-item.rs +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.rs @@ -1,8 +1,6 @@ // edition:2021 // run-rustfix -#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] - trait Trait { #[allow(async_fn_in_trait)] async fn foo(); diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr b/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr index 29f6bad86dc..cec94e39a35 100644 --- a/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr @@ -1,5 +1,5 @@ error[E0046]: not all trait items implemented, missing: `foo`, `bar`, `test`, `baz` - --> $DIR/suggest-missing-item.rs:21:1 + --> $DIR/suggest-missing-item.rs:19:1 | LL | async fn foo(); | --------------- `foo` from trait diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs index 0bbe50ea6fd..c905bfce852 100644 --- a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs +++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.rs @@ -1,4 +1,3 @@ -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] struct S; diff --git a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr index 8ff54cad951..e904548742d 100644 --- a/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr +++ b/tests/ui/impl-trait/in-trait/trait-more-generics-than-impl.stderr @@ -1,5 +1,5 @@ error[E0049]: method `bar` has 0 type parameters but its trait declaration has 1 type parameter - --> $DIR/trait-more-generics-than-impl.rs:11:11 + --> $DIR/trait-more-generics-than-impl.rs:10:11 | LL | fn bar<T>() -> impl Sized; | - expected 1 type parameter diff --git a/tests/ui/impl-trait/in-trait/unconstrained-lt.rs b/tests/ui/impl-trait/in-trait/unconstrained-lt.rs index 07c8606f9fe..ff3753de5a2 100644 --- a/tests/ui/impl-trait/in-trait/unconstrained-lt.rs +++ b/tests/ui/impl-trait/in-trait/unconstrained-lt.rs @@ -1,5 +1,3 @@ -#![feature(return_position_impl_trait_in_trait)] - trait Foo { fn test() -> impl Sized; } diff --git a/tests/ui/impl-trait/in-trait/unconstrained-lt.stderr b/tests/ui/impl-trait/in-trait/unconstrained-lt.stderr index cfce3556720..61a0f8454d1 100644 --- a/tests/ui/impl-trait/in-trait/unconstrained-lt.stderr +++ b/tests/ui/impl-trait/in-trait/unconstrained-lt.stderr @@ -1,5 +1,5 @@ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates - --> $DIR/unconstrained-lt.rs:7:6 + --> $DIR/unconstrained-lt.rs:5:6 | LL | impl<'a, T> Foo for T { | ^^ unconstrained lifetime parameter diff --git a/tests/ui/impl-trait/in-trait/variance.rs b/tests/ui/impl-trait/in-trait/variance.rs index f8e4ab88c19..65565dcc2a6 100644 --- a/tests/ui/impl-trait/in-trait/variance.rs +++ b/tests/ui/impl-trait/in-trait/variance.rs @@ -1,4 +1,4 @@ -#![feature(rustc_attrs, return_position_impl_trait_in_trait)] +#![feature(rustc_attrs)] #![allow(internal_features)] #![rustc_variance_of_opaques] diff --git a/tests/ui/impl-trait/in-trait/variances-of-gat.rs b/tests/ui/impl-trait/in-trait/variances-of-gat.rs index 0d19e1ff416..aabb6f830ed 100644 --- a/tests/ui/impl-trait/in-trait/variances-of-gat.rs +++ b/tests/ui/impl-trait/in-trait/variances-of-gat.rs @@ -1,6 +1,5 @@ // check-pass -#![feature(return_position_impl_trait_in_trait)] trait Foo {} diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.rs b/tests/ui/impl-trait/in-trait/wf-bounds.rs index ee873f94b26..f1e372b196a 100644 --- a/tests/ui/impl-trait/in-trait/wf-bounds.rs +++ b/tests/ui/impl-trait/in-trait/wf-bounds.rs @@ -1,6 +1,5 @@ // issue #101663 -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] use std::fmt::Display; diff --git a/tests/ui/impl-trait/in-trait/wf-bounds.stderr b/tests/ui/impl-trait/in-trait/wf-bounds.stderr index 4d60b133048..c20df9b40ed 100644 --- a/tests/ui/impl-trait/in-trait/wf-bounds.stderr +++ b/tests/ui/impl-trait/in-trait/wf-bounds.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/wf-bounds.rs:15:22 + --> $DIR/wf-bounds.rs:14:22 | LL | fn nya() -> impl Wf<Vec<[u8]>>; | ^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -9,14 +9,14 @@ note: required by a bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/wf-bounds.rs:18:23 + --> $DIR/wf-bounds.rs:17:23 | LL | fn nya2() -> impl Wf<[u8]>; | ^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` note: required by a bound in `Wf` - --> $DIR/wf-bounds.rs:8:10 + --> $DIR/wf-bounds.rs:7:10 | LL | trait Wf<T> { | ^ required by this bound in `Wf` @@ -26,7 +26,7 @@ LL | trait Wf<T: ?Sized> { | ++++++++ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/wf-bounds.rs:21:44 + --> $DIR/wf-bounds.rs:20:44 | LL | fn nya3() -> impl Wf<(), Output = impl Wf<Vec<[u8]>>>; | ^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -36,14 +36,14 @@ note: required by a bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL error[E0277]: `T` doesn't implement `std::fmt::Display` - --> $DIR/wf-bounds.rs:24:26 + --> $DIR/wf-bounds.rs:23:26 | LL | fn nya4<T>() -> impl Wf<NeedsDisplay<T>>; | ^^^^^^^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter | = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead note: required by a bound in `NeedsDisplay` - --> $DIR/wf-bounds.rs:12:24 + --> $DIR/wf-bounds.rs:11:24 | LL | struct NeedsDisplay<T: Display>(T); | ^^^^^^^ required by this bound in `NeedsDisplay` diff --git a/tests/ui/impl-trait/in-trait/where-clause.rs b/tests/ui/impl-trait/in-trait/where-clause.rs index 87bac519cf3..f7f4980b730 100644 --- a/tests/ui/impl-trait/in-trait/where-clause.rs +++ b/tests/ui/impl-trait/in-trait/where-clause.rs @@ -1,7 +1,6 @@ // check-pass // edition: 2021 -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] use std::fmt::Debug; diff --git a/tests/ui/impl-trait/nested-return-type2-tait2.rs b/tests/ui/impl-trait/nested-return-type2-tait2.rs index af8e0663054..b7fee1d91d1 100644 --- a/tests/ui/impl-trait/nested-return-type2-tait2.rs +++ b/tests/ui/impl-trait/nested-return-type2-tait2.rs @@ -1,3 +1,5 @@ +// check-pass + #![feature(type_alias_impl_trait)] trait Duh {} @@ -17,6 +19,7 @@ impl<R: Duh, F: FnMut() -> R> Trait for F { type Sendable = impl Send; type Traitable = impl Trait<Assoc = Sendable>; +//~^ WARN opaque type `Traitable` does not satisfy its associated type bounds // The `impl Send` here is then later compared against the inference var // created, causing the inference var to be set to `impl Send` instead of @@ -25,7 +28,6 @@ type Traitable = impl Trait<Assoc = Sendable>; // type does not implement `Duh`, even if its hidden type does. So we error out. fn foo() -> Traitable { || 42 - //~^ ERROR `Sendable: Duh` is not satisfied } fn main() { diff --git a/tests/ui/impl-trait/nested-return-type2-tait2.stderr b/tests/ui/impl-trait/nested-return-type2-tait2.stderr index 125262b96e8..790e339c8b1 100644 --- a/tests/ui/impl-trait/nested-return-type2-tait2.stderr +++ b/tests/ui/impl-trait/nested-return-type2-tait2.stderr @@ -1,18 +1,13 @@ -error[E0277]: the trait bound `Sendable: Duh` is not satisfied - --> $DIR/nested-return-type2-tait2.rs:27:5 +warning: opaque type `Traitable` does not satisfy its associated type bounds + --> $DIR/nested-return-type2-tait2.rs:21:29 | -LL | || 42 - | ^^^^^ the trait `Duh` is not implemented for `Sendable` +LL | type Assoc: Duh; + | --- this associated type bound is unsatisfied for `Sendable` +... +LL | type Traitable = impl Trait<Assoc = Sendable>; + | ^^^^^^^^^^^^^^^^ | - = help: the trait `Duh` is implemented for `i32` -note: required for `{closure@$DIR/nested-return-type2-tait2.rs:27:5: 27:7}` to implement `Trait` - --> $DIR/nested-return-type2-tait2.rs:14:31 - | -LL | impl<R: Duh, F: FnMut() -> R> Trait for F { - | --- ^^^^^ ^ - | | - | unsatisfied trait bound introduced here + = note: `#[warn(opaque_hidden_inferred_bound)]` on by default -error: aborting due to previous error +warning: 1 warning emitted -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/nested-return-type2-tait3.rs b/tests/ui/impl-trait/nested-return-type2-tait3.rs index 74fd8a9dda0..eed5c271f88 100644 --- a/tests/ui/impl-trait/nested-return-type2-tait3.rs +++ b/tests/ui/impl-trait/nested-return-type2-tait3.rs @@ -1,3 +1,5 @@ +// check-pass + #![feature(type_alias_impl_trait)] trait Duh {} @@ -16,6 +18,7 @@ impl<R: Duh, F: FnMut() -> R> Trait for F { } type Traitable = impl Trait<Assoc = impl Send>; +//~^ WARN opaque type `Traitable` does not satisfy its associated type bounds // The `impl Send` here is then later compared against the inference var // created, causing the inference var to be set to `impl Send` instead of @@ -24,7 +27,6 @@ type Traitable = impl Trait<Assoc = impl Send>; // type does not implement `Duh`, even if its hidden type does. So we error out. fn foo() -> Traitable { || 42 - //~^ ERROR `impl Send: Duh` is not satisfied } fn main() { diff --git a/tests/ui/impl-trait/nested-return-type2-tait3.stderr b/tests/ui/impl-trait/nested-return-type2-tait3.stderr index c2332b6e4bd..72aa51a23f4 100644 --- a/tests/ui/impl-trait/nested-return-type2-tait3.stderr +++ b/tests/ui/impl-trait/nested-return-type2-tait3.stderr @@ -1,18 +1,17 @@ -error[E0277]: the trait bound `impl Send: Duh` is not satisfied - --> $DIR/nested-return-type2-tait3.rs:26:5 +warning: opaque type `Traitable` does not satisfy its associated type bounds + --> $DIR/nested-return-type2-tait3.rs:20:29 | -LL | || 42 - | ^^^^^ the trait `Duh` is not implemented for `impl Send` +LL | type Assoc: Duh; + | --- this associated type bound is unsatisfied for `impl Send` +... +LL | type Traitable = impl Trait<Assoc = impl Send>; + | ^^^^^^^^^^^^^^^^^ | - = help: the trait `Duh` is implemented for `i32` -note: required for `{closure@$DIR/nested-return-type2-tait3.rs:26:5: 26:7}` to implement `Trait` - --> $DIR/nested-return-type2-tait3.rs:14:31 + = note: `#[warn(opaque_hidden_inferred_bound)]` on by default +help: add this bound | -LL | impl<R: Duh, F: FnMut() -> R> Trait for F { - | --- ^^^^^ ^ - | | - | unsatisfied trait bound introduced here +LL | type Traitable = impl Trait<Assoc = impl Send + Duh>; + | +++++ -error: aborting due to previous error +warning: 1 warning emitted -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs b/tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs index 98dbaf036be..91a0e0d4829 100644 --- a/tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs +++ b/tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs @@ -1,7 +1,7 @@ // check-pass #![allow(incomplete_features)] -#![feature(adt_const_params, return_position_impl_trait_in_trait)] +#![feature(adt_const_params)] pub struct Element; diff --git a/tests/ui/impl-trait/where-allowed.rs b/tests/ui/impl-trait/where-allowed.rs index d3fab326e74..158dc5ab974 100644 --- a/tests/ui/impl-trait/where-allowed.rs +++ b/tests/ui/impl-trait/where-allowed.rs @@ -104,10 +104,9 @@ trait InTraitDefnParameters { fn in_parameters(_: impl Debug); } -// Disallowed +// Allowed trait InTraitDefnReturn { fn in_return() -> impl Debug; - //~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types } // Allowed and disallowed in trait impls @@ -124,7 +123,7 @@ impl DummyTrait for () { // Allowed fn in_trait_impl_return() -> impl Debug { () } - //~^ ERROR `impl Trait` only allowed in function and inherent method argument and return types + // Allowed } // Allowed diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr index bd7c9a94793..2d8895030f2 100644 --- a/tests/ui/impl-trait/where-allowed.stderr +++ b/tests/ui/impl-trait/where-allowed.stderr @@ -17,7 +17,7 @@ LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic | outer `impl Trait` error[E0658]: `impl Trait` in associated types is unstable - --> $DIR/where-allowed.rs:120:16 + --> $DIR/where-allowed.rs:119:16 | LL | type Out = impl Debug; | ^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | type Out = impl Debug; = help: add `#![feature(impl_trait_in_assoc_type)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:155:23 + --> $DIR/where-allowed.rs:154:23 | LL | type InTypeAlias<R> = impl Debug; | ^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | type InTypeAlias<R> = impl Debug; = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:158:39 + --> $DIR/where-allowed.rs:157:39 | LL | type InReturnInTypeAlias<R> = fn() -> impl Debug; | ^^^^^^^^^^ @@ -145,146 +145,128 @@ error[E0562]: `impl Trait` only allowed in function and inherent method argument LL | InTupleVariant(impl Debug), | ^^^^^^^^^^ -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in trait method return types - --> $DIR/where-allowed.rs:109:23 - | -LL | fn in_return() -> impl Debug; - | ^^^^^^^^^^ - | - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable - -error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `impl` method return types - --> $DIR/where-allowed.rs:126:34 - | -LL | fn in_trait_impl_return() -> impl Debug { () } - | ^^^^^^^^^^ - | - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable - error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `extern fn` params - --> $DIR/where-allowed.rs:139:33 + --> $DIR/where-allowed.rs:138:33 | LL | fn in_foreign_parameters(_: impl Debug); | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `extern fn` return types - --> $DIR/where-allowed.rs:142:31 + --> $DIR/where-allowed.rs:141:31 | LL | fn in_foreign_return() -> impl Debug; | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `fn` pointer return types - --> $DIR/where-allowed.rs:158:39 + --> $DIR/where-allowed.rs:157:39 | LL | type InReturnInTypeAlias<R> = fn() -> impl Debug; | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in traits - --> $DIR/where-allowed.rs:163:16 + --> $DIR/where-allowed.rs:162:16 | LL | impl PartialEq<impl Debug> for () { | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in impl headers - --> $DIR/where-allowed.rs:168:24 + --> $DIR/where-allowed.rs:167:24 | LL | impl PartialEq<()> for impl Debug { | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in impl headers - --> $DIR/where-allowed.rs:173:6 + --> $DIR/where-allowed.rs:172:6 | LL | impl impl Debug { | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in impl headers - --> $DIR/where-allowed.rs:179:24 + --> $DIR/where-allowed.rs:178:24 | LL | impl InInherentImplAdt<impl Debug> { | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in bounds - --> $DIR/where-allowed.rs:185:11 + --> $DIR/where-allowed.rs:184:11 | LL | where impl Debug: Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in bounds - --> $DIR/where-allowed.rs:192:15 + --> $DIR/where-allowed.rs:191:15 | LL | where Vec<impl Debug>: Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in bounds - --> $DIR/where-allowed.rs:199:24 + --> $DIR/where-allowed.rs:198:24 | LL | where T: PartialEq<impl Debug> | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `Fn` trait params - --> $DIR/where-allowed.rs:206:17 + --> $DIR/where-allowed.rs:205:17 | LL | where T: Fn(impl Debug) | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in `Fn` trait return types - --> $DIR/where-allowed.rs:213:22 + --> $DIR/where-allowed.rs:212:22 | LL | where T: Fn() -> impl Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in generic parameter defaults - --> $DIR/where-allowed.rs:219:40 + --> $DIR/where-allowed.rs:218:40 | LL | struct InStructGenericParamDefault<T = impl Debug>(T); | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in generic parameter defaults - --> $DIR/where-allowed.rs:223:36 + --> $DIR/where-allowed.rs:222:36 | LL | enum InEnumGenericParamDefault<T = impl Debug> { Variant(T) } | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in generic parameter defaults - --> $DIR/where-allowed.rs:227:38 + --> $DIR/where-allowed.rs:226:38 | LL | trait InTraitGenericParamDefault<T = impl Debug> {} | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in generic parameter defaults - --> $DIR/where-allowed.rs:231:41 + --> $DIR/where-allowed.rs:230:41 | LL | type InTypeAliasGenericParamDefault<T = impl Debug> = T; | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in generic parameter defaults - --> $DIR/where-allowed.rs:235:11 + --> $DIR/where-allowed.rs:234:11 | LL | impl <T = impl Debug> T {} | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in generic parameter defaults - --> $DIR/where-allowed.rs:242:40 + --> $DIR/where-allowed.rs:241:40 | LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {} | ^^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in variable bindings - --> $DIR/where-allowed.rs:248:29 + --> $DIR/where-allowed.rs:247:29 | LL | let _in_local_variable: impl Fn() = || {}; | ^^^^^^^^^ error[E0562]: `impl Trait` only allowed in function and inherent method argument and return types, not in closure return types - --> $DIR/where-allowed.rs:250:46 + --> $DIR/where-allowed.rs:249:46 | LL | let _in_return_in_local_variable = || -> impl Fn() { || {} }; | ^^^^^^^^^ error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/where-allowed.rs:235:7 + --> $DIR/where-allowed.rs:234:7 | LL | impl <T = impl Debug> T {} | ^^^^^^^^^^^^^^ @@ -294,7 +276,7 @@ LL | impl <T = impl Debug> T {} = note: `#[deny(invalid_type_param_default)]` on by default error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/where-allowed.rs:242:36 + --> $DIR/where-allowed.rs:241:36 | LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {} | ^^^^^^^^^^^^^^ @@ -303,14 +285,14 @@ LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {} = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887> error[E0118]: no nominal type found for inherent implementation - --> $DIR/where-allowed.rs:235:1 + --> $DIR/where-allowed.rs:234:1 | LL | impl <T = impl Debug> T {} | ^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type | = note: either implement a trait on it or create a newtype to wrap it instead -error: aborting due to 47 previous errors +error: aborting due to 45 previous errors Some errors have detailed explanations: E0118, E0562, E0658, E0666. For more information about an error, try `rustc --explain E0118`. diff --git a/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.rs b/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.rs new file mode 100644 index 00000000000..4544c898ab8 --- /dev/null +++ b/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.rs @@ -0,0 +1,61 @@ +struct MyError; + +fn foo(x: bool) -> Result<(), MyError> { + if x { + Err(MyError); + //~^ ERROR type annotations needed + } + + Ok(()) +} + +fn bar(x: bool) -> Result<(), MyError> { + if x { + Ok(()); + //~^ ERROR type annotations needed + } + + Ok(()) +} + +fn baz(x: bool) -> Result<(), MyError> { + //~^ ERROR mismatched types + if x { + 1; + } + + Err(MyError); +} + +fn error() -> Result<(), MyError> { + Err(MyError) +} + +fn bak(x: bool) -> Result<(), MyError> { + if x { + //~^ ERROR mismatched types + error(); + } else { + //~^ ERROR mismatched types + error(); + } +} + +fn bad(x: bool) -> Result<(), MyError> { + Err(MyError); //~ ERROR type annotations needed + Ok(()) +} + +fn with_closure<F, A, B>(_: F) -> i32 +where + F: FnOnce(A, B), +{ + 0 +} + +fn a() -> i32 { + with_closure(|x: u32, y| {}); //~ ERROR type annotations needed + 0 +} + +fn main() {} diff --git a/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.stderr b/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.stderr new file mode 100644 index 00000000000..1fea73529a8 --- /dev/null +++ b/tests/ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.stderr @@ -0,0 +1,98 @@ +error[E0282]: type annotations needed + --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:5:9 + | +LL | Err(MyError); + | ^^^ cannot infer type of the type parameter `T` declared on the enum `Result` + | +help: consider specifying the generic arguments + | +LL | Err::<T, MyError>(MyError); + | ++++++++++++++ +help: you might have meant to return this to infer its type parameters + | +LL | return Err(MyError); + | ++++++ + +error[E0282]: type annotations needed + --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:14:9 + | +LL | Ok(()); + | ^^ cannot infer type of the type parameter `E` declared on the enum `Result` + | +help: consider specifying the generic arguments + | +LL | Ok::<(), E>(()); + | +++++++++ +help: you might have meant to return this to infer its type parameters + | +LL | return Ok(()); + | ++++++ + +error[E0308]: mismatched types + --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:21:20 + | +LL | fn baz(x: bool) -> Result<(), MyError> { + | --- ^^^^^^^^^^^^^^^^^^^ expected `Result<(), MyError>`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression +... +LL | Err(MyError); + | - help: remove this semicolon to return this value + | + = note: expected enum `Result<(), MyError>` + found unit type `()` + +error[E0308]: mismatched types + --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:35:10 + | +LL | if x { + | __________^ +LL | | +LL | | error(); + | | - help: remove this semicolon to return this value +LL | | } else { + | |_____^ expected `Result<(), MyError>`, found `()` + | + = note: expected enum `Result<(), MyError>` + found unit type `()` + +error[E0308]: mismatched types + --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:38:12 + | +LL | } else { + | ____________^ +LL | | +LL | | error(); + | | - help: remove this semicolon to return this value +LL | | } + | |_____^ expected `Result<(), MyError>`, found `()` + | + = note: expected enum `Result<(), MyError>` + found unit type `()` + +error[E0282]: type annotations needed + --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:45:5 + | +LL | Err(MyError); + | ^^^ cannot infer type of the type parameter `T` declared on the enum `Result` + | +help: consider specifying the generic arguments + | +LL | Err::<T, MyError>(MyError); + | ++++++++++++++ + +error[E0282]: type annotations needed + --> $DIR/issue-86094-suggest-add-return-to-coerce-ret-ty.rs:57:27 + | +LL | with_closure(|x: u32, y| {}); + | ^ + | +help: consider giving this closure parameter an explicit type + | +LL | with_closure(|x: u32, y: /* Type */| {}); + | ++++++++++++ + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0282, E0308. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr index 4fc304cda60..317466eb322 100644 --- a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr +++ b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/intrinsic-raw_eq-const-bad.rs:5:5 | LL | std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at alloc3[0x0..0x4], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory error[E0080]: evaluation of constant value failed --> $DIR/intrinsic-raw_eq-const-bad.rs:11:5 diff --git a/tests/ui/iterators/invalid-iterator-chain-fixable.fixed b/tests/ui/iterators/invalid-iterator-chain-fixable.fixed new file mode 100644 index 00000000000..513b5bd13d8 --- /dev/null +++ b/tests/ui/iterators/invalid-iterator-chain-fixable.fixed @@ -0,0 +1,42 @@ +// run-rustfix +use std::collections::hash_set::Iter; +use std::collections::HashSet; + +fn iter_to_vec<'b, X>(i: Iter<'b, X>) -> Vec<X> where X: Clone { + let i = i.map(|x| x.clone()); + i.collect() //~ ERROR E0277 +} + +fn main() { + let v = vec![(0, 0)]; + let scores = v + .iter() + .map(|(a, b)| { + a + b + }); + println!("{}", scores.sum::<i32>()); //~ ERROR E0277 + println!( + "{}", + vec![0, 1] + .iter() + .map(|x| x * 2) + .map(|x| { x }) + .map(|x| { x }) + .sum::<i32>(), //~ ERROR E0277 + ); + println!("{}", vec![0, 1].iter().map(|x| { x }).sum::<i32>()); //~ ERROR E0277 + let a = vec![0]; + let b = a.into_iter(); + let c = b.map(|x| x + 1); + let d = c.filter(|x| *x > 10 ); + let e = d.map(|x| { + x + 1 + }); + let f = e.filter(|_| false); + let g: Vec<i32> = f.collect(); //~ ERROR E0277 + println!("{g:?}"); + + let mut s = HashSet::new(); + s.insert(1u8); + println!("{:?}", iter_to_vec(s.iter())); +} diff --git a/tests/ui/iterators/invalid-iterator-chain-fixable.rs b/tests/ui/iterators/invalid-iterator-chain-fixable.rs new file mode 100644 index 00000000000..79b861702c7 --- /dev/null +++ b/tests/ui/iterators/invalid-iterator-chain-fixable.rs @@ -0,0 +1,42 @@ +// run-rustfix +use std::collections::hash_set::Iter; +use std::collections::HashSet; + +fn iter_to_vec<'b, X>(i: Iter<'b, X>) -> Vec<X> { + let i = i.map(|x| x.clone()); + i.collect() //~ ERROR E0277 +} + +fn main() { + let v = vec![(0, 0)]; + let scores = v + .iter() + .map(|(a, b)| { + a + b; + }); + println!("{}", scores.sum::<i32>()); //~ ERROR E0277 + println!( + "{}", + vec![0, 1] + .iter() + .map(|x| x * 2) + .map(|x| { x; }) + .map(|x| { x }) + .sum::<i32>(), //~ ERROR E0277 + ); + println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>()); //~ ERROR E0277 + let a = vec![0]; + let b = a.into_iter(); + let c = b.map(|x| x + 1); + let d = c.filter(|x| *x > 10 ); + let e = d.map(|x| { + x + 1; + }); + let f = e.filter(|_| false); + let g: Vec<i32> = f.collect(); //~ ERROR E0277 + println!("{g:?}"); + + let mut s = HashSet::new(); + s.insert(1u8); + println!("{:?}", iter_to_vec(s.iter())); +} diff --git a/tests/ui/iterators/invalid-iterator-chain-fixable.stderr b/tests/ui/iterators/invalid-iterator-chain-fixable.stderr new file mode 100644 index 00000000000..1bfe765e78a --- /dev/null +++ b/tests/ui/iterators/invalid-iterator-chain-fixable.stderr @@ -0,0 +1,157 @@ +error[E0277]: a value of type `Vec<X>` cannot be built from an iterator over elements of type `&X` + --> $DIR/invalid-iterator-chain-fixable.rs:7:7 + | +LL | let i = i.map(|x| x.clone()); + | ------- this method call is cloning the reference `&X`, not `X` which doesn't implement `Clone` +LL | i.collect() + | ^^^^^^^ value of type `Vec<X>` cannot be built from `std::iter::Iterator<Item=&X>` + | + = help: the trait `FromIterator<&X>` is not implemented for `Vec<X>` + = help: the trait `FromIterator<X>` is implemented for `Vec<X>` + = help: for that trait implementation, expected `X`, found `&X` +note: the method call chain might not have had the expected associated types + --> $DIR/invalid-iterator-chain-fixable.rs:5:26 + | +LL | fn iter_to_vec<'b, X>(i: Iter<'b, X>) -> Vec<X> { + | ^^^^^^^^^^^ `Iterator::Item` is `&X` here +LL | let i = i.map(|x| x.clone()); + | ------------------ `Iterator::Item` remains `&X` here +note: required by a bound in `collect` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider further restricting type parameter `X` + | +LL | fn iter_to_vec<'b, X>(i: Iter<'b, X>) -> Vec<X> where X: Clone { + | ++++++++++++++ + +error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()` + --> $DIR/invalid-iterator-chain-fixable.rs:17:33 + | +LL | println!("{}", scores.sum::<i32>()); + | --- ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>` + | | + | required by a bound introduced by this call + | + = help: the trait `Sum<()>` is not implemented for `i32` + = help: the following other types implement trait `Sum<A>`: + <i32 as Sum> + <i32 as Sum<&'a i32>> +note: the method call chain might not have had the expected associated types + --> $DIR/invalid-iterator-chain-fixable.rs:14:10 + | +LL | let v = vec![(0, 0)]; + | ------------ this expression has type `Vec<({integer}, {integer})>` +LL | let scores = v +LL | .iter() + | ------ `Iterator::Item` is `&({integer}, {integer})` here +LL | .map(|(a, b)| { + | __________^ +LL | | a + b; +LL | | }); + | |__________^ `Iterator::Item` changed to `()` here +note: required by a bound in `std::iter::Iterator::sum` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider removing this semicolon + | +LL - a + b; +LL + a + b + | + +error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()` + --> $DIR/invalid-iterator-chain-fixable.rs:25:20 + | +LL | .sum::<i32>(), + | --- ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>` + | | + | required by a bound introduced by this call + | + = help: the trait `Sum<()>` is not implemented for `i32` + = help: the following other types implement trait `Sum<A>`: + <i32 as Sum> + <i32 as Sum<&'a i32>> +note: the method call chain might not have had the expected associated types + --> $DIR/invalid-iterator-chain-fixable.rs:23:14 + | +LL | vec![0, 1] + | ---------- this expression has type `Vec<{integer}>` +LL | .iter() + | ------ `Iterator::Item` is `&{integer}` here +LL | .map(|x| x * 2) + | -------------- `Iterator::Item` changed to `{integer}` here +LL | .map(|x| { x; }) + | ^^^^^^^^^^^^^^^ `Iterator::Item` changed to `()` here +LL | .map(|x| { x }) + | -------------- `Iterator::Item` remains `()` here +note: required by a bound in `std::iter::Iterator::sum` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider removing this semicolon + | +LL - .map(|x| { x; }) +LL + .map(|x| { x }) + | + +error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()` + --> $DIR/invalid-iterator-chain-fixable.rs:27:60 + | +LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>()); + | --- ^^^ value of type `i32` cannot be made by summing a `std::iter::Iterator<Item=()>` + | | + | required by a bound introduced by this call + | + = help: the trait `Sum<()>` is not implemented for `i32` + = help: the following other types implement trait `Sum<A>`: + <i32 as Sum> + <i32 as Sum<&'a i32>> +note: the method call chain might not have had the expected associated types + --> $DIR/invalid-iterator-chain-fixable.rs:27:38 + | +LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>()); + | ---------- ------ ^^^^^^^^^^^^^^^ `Iterator::Item` changed to `()` here + | | | + | | `Iterator::Item` is `&{integer}` here + | this expression has type `Vec<{integer}>` +note: required by a bound in `std::iter::Iterator::sum` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider removing this semicolon + | +LL - println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>()); +LL + println!("{}", vec![0, 1].iter().map(|x| { x }).sum::<i32>()); + | + +error[E0277]: a value of type `Vec<i32>` cannot be built from an iterator over elements of type `()` + --> $DIR/invalid-iterator-chain-fixable.rs:36:25 + | +LL | let g: Vec<i32> = f.collect(); + | ^^^^^^^ value of type `Vec<i32>` cannot be built from `std::iter::Iterator<Item=()>` + | + = help: the trait `FromIterator<()>` is not implemented for `Vec<i32>` + = help: the trait `FromIterator<i32>` is implemented for `Vec<i32>` + = help: for that trait implementation, expected `i32`, found `()` +note: the method call chain might not have had the expected associated types + --> $DIR/invalid-iterator-chain-fixable.rs:32:15 + | +LL | let a = vec![0]; + | ------- this expression has type `Vec<{integer}>` +LL | let b = a.into_iter(); + | ----------- `Iterator::Item` is `{integer}` here +LL | let c = b.map(|x| x + 1); + | -------------- `Iterator::Item` remains `{integer}` here +LL | let d = c.filter(|x| *x > 10 ); + | -------------------- `Iterator::Item` remains `{integer}` here +LL | let e = d.map(|x| { + | _______________^ +LL | | x + 1; +LL | | }); + | |______^ `Iterator::Item` changed to `()` here +LL | let f = e.filter(|_| false); + | ----------------- `Iterator::Item` remains `()` here +note: required by a bound in `collect` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider removing this semicolon + | +LL - x + 1; +LL + x + 1 + | + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/iterators/invalid-iterator-chain.stderr b/tests/ui/iterators/invalid-iterator-chain.stderr index 2601c9c0d69..4dc13086912 100644 --- a/tests/ui/iterators/invalid-iterator-chain.stderr +++ b/tests/ui/iterators/invalid-iterator-chain.stderr @@ -1,6 +1,8 @@ error[E0277]: a value of type `Vec<X>` cannot be built from an iterator over elements of type `&X` --> $DIR/invalid-iterator-chain.rs:6:7 | +LL | let i = i.map(|x| x.clone()); + | ------- this method call is cloning the reference `&X`, not `X` which doesn't implement `Clone` LL | i.collect() | ^^^^^^^ value of type `Vec<X>` cannot be built from `std::iter::Iterator<Item=&X>` | @@ -16,6 +18,10 @@ LL | let i = i.map(|x| x.clone()); | ------------------ `Iterator::Item` remains `&X` here note: required by a bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider further restricting type parameter `X` + | +LL | fn iter_to_vec<'b, X>(i: Iter<'b, X>) -> Vec<X> where X: Clone { + | ++++++++++++++ error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()` --> $DIR/invalid-iterator-chain.rs:15:33 @@ -43,6 +49,11 @@ LL | | }); | |__________^ `Iterator::Item` changed to `()` here note: required by a bound in `std::iter::Iterator::sum` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider removing this semicolon + | +LL - a + b; +LL + a + b + | error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `()` --> $DIR/invalid-iterator-chain.rs:26:20 @@ -77,6 +88,11 @@ LL | .map(|x| { x; }) | ^^^^^^^^^^^^^^^ `Iterator::Item` changed to `()` here note: required by a bound in `std::iter::Iterator::sum` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider removing this semicolon + | +LL - .map(|x| { x; }) +LL + .map(|x| { x }) + | error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `f64` --> $DIR/invalid-iterator-chain.rs:36:20 @@ -130,6 +146,11 @@ LL | println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>()); | this expression has type `Vec<{integer}>` note: required by a bound in `std::iter::Iterator::sum` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider removing this semicolon + | +LL - println!("{}", vec![0, 1].iter().map(|x| { x; }).sum::<i32>()); +LL + println!("{}", vec![0, 1].iter().map(|x| { x }).sum::<i32>()); + | error[E0277]: a value of type `i32` cannot be made by summing an iterator over elements of type `&()` --> $DIR/invalid-iterator-chain.rs:39:46 @@ -182,6 +203,11 @@ LL | let f = e.filter(|_| false); | ----------------- `Iterator::Item` remains `()` here note: required by a bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +help: consider removing this semicolon + | +LL - x + 1; +LL + x + 1 + | error: aborting due to 7 previous errors diff --git a/tests/ui/linkage-attr/link-self-contained-consistency.many.stderr b/tests/ui/linkage-attr/link-self-contained-consistency.many.stderr new file mode 100644 index 00000000000..a5fc96b4e0b --- /dev/null +++ b/tests/ui/linkage-attr/link-self-contained-consistency.many.stderr @@ -0,0 +1,2 @@ +error: some `-C link-self-contained` components were both enabled and disabled: crto, linker + diff --git a/tests/ui/linkage-attr/link-self-contained-consistency.one.stderr b/tests/ui/linkage-attr/link-self-contained-consistency.one.stderr new file mode 100644 index 00000000000..5982b7a618e --- /dev/null +++ b/tests/ui/linkage-attr/link-self-contained-consistency.one.stderr @@ -0,0 +1,2 @@ +error: some `-C link-self-contained` components were both enabled and disabled: linker + diff --git a/tests/ui/linkage-attr/link-self-contained-consistency.rs b/tests/ui/linkage-attr/link-self-contained-consistency.rs new file mode 100644 index 00000000000..9be72f559a9 --- /dev/null +++ b/tests/ui/linkage-attr/link-self-contained-consistency.rs @@ -0,0 +1,10 @@ +// Checks that self-contained linking components cannot be both enabled and disabled at the same +// time on the CLI. + +// check-fail +// revisions: one many +// [one] compile-flags: -Clink-self-contained=-linker -Clink-self-contained=+linker -Zunstable-options +// [many] compile-flags: -Clink-self-contained=+linker,+crto -Clink-self-contained=-linker,-crto -Zunstable-options +// ignore-tidy-linelength + +fn main() {} diff --git a/tests/ui/lint/bare-trait-objects-path.stderr b/tests/ui/lint/bare-trait-objects-path.stderr index a19f4963c23..01ca08a6f19 100644 --- a/tests/ui/lint/bare-trait-objects-path.stderr +++ b/tests/ui/lint/bare-trait-objects-path.stderr @@ -16,7 +16,7 @@ error[E0223]: ambiguous associated type --> $DIR/bare-trait-objects-path.rs:23:12 | LL | let _: Dyn::Ty; - | ^^^^^^^ help: use the fully-qualified path: `<dyn Dyn as Assoc>::Ty` + | ^^^^^^^ help: use fully-qualified syntax: `<dyn Dyn as Assoc>::Ty` warning: trait objects without an explicit `dyn` are deprecated --> $DIR/bare-trait-objects-path.rs:14:5 diff --git a/tests/ui/lint/lint-type-overflow.stderr b/tests/ui/lint/lint-type-overflow.stderr index 48d8228b802..971c3eb9b2e 100644 --- a/tests/ui/lint/lint-type-overflow.stderr +++ b/tests/ui/lint/lint-type-overflow.stderr @@ -29,21 +29,21 @@ LL | let x1: i8 = 128; = help: consider using the type `u8` instead error: literal out of range for `i8` - --> $DIR/lint-type-overflow.rs:18:19 + --> $DIR/lint-type-overflow.rs:18:18 | LL | let x3: i8 = -129; - | ^^^ + | ^^^^ | - = note: the literal `129` does not fit into the type `i8` whose range is `-128..=127` + = note: the literal `-129` does not fit into the type `i8` whose range is `-128..=127` = help: consider using the type `i16` instead error: literal out of range for `i8` - --> $DIR/lint-type-overflow.rs:19:19 + --> $DIR/lint-type-overflow.rs:19:18 | LL | let x3: i8 = -(129); - | ^^^^^ + | ^^^^^^ | - = note: the literal `129` does not fit into the type `i8` whose range is `-128..=127` + = note: the literal `-(129)` does not fit into the type `i8` whose range is `-128..=127` = help: consider using the type `i16` instead error: literal out of range for `i8` @@ -74,12 +74,12 @@ LL | let x = 128_i8; = help: consider using the type `u8` instead error: literal out of range for `i8` - --> $DIR/lint-type-overflow.rs:28:14 + --> $DIR/lint-type-overflow.rs:28:13 | LL | let x = -129_i8; - | ^^^^^^ + | ^^^^^^^ | - = note: the literal `129_i8` does not fit into the type `i8` whose range is `-128..=127` + = note: the literal `-129_i8` does not fit into the type `i8` whose range is `-128..=127` = help: consider using the type `i16` instead error: literal out of range for `i32` @@ -101,21 +101,21 @@ LL | let x = 2147483648_i32; = help: consider using the type `u32` instead error: literal out of range for `i32` - --> $DIR/lint-type-overflow.rs:36:19 + --> $DIR/lint-type-overflow.rs:36:18 | LL | let x: i32 = -2147483649; - | ^^^^^^^^^^ + | ^^^^^^^^^^^ | - = note: the literal `2147483649` does not fit into the type `i32` whose range is `-2147483648..=2147483647` + = note: the literal `-2147483649` does not fit into the type `i32` whose range is `-2147483648..=2147483647` = help: consider using the type `i64` instead error: literal out of range for `i32` - --> $DIR/lint-type-overflow.rs:37:14 + --> $DIR/lint-type-overflow.rs:37:13 | LL | let x = -2147483649_i32; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | - = note: the literal `2147483649_i32` does not fit into the type `i32` whose range is `-2147483648..=2147483647` + = note: the literal `-2147483649_i32` does not fit into the type `i32` whose range is `-2147483648..=2147483647` = help: consider using the type `i64` instead error: literal out of range for `i32` @@ -146,21 +146,21 @@ LL | let x = 18446744073709551615_i64; = help: consider using the type `u64` instead error: literal out of range for `i64` - --> $DIR/lint-type-overflow.rs:43:19 + --> $DIR/lint-type-overflow.rs:43:18 | LL | let x: i64 = -9223372036854775809; - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ | - = note: the literal `9223372036854775809` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` + = note: the literal `-9223372036854775809` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` = help: consider using the type `i128` instead error: literal out of range for `i64` - --> $DIR/lint-type-overflow.rs:44:14 + --> $DIR/lint-type-overflow.rs:44:13 | LL | let x = -9223372036854775809_i64; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: the literal `9223372036854775809_i64` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` + = note: the literal `-9223372036854775809_i64` does not fit into the type `i64` whose range is `-9223372036854775808..=9223372036854775807` = help: consider using the type `i128` instead error: aborting due to 18 previous errors diff --git a/tests/ui/lint/missing-copy-implementations-non-exhaustive.rs b/tests/ui/lint/missing-copy-implementations-non-exhaustive.rs new file mode 100644 index 00000000000..2d5e90720ef --- /dev/null +++ b/tests/ui/lint/missing-copy-implementations-non-exhaustive.rs @@ -0,0 +1,25 @@ +// Test for issue #116766. +// Ensure that we don't suggest impl'ing `Copy` for a type if it or at least one +// of it's variants are marked as `non_exhaustive`. + +// check-pass + +#![deny(missing_copy_implementations)] + +#[non_exhaustive] +pub enum MyEnum { + A, +} + +#[non_exhaustive] +pub struct MyStruct { + foo: usize, +} + +pub enum MyEnum2 { + #[non_exhaustive] + A, + B, +} + +fn main() {} diff --git a/tests/ui/macros/assert-long-condition.rs b/tests/ui/macros/assert-long-condition.rs new file mode 100644 index 00000000000..1974ec9d6db --- /dev/null +++ b/tests/ui/macros/assert-long-condition.rs @@ -0,0 +1,9 @@ +// run-fail +// check-run-results +// exec-env:RUST_BACKTRACE=0 +// ignore-emscripten no processes +// ignore-tidy-linelength + +fn main() { + assert!(1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 == 0); +} diff --git a/tests/ui/macros/assert-long-condition.run.stderr b/tests/ui/macros/assert-long-condition.run.stderr new file mode 100644 index 00000000000..16e56c92735 --- /dev/null +++ b/tests/ui/macros/assert-long-condition.run.stderr @@ -0,0 +1,4 @@ +thread 'main' panicked at $DIR/assert-long-condition.rs:8:5: +assertion failed: 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + + 19 + 20 + 21 + 22 + 23 + 24 + 25 == 0 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/ui/match/match-range-fail-2.stderr b/tests/ui/match/match-range-fail-2.stderr index 52a2bf2b34a..089fa851f97 100644 --- a/tests/ui/match/match-range-fail-2.stderr +++ b/tests/ui/match/match-range-fail-2.stderr @@ -2,19 +2,19 @@ error[E0030]: lower range bound must be less than or equal to upper --> $DIR/match-range-fail-2.rs:5:9 | LL | 6 ..= 1 => { } - | ^ lower bound larger than upper bound + | ^^^^^^^ lower bound larger than upper bound error[E0579]: lower range bound must be less than upper --> $DIR/match-range-fail-2.rs:11:9 | LL | 0 .. 0 => { } - | ^ + | ^^^^^^ error[E0030]: lower range bound must be less than or equal to upper --> $DIR/match-range-fail-2.rs:17:9 | LL | 0xFFFF_FFFF_FFFF_FFFF ..= 1 => { } - | ^^^^^^^^^^^^^^^^^^^^^ lower bound larger than upper bound + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ lower bound larger than upper bound error: aborting due to 3 previous errors diff --git a/tests/ui/match/validate-range-endpoints.rs b/tests/ui/match/validate-range-endpoints.rs new file mode 100644 index 00000000000..1d1737f8b82 --- /dev/null +++ b/tests/ui/match/validate-range-endpoints.rs @@ -0,0 +1,59 @@ +#![feature(exclusive_range_pattern)] +#![feature(inline_const_pat)] +#![allow(incomplete_features)] +#![allow(overlapping_range_endpoints)] + +fn main() { + const TOO_BIG: u8 = 256; + match 0u8 { + 1..257 => {} + //~^ ERROR literal out of range + 1..=256 => {} + //~^ ERROR literal out of range + + // overflow is detected in a later pass for these + 0..257 => {} + 0..=256 => {} + 256..=100 => {} + + // There isn't really a way to detect these + 1..=TOO_BIG => {} + //~^ ERROR lower range bound must be less than or equal to upper + 1..=const { 256 } => {} + //~^ ERROR lower range bound must be less than or equal to upper + _ => {} + } + + match 0u64 { + 10000000000000000000..=99999999999999999999 => {} + //~^ ERROR literal out of range + _ => {} + } + + match 0i8 { + 0..129 => {} + //~^ ERROR literal out of range + 0..=128 => {} + //~^ ERROR literal out of range + -129..0 => {} + //~^ ERROR literal out of range + -10000..=-20 => {} + //~^ ERROR literal out of range + + // overflow is detected in a later pass for these + 128..=0 => {} + 0..-129 => {} + -10000..=0 => {} + _ => {} + } + + // FIXME: error message is confusing + match 0i8 { + //~^ ERROR `i8::MIN..=-17_i8` and `1_i8..=i8::MAX` not covered + -10000..=0 => {} + } + match 0i8 { + //~^ ERROR `i8::MIN..=-17_i8` not covered + -10000.. => {} + } +} diff --git a/tests/ui/match/validate-range-endpoints.stderr b/tests/ui/match/validate-range-endpoints.stderr new file mode 100644 index 00000000000..0813fccff51 --- /dev/null +++ b/tests/ui/match/validate-range-endpoints.stderr @@ -0,0 +1,84 @@ +error: literal out of range for `u8` + --> $DIR/validate-range-endpoints.rs:9:12 + | +LL | 1..257 => {} + | ^^^ this value does not fit into the type `u8` whose range is `0..=255` + +error: literal out of range for `u8` + --> $DIR/validate-range-endpoints.rs:11:13 + | +LL | 1..=256 => {} + | ^^^ this value does not fit into the type `u8` whose range is `0..=255` + +error[E0030]: lower range bound must be less than or equal to upper + --> $DIR/validate-range-endpoints.rs:20:9 + | +LL | 1..=TOO_BIG => {} + | ^^^^^^^^^^^ lower bound larger than upper bound + +error[E0030]: lower range bound must be less than or equal to upper + --> $DIR/validate-range-endpoints.rs:22:9 + | +LL | 1..=const { 256 } => {} + | ^^^^^^^^^^^^^^^^^ lower bound larger than upper bound + +error: literal out of range for `u64` + --> $DIR/validate-range-endpoints.rs:28:32 + | +LL | 10000000000000000000..=99999999999999999999 => {} + | ^^^^^^^^^^^^^^^^^^^^ this value does not fit into the type `u64` whose range is `0..=18446744073709551615` + +error: literal out of range for `i8` + --> $DIR/validate-range-endpoints.rs:34:12 + | +LL | 0..129 => {} + | ^^^ this value does not fit into the type `i8` whose range is `-128..=127` + +error: literal out of range for `i8` + --> $DIR/validate-range-endpoints.rs:36:13 + | +LL | 0..=128 => {} + | ^^^ this value does not fit into the type `i8` whose range is `-128..=127` + +error: literal out of range for `i8` + --> $DIR/validate-range-endpoints.rs:38:9 + | +LL | -129..0 => {} + | ^^^^ this value does not fit into the type `i8` whose range is `-128..=127` + +error: literal out of range for `i8` + --> $DIR/validate-range-endpoints.rs:40:9 + | +LL | -10000..=-20 => {} + | ^^^^^^ this value does not fit into the type `i8` whose range is `-128..=127` + +error[E0004]: non-exhaustive patterns: `i8::MIN..=-17_i8` and `1_i8..=i8::MAX` not covered + --> $DIR/validate-range-endpoints.rs:51:11 + | +LL | match 0i8 { + | ^^^ patterns `i8::MIN..=-17_i8` and `1_i8..=i8::MAX` not covered + | + = note: the matched value is of type `i8` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ -10000..=0 => {}, +LL + i8::MIN..=-17_i8 | 1_i8..=i8::MAX => todo!() + | + +error[E0004]: non-exhaustive patterns: `i8::MIN..=-17_i8` not covered + --> $DIR/validate-range-endpoints.rs:55:11 + | +LL | match 0i8 { + | ^^^ pattern `i8::MIN..=-17_i8` not covered + | + = note: the matched value is of type `i8` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ -10000.. => {}, +LL + i8::MIN..=-17_i8 => todo!() + | + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0004, E0030. +For more information about an error, try `rustc --explain E0004`. diff --git a/tests/ui/methods/disambiguate-multiple-blanket-impl.rs b/tests/ui/methods/disambiguate-multiple-blanket-impl.rs new file mode 100644 index 00000000000..6a17f6a2172 --- /dev/null +++ b/tests/ui/methods/disambiguate-multiple-blanket-impl.rs @@ -0,0 +1,38 @@ +trait A { + type Type; + const CONST: usize; + fn foo(&self); +} + +trait B { + type Type; + const CONST: usize; + fn foo(&self); +} + +#[derive(Debug)] +struct S; + +impl<T: std::fmt::Debug> A for T { + type Type = (); + const CONST: usize = 1; //~ NOTE candidate #1 + fn foo(&self) {} //~ NOTE candidate #1 +} + +impl<T: std::fmt::Debug> B for T { + type Type = (); + const CONST: usize = 2; //~ NOTE candidate #2 + fn foo(&self) {} //~ NOTE candidate #2 +} + +fn main() { + let s = S; + S::foo(&s); //~ ERROR multiple applicable items in scope + //~^ NOTE multiple `foo` found + //~| HELP use fully-qualified syntax to disambiguate + S::CONST; //~ ERROR multiple applicable items in scope + //~^ NOTE multiple `CONST` found + //~| HELP use fully-qualified syntax to disambiguate + let _: S::Type; //~ ERROR ambiguous associated type + //~^ HELP use fully-qualified syntax +} diff --git a/tests/ui/methods/disambiguate-multiple-blanket-impl.stderr b/tests/ui/methods/disambiguate-multiple-blanket-impl.stderr new file mode 100644 index 00000000000..a9e9c679fdb --- /dev/null +++ b/tests/ui/methods/disambiguate-multiple-blanket-impl.stderr @@ -0,0 +1,63 @@ +error[E0223]: ambiguous associated type + --> $DIR/disambiguate-multiple-blanket-impl.rs:36:12 + | +LL | let _: S::Type; + | ^^^^^^^ + | +help: use fully-qualified syntax + | +LL | let _: <S as A>::Type; + | ~~~~~~~~~~~~~~ +LL | let _: <S as B>::Type; + | ~~~~~~~~~~~~~~ + +error[E0034]: multiple applicable items in scope + --> $DIR/disambiguate-multiple-blanket-impl.rs:30:8 + | +LL | S::foo(&s); + | ^^^ multiple `foo` found + | +note: candidate #1 is defined in an impl of the trait `A` for the type `T` + --> $DIR/disambiguate-multiple-blanket-impl.rs:19:5 + | +LL | fn foo(&self) {} + | ^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `B` for the type `T` + --> $DIR/disambiguate-multiple-blanket-impl.rs:25:5 + | +LL | fn foo(&self) {} + | ^^^^^^^^^^^^^ +help: use fully-qualified syntax to disambiguate + | +LL | <T as A>::foo(&s); + | ~~~~~~~~~~ +LL | <T as B>::foo(&s); + | ~~~~~~~~~~ + +error[E0034]: multiple applicable items in scope + --> $DIR/disambiguate-multiple-blanket-impl.rs:33:8 + | +LL | S::CONST; + | ^^^^^ multiple `CONST` found + | +note: candidate #1 is defined in an impl of the trait `A` for the type `T` + --> $DIR/disambiguate-multiple-blanket-impl.rs:18:5 + | +LL | const CONST: usize = 1; + | ^^^^^^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `B` for the type `T` + --> $DIR/disambiguate-multiple-blanket-impl.rs:24:5 + | +LL | const CONST: usize = 2; + | ^^^^^^^^^^^^^^^^^^ +help: use fully-qualified syntax to disambiguate + | +LL | <T as A>::CONST; + | ~~~~~~~~~~ +LL | <T as B>::CONST; + | ~~~~~~~~~~ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0034, E0223. +For more information about an error, try `rustc --explain E0034`. diff --git a/tests/ui/methods/disambiguate-multiple-impl.rs b/tests/ui/methods/disambiguate-multiple-impl.rs new file mode 100644 index 00000000000..9a82ff01574 --- /dev/null +++ b/tests/ui/methods/disambiguate-multiple-impl.rs @@ -0,0 +1,37 @@ +trait A { + type Type; + const CONST: usize; + fn foo(&self); +} + +trait B { + type Type; + const CONST: usize; + fn foo(&self); +} + +struct S; + +impl A for S { + type Type = (); + const CONST: usize = 1; //~ NOTE candidate #1 + fn foo(&self) {} //~ NOTE candidate #1 +} + +impl B for S { + type Type = (); + const CONST: usize = 2; //~ NOTE candidate #2 + fn foo(&self) {} //~ NOTE candidate #2 +} + +fn main() { + let s = S; + S::foo(&s); //~ ERROR multiple applicable items in scope + //~^ NOTE multiple `foo` found + //~| HELP use fully-qualified syntax + let _: S::Type = (); //~ ERROR ambiguous associated type + //~| HELP use fully-qualified syntax + let _ = S::CONST; //~ ERROR multiple applicable items in scope + //~^ NOTE multiple `CONST` found + //~| HELP use fully-qualified syntax +} diff --git a/tests/ui/methods/disambiguate-multiple-impl.stderr b/tests/ui/methods/disambiguate-multiple-impl.stderr new file mode 100644 index 00000000000..901bfc30a3f --- /dev/null +++ b/tests/ui/methods/disambiguate-multiple-impl.stderr @@ -0,0 +1,63 @@ +error[E0223]: ambiguous associated type + --> $DIR/disambiguate-multiple-impl.rs:32:12 + | +LL | let _: S::Type = (); + | ^^^^^^^ + | +help: use fully-qualified syntax + | +LL | let _: <S as A>::Type = (); + | ~~~~~~~~~~~~~~ +LL | let _: <S as B>::Type = (); + | ~~~~~~~~~~~~~~ + +error[E0034]: multiple applicable items in scope + --> $DIR/disambiguate-multiple-impl.rs:29:8 + | +LL | S::foo(&s); + | ^^^ multiple `foo` found + | +note: candidate #1 is defined in an impl of the trait `A` for the type `S` + --> $DIR/disambiguate-multiple-impl.rs:18:5 + | +LL | fn foo(&self) {} + | ^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `B` for the type `S` + --> $DIR/disambiguate-multiple-impl.rs:24:5 + | +LL | fn foo(&self) {} + | ^^^^^^^^^^^^^ +help: use fully-qualified syntax to disambiguate + | +LL | <S as A>::foo(&s); + | ~~~~~~~~~~ +LL | <S as B>::foo(&s); + | ~~~~~~~~~~ + +error[E0034]: multiple applicable items in scope + --> $DIR/disambiguate-multiple-impl.rs:34:16 + | +LL | let _ = S::CONST; + | ^^^^^ multiple `CONST` found + | +note: candidate #1 is defined in an impl of the trait `A` for the type `S` + --> $DIR/disambiguate-multiple-impl.rs:17:5 + | +LL | const CONST: usize = 1; + | ^^^^^^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `B` for the type `S` + --> $DIR/disambiguate-multiple-impl.rs:23:5 + | +LL | const CONST: usize = 2; + | ^^^^^^^^^^^^^^^^^^ +help: use fully-qualified syntax to disambiguate + | +LL | let _ = <S as A>::CONST; + | ~~~~~~~~~~ +LL | let _ = <S as B>::CONST; + | ~~~~~~~~~~ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0034, E0223. +For more information about an error, try `rustc --explain E0034`. diff --git a/tests/ui/methods/disambiguate-multiple-trait-2.rs b/tests/ui/methods/disambiguate-multiple-trait-2.rs new file mode 100644 index 00000000000..829491d824d --- /dev/null +++ b/tests/ui/methods/disambiguate-multiple-trait-2.rs @@ -0,0 +1,54 @@ +trait A { + type Type; //~ NOTE ambiguous `Type` from `A` + const CONST: usize = 1; //~ NOTE candidate #1 + fn foo(&self); //~ NOTE candidate #1 +} + +trait B { + type Type; //~ NOTE ambiguous `Type` from `B` + const CONST: usize; //~ NOTE candidate #2 + fn foo(&self); //~ NOTE candidate #2 +} + +trait C: A + B {} + +fn a<T: C>(t: T) { + t.foo(); //~ ERROR multiple applicable items in scope + //~^ NOTE multiple `foo` found + //~| HELP disambiguate the method + //~| HELP disambiguate the method + let _ = T::CONST; //~ ERROR multiple applicable items in scope + //~^ NOTE multiple `CONST` found + //~| HELP use fully-qualified syntax + let _: T::Type; //~ ERROR ambiguous associated type + //~^ NOTE ambiguous associated type `Type` + //~| HELP use fully-qualified syntax + //~| HELP use fully-qualified syntax +} + +#[derive(Debug)] +struct S; + +impl<T: std::fmt::Debug> A for T { + type Type = (); + const CONST: usize = 1; //~ NOTE candidate #1 + fn foo(&self) {} //~ NOTE candidate #1 +} + +impl<T: std::fmt::Debug> B for T { + type Type = (); + const CONST: usize = 1; //~ NOTE candidate #2 + fn foo(&self) {} //~ NOTE candidate #2 +} + +fn main() { + let s = S; + S::foo(&s); //~ ERROR multiple applicable items in scope + //~^ NOTE multiple `foo` found + //~| HELP use fully-qualified syntax + let _ = S::CONST; //~ ERROR multiple applicable items in scope + //~^ NOTE multiple `CONST` found + //~| HELP use fully-qualified syntax + let _: S::Type; //~ ERROR ambiguous associated type + //~^ HELP use fully-qualified syntax +} diff --git a/tests/ui/methods/disambiguate-multiple-trait-2.stderr b/tests/ui/methods/disambiguate-multiple-trait-2.stderr new file mode 100644 index 00000000000..0f9c60ce243 --- /dev/null +++ b/tests/ui/methods/disambiguate-multiple-trait-2.stderr @@ -0,0 +1,132 @@ +error[E0221]: ambiguous associated type `Type` in bounds of `T` + --> $DIR/disambiguate-multiple-trait-2.rs:23:12 + | +LL | type Type; + | --------- ambiguous `Type` from `A` +... +LL | type Type; + | --------- ambiguous `Type` from `B` +... +LL | let _: T::Type; + | ^^^^^^^ ambiguous associated type `Type` + | +help: use fully-qualified syntax to disambiguate + | +LL | let _: <T as A>::Type; + | ~~~~~~~~~~ +help: use fully-qualified syntax to disambiguate + | +LL | let _: <T as B>::Type; + | ~~~~~~~~~~ + +error[E0034]: multiple applicable items in scope + --> $DIR/disambiguate-multiple-trait-2.rs:16:7 + | +LL | t.foo(); + | ^^^ multiple `foo` found + | +note: candidate #1 is defined in the trait `A` + --> $DIR/disambiguate-multiple-trait-2.rs:4:5 + | +LL | fn foo(&self); + | ^^^^^^^^^^^^^^ +note: candidate #2 is defined in the trait `B` + --> $DIR/disambiguate-multiple-trait-2.rs:10:5 + | +LL | fn foo(&self); + | ^^^^^^^^^^^^^^ +help: disambiguate the method for candidate #1 + | +LL | A::foo(t); + | ~~~~~~~~~ +help: disambiguate the method for candidate #2 + | +LL | B::foo(t); + | ~~~~~~~~~ + +error[E0034]: multiple applicable items in scope + --> $DIR/disambiguate-multiple-trait-2.rs:20:16 + | +LL | let _ = T::CONST; + | ^^^^^ multiple `CONST` found + | +note: candidate #1 is defined in the trait `A` + --> $DIR/disambiguate-multiple-trait-2.rs:3:5 + | +LL | const CONST: usize = 1; + | ^^^^^^^^^^^^^^^^^^ +note: candidate #2 is defined in the trait `B` + --> $DIR/disambiguate-multiple-trait-2.rs:9:5 + | +LL | const CONST: usize; + | ^^^^^^^^^^^^^^^^^^ +help: use fully-qualified syntax to disambiguate + | +LL | let _ = A::CONST; + | ~~~ +LL | let _ = B::CONST; + | ~~~ + +error[E0223]: ambiguous associated type + --> $DIR/disambiguate-multiple-trait-2.rs:52:12 + | +LL | let _: S::Type; + | ^^^^^^^ + | +help: use fully-qualified syntax + | +LL | let _: <S as A>::Type; + | ~~~~~~~~~~~~~~ +LL | let _: <S as B>::Type; + | ~~~~~~~~~~~~~~ + +error[E0034]: multiple applicable items in scope + --> $DIR/disambiguate-multiple-trait-2.rs:46:8 + | +LL | S::foo(&s); + | ^^^ multiple `foo` found + | +note: candidate #1 is defined in an impl of the trait `A` for the type `T` + --> $DIR/disambiguate-multiple-trait-2.rs:35:5 + | +LL | fn foo(&self) {} + | ^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `B` for the type `T` + --> $DIR/disambiguate-multiple-trait-2.rs:41:5 + | +LL | fn foo(&self) {} + | ^^^^^^^^^^^^^ +help: use fully-qualified syntax to disambiguate + | +LL | <T as A>::foo(&s); + | ~~~~~~~~~~ +LL | <T as B>::foo(&s); + | ~~~~~~~~~~ + +error[E0034]: multiple applicable items in scope + --> $DIR/disambiguate-multiple-trait-2.rs:49:16 + | +LL | let _ = S::CONST; + | ^^^^^ multiple `CONST` found + | +note: candidate #1 is defined in an impl of the trait `A` for the type `T` + --> $DIR/disambiguate-multiple-trait-2.rs:34:5 + | +LL | const CONST: usize = 1; + | ^^^^^^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `B` for the type `T` + --> $DIR/disambiguate-multiple-trait-2.rs:40:5 + | +LL | const CONST: usize = 1; + | ^^^^^^^^^^^^^^^^^^ +help: use fully-qualified syntax to disambiguate + | +LL | let _ = <T as A>::CONST; + | ~~~~~~~~~~ +LL | let _ = <T as B>::CONST; + | ~~~~~~~~~~ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0034, E0221, E0223. +For more information about an error, try `rustc --explain E0034`. diff --git a/tests/ui/methods/disambiguate-multiple-trait.rs b/tests/ui/methods/disambiguate-multiple-trait.rs new file mode 100644 index 00000000000..c990d047576 --- /dev/null +++ b/tests/ui/methods/disambiguate-multiple-trait.rs @@ -0,0 +1,32 @@ +#![feature(associated_type_defaults)] + +trait A { + type Type = (); + const CONST: usize = 1; //~ NOTE candidate #1 + fn foo(&self) {} //~ NOTE candidate #1 +} + +trait B { + type Type = (); + const CONST: usize = 2; //~ NOTE candidate #2 + fn foo(&self) {} //~ NOTE candidate #2 +} + +#[derive(Debug)] +struct S; + +impl<T: std::fmt::Debug> A for T {} + +impl<T: std::fmt::Debug> B for T {} + +fn main() { + let s = S; + S::foo(&s); //~ ERROR multiple applicable items in scope + //~^ NOTE multiple `foo` found + //~| HELP use fully-qualified syntax + let _ = S::CONST; //~ ERROR multiple applicable items in scope + //~^ NOTE multiple `CONST` found + //~| HELP use fully-qualified syntax + let _: S::Type; //~ ERROR ambiguous associated type + //~^ HELP use fully-qualified syntax +} diff --git a/tests/ui/methods/disambiguate-multiple-trait.stderr b/tests/ui/methods/disambiguate-multiple-trait.stderr new file mode 100644 index 00000000000..9a50d51245b --- /dev/null +++ b/tests/ui/methods/disambiguate-multiple-trait.stderr @@ -0,0 +1,63 @@ +error[E0223]: ambiguous associated type + --> $DIR/disambiguate-multiple-trait.rs:30:12 + | +LL | let _: S::Type; + | ^^^^^^^ + | +help: use fully-qualified syntax + | +LL | let _: <S as A>::Type; + | ~~~~~~~~~~~~~~ +LL | let _: <S as B>::Type; + | ~~~~~~~~~~~~~~ + +error[E0034]: multiple applicable items in scope + --> $DIR/disambiguate-multiple-trait.rs:24:8 + | +LL | S::foo(&s); + | ^^^ multiple `foo` found + | +note: candidate #1 is defined in an impl of the trait `A` for the type `T` + --> $DIR/disambiguate-multiple-trait.rs:6:5 + | +LL | fn foo(&self) {} + | ^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `B` for the type `T` + --> $DIR/disambiguate-multiple-trait.rs:12:5 + | +LL | fn foo(&self) {} + | ^^^^^^^^^^^^^ +help: use fully-qualified syntax to disambiguate + | +LL | <T as A>::foo(&s); + | ~~~~~~~~~~ +LL | <T as B>::foo(&s); + | ~~~~~~~~~~ + +error[E0034]: multiple applicable items in scope + --> $DIR/disambiguate-multiple-trait.rs:27:16 + | +LL | let _ = S::CONST; + | ^^^^^ multiple `CONST` found + | +note: candidate #1 is defined in an impl of the trait `A` for the type `T` + --> $DIR/disambiguate-multiple-trait.rs:5:5 + | +LL | const CONST: usize = 1; + | ^^^^^^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `B` for the type `T` + --> $DIR/disambiguate-multiple-trait.rs:11:5 + | +LL | const CONST: usize = 2; + | ^^^^^^^^^^^^^^^^^^ +help: use fully-qualified syntax to disambiguate + | +LL | let _ = <T as A>::CONST; + | ~~~~~~~~~~ +LL | let _ = <T as B>::CONST; + | ~~~~~~~~~~ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0034, E0223. +For more information about an error, try `rustc --explain E0034`. diff --git a/tests/ui/methods/method-ambig-two-traits-from-impls2.stderr b/tests/ui/methods/method-ambig-two-traits-from-impls2.stderr index 4ba778e0ef7..5bb887b4503 100644 --- a/tests/ui/methods/method-ambig-two-traits-from-impls2.stderr +++ b/tests/ui/methods/method-ambig-two-traits-from-impls2.stderr @@ -14,12 +14,10 @@ note: candidate #2 is defined in an impl of the trait `B` for the type `AB` | LL | fn foo() {} | ^^^^^^^^ -help: disambiguate the associated function for candidate #1 +help: use fully-qualified syntax to disambiguate | LL | <AB as A>::foo(); | ~~~~~~~~~~~ -help: disambiguate the associated function for candidate #2 - | LL | <AB as B>::foo(); | ~~~~~~~~~~~ diff --git a/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr b/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr index c16a90368e1..e09194d5d39 100644 --- a/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -2,9 +2,15 @@ error: expected identifier, found `:` --> $DIR/or-patterns-syntactic-fail.rs:11:19 | LL | let _ = |A | B: E| (); - | ^ expected identifier + | ---- ^ expected identifier + | | + | while parsing the body of this closure | = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728> +help: you might have meant to open the body of the closure + | +LL | let _ = |A | { B: E| (); + | + error: top-level or-patterns are not allowed in function parameters --> $DIR/or-patterns-syntactic-fail.rs:18:13 diff --git a/tests/ui/parser/attr-bad-meta-2.rs b/tests/ui/parser/attribute/attr-bad-meta-2.rs index db612ed883d..db612ed883d 100644 --- a/tests/ui/parser/attr-bad-meta-2.rs +++ b/tests/ui/parser/attribute/attr-bad-meta-2.rs diff --git a/tests/ui/parser/attr-bad-meta-2.stderr b/tests/ui/parser/attribute/attr-bad-meta-2.stderr index 6fc6fb665a8..6fc6fb665a8 100644 --- a/tests/ui/parser/attr-bad-meta-2.stderr +++ b/tests/ui/parser/attribute/attr-bad-meta-2.stderr diff --git a/tests/ui/parser/attr-bad-meta-3.rs b/tests/ui/parser/attribute/attr-bad-meta-3.rs index b51e9f2212d..b51e9f2212d 100644 --- a/tests/ui/parser/attr-bad-meta-3.rs +++ b/tests/ui/parser/attribute/attr-bad-meta-3.rs diff --git a/tests/ui/parser/attr-bad-meta-3.stderr b/tests/ui/parser/attribute/attr-bad-meta-3.stderr index 4fa420c79fc..4fa420c79fc 100644 --- a/tests/ui/parser/attr-bad-meta-3.stderr +++ b/tests/ui/parser/attribute/attr-bad-meta-3.stderr diff --git a/tests/ui/parser/attr-bad-meta.rs b/tests/ui/parser/attribute/attr-bad-meta.rs index 8001977f5a3..8001977f5a3 100644 --- a/tests/ui/parser/attr-bad-meta.rs +++ b/tests/ui/parser/attribute/attr-bad-meta.rs diff --git a/tests/ui/parser/attr-bad-meta.stderr b/tests/ui/parser/attribute/attr-bad-meta.stderr index 8d65c423c8d..8d65c423c8d 100644 --- a/tests/ui/parser/attr-bad-meta.stderr +++ b/tests/ui/parser/attribute/attr-bad-meta.stderr diff --git a/tests/ui/parser/attr-before-eof.rs b/tests/ui/parser/attribute/attr-before-eof.rs index 6af1783e630..6af1783e630 100644 --- a/tests/ui/parser/attr-before-eof.rs +++ b/tests/ui/parser/attribute/attr-before-eof.rs diff --git a/tests/ui/parser/attr-before-eof.stderr b/tests/ui/parser/attribute/attr-before-eof.stderr index a2acb94372b..a2acb94372b 100644 --- a/tests/ui/parser/attr-before-eof.stderr +++ b/tests/ui/parser/attribute/attr-before-eof.stderr diff --git a/tests/ui/parser/attr-dangling-in-fn.rs b/tests/ui/parser/attribute/attr-dangling-in-fn.rs index c7c45bafb0d..c7c45bafb0d 100644 --- a/tests/ui/parser/attr-dangling-in-fn.rs +++ b/tests/ui/parser/attribute/attr-dangling-in-fn.rs diff --git a/tests/ui/parser/attr-dangling-in-fn.stderr b/tests/ui/parser/attribute/attr-dangling-in-fn.stderr index b1bb3ab3b17..b1bb3ab3b17 100644 --- a/tests/ui/parser/attr-dangling-in-fn.stderr +++ b/tests/ui/parser/attribute/attr-dangling-in-fn.stderr diff --git a/tests/ui/parser/attr-dangling-in-mod.rs b/tests/ui/parser/attribute/attr-dangling-in-mod.rs index 261ed3913af..261ed3913af 100644 --- a/tests/ui/parser/attr-dangling-in-mod.rs +++ b/tests/ui/parser/attribute/attr-dangling-in-mod.rs diff --git a/tests/ui/parser/attr-dangling-in-mod.stderr b/tests/ui/parser/attribute/attr-dangling-in-mod.stderr index 1c892eac08f..1c892eac08f 100644 --- a/tests/ui/parser/attr-dangling-in-mod.stderr +++ b/tests/ui/parser/attribute/attr-dangling-in-mod.stderr diff --git a/tests/ui/parser/attr-stmt-expr-attr-bad.rs b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs index d1950087c4c..d1950087c4c 100644 --- a/tests/ui/parser/attr-stmt-expr-attr-bad.rs +++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs diff --git a/tests/ui/parser/attr-stmt-expr-attr-bad.stderr b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr index e46c591080d..e46c591080d 100644 --- a/tests/ui/parser/attr-stmt-expr-attr-bad.stderr +++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr diff --git a/tests/ui/parser/attr-with-a-semicolon.rs b/tests/ui/parser/attribute/attr-with-a-semicolon.rs index 56fe40b916b..56fe40b916b 100644 --- a/tests/ui/parser/attr-with-a-semicolon.rs +++ b/tests/ui/parser/attribute/attr-with-a-semicolon.rs diff --git a/tests/ui/parser/attr-with-a-semicolon.stderr b/tests/ui/parser/attribute/attr-with-a-semicolon.stderr index 0de3490b8ea..0de3490b8ea 100644 --- a/tests/ui/parser/attr-with-a-semicolon.stderr +++ b/tests/ui/parser/attribute/attr-with-a-semicolon.stderr diff --git a/tests/ui/parser/attr.rs b/tests/ui/parser/attribute/attr.rs index 42b2dfde855..42b2dfde855 100644 --- a/tests/ui/parser/attr.rs +++ b/tests/ui/parser/attribute/attr.rs diff --git a/tests/ui/parser/attr.stderr b/tests/ui/parser/attribute/attr.stderr index 7cd0ac2244a..7cd0ac2244a 100644 --- a/tests/ui/parser/attr.stderr +++ b/tests/ui/parser/attribute/attr.stderr diff --git a/tests/ui/parser/attribute-with-no-generics-in-parameter-list.rs b/tests/ui/parser/attribute/attribute-with-no-generics-in-parameter-list.rs index c2cc91d8f77..c2cc91d8f77 100644 --- a/tests/ui/parser/attribute-with-no-generics-in-parameter-list.rs +++ b/tests/ui/parser/attribute/attribute-with-no-generics-in-parameter-list.rs diff --git a/tests/ui/parser/attribute-with-no-generics-in-parameter-list.stderr b/tests/ui/parser/attribute/attribute-with-no-generics-in-parameter-list.stderr index 4c5964715db..4c5964715db 100644 --- a/tests/ui/parser/attribute-with-no-generics-in-parameter-list.stderr +++ b/tests/ui/parser/attribute/attribute-with-no-generics-in-parameter-list.stderr diff --git a/tests/ui/parser/attrs-after-extern-mod.rs b/tests/ui/parser/attribute/attrs-after-extern-mod.rs index e3f0fa0fc46..e3f0fa0fc46 100644 --- a/tests/ui/parser/attrs-after-extern-mod.rs +++ b/tests/ui/parser/attribute/attrs-after-extern-mod.rs diff --git a/tests/ui/parser/attrs-after-extern-mod.stderr b/tests/ui/parser/attribute/attrs-after-extern-mod.stderr index 135d98457e1..135d98457e1 100644 --- a/tests/ui/parser/attrs-after-extern-mod.stderr +++ b/tests/ui/parser/attribute/attrs-after-extern-mod.stderr diff --git a/tests/ui/parser/break-in-unlabeled-block-in-macro.rs b/tests/ui/parser/break-in-unlabeled-block-in-macro.rs new file mode 100644 index 00000000000..eecc0026b12 --- /dev/null +++ b/tests/ui/parser/break-in-unlabeled-block-in-macro.rs @@ -0,0 +1,43 @@ +macro_rules! foo { + () => { + break (); //~ ERROR `break` outside of a loop or labeled block + }; + ($e: expr) => { + break $e; //~ ERROR `break` outside of a loop or labeled block + }; + (stmt $s: stmt) => { + $s + }; + (@ $e: expr) => { + { break $e; } //~ ERROR `break` outside of a loop or labeled block + }; + (=> $s: stmt) => { + { $s } + }; +} + +fn main() { + { + foo!(); + } + { + foo!(()); + } + { + foo!(stmt break ()); //~ ERROR `break` outside of a loop or labeled block + } + { + foo!(@ ()); + } + { + foo!(=> break ()); //~ ERROR `break` outside of a loop or labeled block + } + { + macro_rules! bar { + () => { + break () //~ ERROR `break` outside of a loop or labeled block + }; + } + bar!() + } +} diff --git a/tests/ui/parser/break-in-unlabeled-block-in-macro.stderr b/tests/ui/parser/break-in-unlabeled-block-in-macro.stderr new file mode 100644 index 00000000000..9407e8ac002 --- /dev/null +++ b/tests/ui/parser/break-in-unlabeled-block-in-macro.stderr @@ -0,0 +1,69 @@ +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-in-unlabeled-block-in-macro.rs:3:9 + | +LL | break (); + | ^^^^^^^^ cannot `break` outside of a loop or labeled block +... +LL | foo!(); + | ------ in this macro invocation + | + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-in-unlabeled-block-in-macro.rs:6:9 + | +LL | break $e; + | ^^^^^^^^ cannot `break` outside of a loop or labeled block +... +LL | foo!(()); + | -------- in this macro invocation + | + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-in-unlabeled-block-in-macro.rs:27:19 + | +LL | foo!(stmt break ()); + | ^^^^^^^^ cannot `break` outside of a loop or labeled block + | +help: consider labeling this block to be able to break within it + | +LL ~ 'block: { +LL ~ foo!(stmt break 'block ()); + | + +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-in-unlabeled-block-in-macro.rs:12:11 + | +LL | { break $e; } + | ^^^^^^^^ cannot `break` outside of a loop or labeled block +... +LL | foo!(@ ()); + | ---------- in this macro invocation + | + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider labeling this block to be able to break within it + | +LL | 'block: { break 'block $e; } + | +++++++ ++++++ + +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-in-unlabeled-block-in-macro.rs:33:17 + | +LL | foo!(=> break ()); + | ^^^^^^^^ cannot `break` outside of a loop or labeled block + +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-in-unlabeled-block-in-macro.rs:38:17 + | +LL | break () + | ^^^^^^^^ cannot `break` outside of a loop or labeled block +... +LL | bar!() + | ------ in this macro invocation + | + = note: this error originates in the macro `bar` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0268`. diff --git a/tests/ui/parser/break-in-unlabeled-block.fixed b/tests/ui/parser/break-in-unlabeled-block.fixed new file mode 100644 index 00000000000..08856232521 --- /dev/null +++ b/tests/ui/parser/break-in-unlabeled-block.fixed @@ -0,0 +1,11 @@ +// run-rustfix +fn main() { + 'block: { + break 'block (); //~ ERROR `break` outside of a loop or labeled block + } + { + 'block: { + break 'block (); //~ ERROR `break` outside of a loop or labeled block + } + } +} diff --git a/tests/ui/parser/break-in-unlabeled-block.rs b/tests/ui/parser/break-in-unlabeled-block.rs new file mode 100644 index 00000000000..3e5587e9f9c --- /dev/null +++ b/tests/ui/parser/break-in-unlabeled-block.rs @@ -0,0 +1,11 @@ +// run-rustfix +fn main() { + { + break (); //~ ERROR `break` outside of a loop or labeled block + } + { + { + break (); //~ ERROR `break` outside of a loop or labeled block + } + } +} diff --git a/tests/ui/parser/break-in-unlabeled-block.stderr b/tests/ui/parser/break-in-unlabeled-block.stderr new file mode 100644 index 00000000000..632cca80d8c --- /dev/null +++ b/tests/ui/parser/break-in-unlabeled-block.stderr @@ -0,0 +1,27 @@ +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-in-unlabeled-block.rs:4:9 + | +LL | break (); + | ^^^^^^^^ cannot `break` outside of a loop or labeled block + | +help: consider labeling this block to be able to break within it + | +LL ~ 'block: { +LL ~ break 'block (); + | + +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-in-unlabeled-block.rs:8:13 + | +LL | break (); + | ^^^^^^^^ cannot `break` outside of a loop or labeled block + | +help: consider labeling this block to be able to break within it + | +LL ~ 'block: { +LL ~ break 'block (); + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0268`. diff --git a/tests/ui/parser/fn-header-semantic-fail.rs b/tests/ui/parser/fn-header-semantic-fail.rs index 71f18a27e7c..f8b58cad7c1 100644 --- a/tests/ui/parser/fn-header-semantic-fail.rs +++ b/tests/ui/parser/fn-header-semantic-fail.rs @@ -13,25 +13,23 @@ fn main() { //~^ ERROR functions cannot be both `const` and `async` trait X { - async fn ft1(); //~ ERROR functions in traits cannot be declared `async` + async fn ft1(); // OK. unsafe fn ft2(); // OK. const fn ft3(); //~ ERROR functions in traits cannot be declared const extern "C" fn ft4(); // OK. const async unsafe extern "C" fn ft5(); - //~^ ERROR functions in traits cannot be declared `async` - //~| ERROR functions in traits cannot be declared const + //~^ ERROR functions in traits cannot be declared const //~| ERROR functions cannot be both `const` and `async` } struct Y; impl X for Y { - async fn ft1() {} //~ ERROR functions in traits cannot be declared `async` + async fn ft1() {} // OK. unsafe fn ft2() {} // OK. const fn ft3() {} //~ ERROR functions in traits cannot be declared const extern "C" fn ft4() {} const async unsafe extern "C" fn ft5() {} - //~^ ERROR functions in traits cannot be declared `async` - //~| ERROR functions in traits cannot be declared const + //~^ ERROR functions in traits cannot be declared const //~| ERROR functions cannot be both `const` and `async` } diff --git a/tests/ui/parser/fn-header-semantic-fail.stderr b/tests/ui/parser/fn-header-semantic-fail.stderr index 7f7b7e835f8..cdf01e0c5df 100644 --- a/tests/ui/parser/fn-header-semantic-fail.stderr +++ b/tests/ui/parser/fn-header-semantic-fail.stderr @@ -29,19 +29,19 @@ LL | const async unsafe extern "C" fn ft5(); | `const` because of this error[E0379]: functions in traits cannot be declared const - --> $DIR/fn-header-semantic-fail.rs:30:9 + --> $DIR/fn-header-semantic-fail.rs:29:9 | LL | const fn ft3() {} | ^^^^^ functions in traits cannot be const error[E0379]: functions in traits cannot be declared const - --> $DIR/fn-header-semantic-fail.rs:32:9 + --> $DIR/fn-header-semantic-fail.rs:31:9 | LL | const async unsafe extern "C" fn ft5() {} | ^^^^^ functions in traits cannot be const error: functions cannot be both `const` and `async` - --> $DIR/fn-header-semantic-fail.rs:32:9 + --> $DIR/fn-header-semantic-fail.rs:31:9 | LL | const async unsafe extern "C" fn ft5() {} | ^^^^^-^^^^^------------------------------ @@ -50,7 +50,7 @@ LL | const async unsafe extern "C" fn ft5() {} | `const` because of this error: functions cannot be both `const` and `async` - --> $DIR/fn-header-semantic-fail.rs:43:9 + --> $DIR/fn-header-semantic-fail.rs:41:9 | LL | const async unsafe extern "C" fn fi5() {} | ^^^^^-^^^^^------------------------------ @@ -59,7 +59,7 @@ LL | const async unsafe extern "C" fn fi5() {} | `const` because of this error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:48:18 + --> $DIR/fn-header-semantic-fail.rs:46:18 | LL | extern "C" { | ---------- in this `extern` block @@ -72,7 +72,7 @@ LL | fn fe1(); | ~~ error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:49:19 + --> $DIR/fn-header-semantic-fail.rs:47:19 | LL | extern "C" { | ---------- in this `extern` block @@ -86,7 +86,7 @@ LL | fn fe2(); | ~~ error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:50:18 + --> $DIR/fn-header-semantic-fail.rs:48:18 | LL | extern "C" { | ---------- in this `extern` block @@ -100,7 +100,7 @@ LL | fn fe3(); | ~~ error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:51:23 + --> $DIR/fn-header-semantic-fail.rs:49:23 | LL | extern "C" { | ---------- in this `extern` block @@ -114,7 +114,7 @@ LL | fn fe4(); | ~~ error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:52:42 + --> $DIR/fn-header-semantic-fail.rs:50:42 | LL | extern "C" { | ---------- in this `extern` block @@ -128,7 +128,7 @@ LL | fn fe5(); | ~~ error: functions cannot be both `const` and `async` - --> $DIR/fn-header-semantic-fail.rs:52:9 + --> $DIR/fn-header-semantic-fail.rs:50:9 | LL | const async unsafe extern "C" fn fe5(); | ^^^^^-^^^^^---------------------------- @@ -136,59 +136,6 @@ LL | const async unsafe extern "C" fn fe5(); | | `async` because of this | `const` because of this -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/fn-header-semantic-fail.rs:16:9 - | -LL | async fn ft1(); - | -----^^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/fn-header-semantic-fail.rs:20:9 - | -LL | const async unsafe extern "C" fn ft5(); - | ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/fn-header-semantic-fail.rs:28:9 - | -LL | async fn ft1() {} - | -----^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/fn-header-semantic-fail.rs:32:9 - | -LL | const async unsafe extern "C" fn ft5() {} - | ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error: aborting due to 18 previous errors +error: aborting due to 14 previous errors -Some errors have detailed explanations: E0379, E0706. -For more information about an error, try `rustc --explain E0379`. +For more information about this error, try `rustc --explain E0379`. diff --git a/tests/ui/parser/issues/issue-32505.rs b/tests/ui/parser/issues/issue-32505.rs index f31c00e5cc3..d95e7dc7d9e 100644 --- a/tests/ui/parser/issues/issue-32505.rs +++ b/tests/ui/parser/issues/issue-32505.rs @@ -1,5 +1,6 @@ pub fn test() { foo(|_|) //~ ERROR expected expression, found `)` + //~^ ERROR cannot find function `foo` in this scope } fn main() { } diff --git a/tests/ui/parser/issues/issue-32505.stderr b/tests/ui/parser/issues/issue-32505.stderr index cdd779a93ef..27ad2c3e5be 100644 --- a/tests/ui/parser/issues/issue-32505.stderr +++ b/tests/ui/parser/issues/issue-32505.stderr @@ -2,7 +2,21 @@ error: expected expression, found `)` --> $DIR/issue-32505.rs:2:12 | LL | foo(|_|) - | ^ expected expression + | ---^ expected expression + | | + | while parsing the body of this closure + | +help: you might have meant to open the body of the closure + | +LL | foo(|_| {}) + | ++ + +error[E0425]: cannot find function `foo` in this scope + --> $DIR/issue-32505.rs:2:5 + | +LL | foo(|_|) + | ^^^ not found in this scope -error: aborting due to previous error +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/pattern/issue-115599.rs b/tests/ui/pattern/issue-115599.rs new file mode 100644 index 00000000000..7a222b90aec --- /dev/null +++ b/tests/ui/pattern/issue-115599.rs @@ -0,0 +1,7 @@ +const CONST_STRING: String = String::new(); + +fn main() { + let empty_str = String::from(""); + if let CONST_STRING = empty_str {} + //~^ ERROR to use a constant of type `Vec<u8>` in a pattern, `Vec<u8>` must be annotated with `#[derive(PartialEq, Eq)]` +} diff --git a/tests/ui/pattern/issue-115599.stderr b/tests/ui/pattern/issue-115599.stderr new file mode 100644 index 00000000000..e6cb6c1ddac --- /dev/null +++ b/tests/ui/pattern/issue-115599.stderr @@ -0,0 +1,11 @@ +error: to use a constant of type `Vec<u8>` in a pattern, `Vec<u8>` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/issue-115599.rs:5:12 + | +LL | if let CONST_STRING = empty_str {} + | ^^^^^^^^^^^^ + | + = note: the traits must be derived, manual `impl`s are not sufficient + = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details + +error: aborting due to previous error + diff --git a/tests/ui/pattern/non-structural-match-types.rs b/tests/ui/pattern/non-structural-match-types.rs index 5c331547366..fc52ee3d013 100644 --- a/tests/ui/pattern/non-structural-match-types.rs +++ b/tests/ui/pattern/non-structural-match-types.rs @@ -6,9 +6,9 @@ fn main() { match loop {} { - const { || {} } => {}, //~ ERROR cannot be used in patterns + const { || {} } => {} //~ ERROR cannot be used in patterns } match loop {} { - const { async {} } => {}, //~ ERROR cannot be used in patterns + const { async {} } => {} //~ ERROR cannot be used in patterns } } diff --git a/tests/ui/pattern/non-structural-match-types.stderr b/tests/ui/pattern/non-structural-match-types.stderr index 43d92775e88..f3e0665fef5 100644 --- a/tests/ui/pattern/non-structural-match-types.stderr +++ b/tests/ui/pattern/non-structural-match-types.stderr @@ -1,13 +1,13 @@ error: `{closure@$DIR/non-structural-match-types.rs:9:17: 9:19}` cannot be used in patterns --> $DIR/non-structural-match-types.rs:9:9 | -LL | const { || {} } => {}, +LL | const { || {} } => {} | ^^^^^^^^^^^^^^^ error: `{async block@$DIR/non-structural-match-types.rs:12:17: 12:25}` cannot be used in patterns --> $DIR/non-structural-match-types.rs:12:9 | -LL | const { async {} } => {}, +LL | const { async {} } => {} | ^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/pattern/usefulness/consts-opaque.rs b/tests/ui/pattern/usefulness/consts-opaque.rs index c10c6205a08..6dc1425cf03 100644 --- a/tests/ui/pattern/usefulness/consts-opaque.rs +++ b/tests/ui/pattern/usefulness/consts-opaque.rs @@ -30,15 +30,13 @@ fn main() { match FOO { FOO => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - _ => {} // should not be emitting unreachable warning - //~^ ERROR unreachable pattern + _ => {} } match FOO_REF { FOO_REF => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - Foo(_) => {} // should not be emitting unreachable warning - //~^ ERROR unreachable pattern + Foo(_) => {} } // This used to cause an ICE (https://github.com/rust-lang/rust/issues/78071) @@ -51,39 +49,31 @@ fn main() { match BAR { Bar => {} - BAR => {} // should not be emitting unreachable warning + BAR => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR unreachable pattern _ => {} - //~^ ERROR unreachable pattern } match BAR { BAR => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - Bar => {} // should not be emitting unreachable warning - //~^ ERROR unreachable pattern + Bar => {} _ => {} - //~^ ERROR unreachable pattern } match BAR { BAR => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - BAR => {} // should not be emitting unreachable warning + BAR => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR unreachable pattern - _ => {} // should not be emitting unreachable warning - //~^ ERROR unreachable pattern + _ => {} } match BAZ { BAZ => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - Baz::Baz1 => {} // should not be emitting unreachable warning - //~^ ERROR unreachable pattern + Baz::Baz1 => {} _ => {} - //~^ ERROR unreachable pattern } match BAZ { @@ -91,16 +81,13 @@ fn main() { BAZ => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => {} - //~^ ERROR unreachable pattern } match BAZ { BAZ => {} //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - Baz::Baz2 => {} // should not be emitting unreachable warning - //~^ ERROR unreachable pattern - _ => {} // should not be emitting unreachable warning - //~^ ERROR unreachable pattern + Baz::Baz2 => {} + _ => {} } type Quux = fn(usize, usize) -> usize; diff --git a/tests/ui/pattern/usefulness/consts-opaque.stderr b/tests/ui/pattern/usefulness/consts-opaque.stderr index e01b06ccc82..51f2f276bbe 100644 --- a/tests/ui/pattern/usefulness/consts-opaque.stderr +++ b/tests/ui/pattern/usefulness/consts-opaque.stderr @@ -8,7 +8,7 @@ LL | FOO => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:38:9 + --> $DIR/consts-opaque.rs:37:9 | LL | FOO_REF => {} | ^^^^^^^ @@ -17,7 +17,7 @@ LL | FOO_REF => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details warning: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:46:9 + --> $DIR/consts-opaque.rs:44:9 | LL | FOO_REF_REF => {} | ^^^^^^^^^^^ @@ -29,16 +29,16 @@ LL | FOO_REF_REF => {} = note: `#[warn(indirect_structural_match)]` on by default error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:54:9 + --> $DIR/consts-opaque.rs:52:9 | -LL | BAR => {} // should not be emitting unreachable warning +LL | BAR => {} | ^^^ | = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:62:9 + --> $DIR/consts-opaque.rs:58:9 | LL | BAR => {} | ^^^ @@ -47,7 +47,7 @@ LL | BAR => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:71:9 + --> $DIR/consts-opaque.rs:65:9 | LL | BAR => {} | ^^^ @@ -56,16 +56,16 @@ LL | BAR => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:73:9 + --> $DIR/consts-opaque.rs:67:9 | -LL | BAR => {} // should not be emitting unreachable warning +LL | BAR => {} | ^^^ | = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:81:9 + --> $DIR/consts-opaque.rs:73:9 | LL | BAZ => {} | ^^^ @@ -74,7 +74,7 @@ LL | BAZ => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:91:9 + --> $DIR/consts-opaque.rs:81:9 | LL | BAZ => {} | ^^^ @@ -83,7 +83,7 @@ LL | BAZ => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:98:9 + --> $DIR/consts-opaque.rs:87:9 | LL | BAZ => {} | ^^^ @@ -91,136 +91,14 @@ LL | BAZ => {} = note: the traits must be derived, manual `impl`s are not sufficient = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details -error: unreachable pattern - --> $DIR/consts-opaque.rs:33:9 - | -LL | FOO => {} - | --- matches any value -LL | -LL | _ => {} // should not be emitting unreachable warning - | ^ unreachable pattern - | -note: the lint level is defined here - --> $DIR/consts-opaque.rs:6:9 - | -LL | #![deny(unreachable_patterns)] - | ^^^^^^^^^^^^^^^^^^^^ - -error: unreachable pattern - --> $DIR/consts-opaque.rs:40:9 - | -LL | FOO_REF => {} - | ------- matches any value -LL | -LL | Foo(_) => {} // should not be emitting unreachable warning - | ^^^^^^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:54:9 - | -LL | Bar => {} - | --- matches any value -LL | BAR => {} // should not be emitting unreachable warning - | ^^^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:57:9 - | -LL | Bar => {} - | --- matches any value -... -LL | _ => {} - | ^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:64:9 - | -LL | BAR => {} - | --- matches any value -LL | -LL | Bar => {} // should not be emitting unreachable warning - | ^^^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:66:9 - | -LL | BAR => {} - | --- matches any value -... -LL | _ => {} - | ^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:73:9 - | -LL | BAR => {} - | --- matches any value -LL | -LL | BAR => {} // should not be emitting unreachable warning - | ^^^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:76:9 - | -LL | BAR => {} - | --- matches any value -... -LL | _ => {} // should not be emitting unreachable warning - | ^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:83:9 - | -LL | BAZ => {} - | --- matches any value -LL | -LL | Baz::Baz1 => {} // should not be emitting unreachable warning - | ^^^^^^^^^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:85:9 - | -LL | BAZ => {} - | --- matches any value -... -LL | _ => {} - | ^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:93:9 - | -LL | BAZ => {} - | --- matches any value -LL | -LL | _ => {} - | ^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:100:9 - | -LL | BAZ => {} - | --- matches any value -LL | -LL | Baz::Baz2 => {} // should not be emitting unreachable warning - | ^^^^^^^^^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:102:9 - | -LL | BAZ => {} - | --- matches any value -... -LL | _ => {} // should not be emitting unreachable warning - | ^ unreachable pattern - error[E0004]: non-exhaustive patterns: `Wrap(_)` not covered - --> $DIR/consts-opaque.rs:135:11 + --> $DIR/consts-opaque.rs:122:11 | LL | match WRAPQUUX { | ^^^^^^^^ pattern `Wrap(_)` not covered | note: `Wrap<fn(usize, usize) -> usize>` defined here - --> $DIR/consts-opaque.rs:117:12 + --> $DIR/consts-opaque.rs:104:12 | LL | struct Wrap<T>(T); | ^^^^ @@ -231,6 +109,6 @@ LL ~ WRAPQUUX => {}, LL + Wrap(_) => todo!() | -error: aborting due to 23 previous errors; 1 warning emitted +error: aborting due to 10 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/pattern/usefulness/slice_of_empty.rs b/tests/ui/pattern/usefulness/slice_of_empty.rs new file mode 100644 index 00000000000..fe068871195 --- /dev/null +++ b/tests/ui/pattern/usefulness/slice_of_empty.rs @@ -0,0 +1,22 @@ +#![feature(never_type)] +#![feature(exhaustive_patterns)] +#![deny(unreachable_patterns)] + +fn main() {} + +fn foo(nevers: &[!]) { + match nevers { + &[] => (), + }; + + match nevers { + &[] => (), + &[_] => (), //~ ERROR unreachable pattern + &[_, _, ..] => (), //~ ERROR unreachable pattern + }; + + match nevers { + //~^ ERROR non-exhaustive patterns: `&[]` not covered + &[_] => (), //~ ERROR unreachable pattern + }; +} diff --git a/tests/ui/pattern/usefulness/slice_of_empty.stderr b/tests/ui/pattern/usefulness/slice_of_empty.stderr new file mode 100644 index 00000000000..07bb6b3a67d --- /dev/null +++ b/tests/ui/pattern/usefulness/slice_of_empty.stderr @@ -0,0 +1,39 @@ +error: unreachable pattern + --> $DIR/slice_of_empty.rs:14:9 + | +LL | &[_] => (), + | ^^^^ + | +note: the lint level is defined here + --> $DIR/slice_of_empty.rs:3:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice_of_empty.rs:15:9 + | +LL | &[_, _, ..] => (), + | ^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice_of_empty.rs:20:9 + | +LL | &[_] => (), + | ^^^^ + +error[E0004]: non-exhaustive patterns: `&[]` not covered + --> $DIR/slice_of_empty.rs:18:11 + | +LL | match nevers { + | ^^^^^^ pattern `&[]` not covered + | + = note: the matched value is of type `&[!]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL | &[_] => (), &[] => todo!(), + | ++++++++++++++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/proc-macro/issue-75930-derive-cfg.rs b/tests/ui/proc-macro/issue-75930-derive-cfg.rs index ef56e8e02d0..e0213527c50 100644 --- a/tests/ui/proc-macro/issue-75930-derive-cfg.rs +++ b/tests/ui/proc-macro/issue-75930-derive-cfg.rs @@ -16,6 +16,36 @@ extern crate std; #[macro_use] extern crate test_macros; +// Note: the expected output contains this sequence: +// ``` +// Punct { +// ch: '<', +// spacing: Joint, +// span: $DIR/issue-75930-derive-cfg.rs:25:11: 25:12 (#0), +// }, +// Ident { +// ident: "B", +// span: $DIR/issue-75930-derive-cfg.rs:25:29: 25:30 (#0), +// }, +// ``` +// It's surprising to see a `Joint` token tree followed by an `Ident` token +// tree, because `Joint` is supposed to only be used if the following token is +// `Punct`. +// +// It is because of this code from below: +// ``` +// struct Foo<#[cfg(FALSE)] A, B> +// ``` +// When the token stream is formed during parsing, `<` is followed immediately +// by `#`, which is punctuation, so it is marked `Joint`. But before being +// passed to the proc macro it is rewritten to this: +// ``` +// struct Foo<B> +// ``` +// But the `Joint` marker on the `<` is not updated. Perhaps it should be +// corrected before being passed to the proc macro? But a prior attempt to do +// that kind of correction caused the problem seen in #76399, so maybe not. + #[print_helper(a)] //~ WARN derive helper attribute is used before it is introduced //~| WARN this was previously accepted #[cfg_attr(not(FALSE), allow(dead_code))] diff --git a/tests/ui/proc-macro/issue-75930-derive-cfg.stderr b/tests/ui/proc-macro/issue-75930-derive-cfg.stderr index f3f470676e4..1017745de6f 100644 --- a/tests/ui/proc-macro/issue-75930-derive-cfg.stderr +++ b/tests/ui/proc-macro/issue-75930-derive-cfg.stderr @@ -1,5 +1,5 @@ warning: derive helper attribute is used before it is introduced - --> $DIR/issue-75930-derive-cfg.rs:19:3 + --> $DIR/issue-75930-derive-cfg.rs:49:3 | LL | #[print_helper(a)] | ^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | #[derive(Print)] = note: `#[warn(legacy_derive_helpers)]` on by default warning: derive helper attribute is used before it is introduced - --> $DIR/issue-75930-derive-cfg.rs:19:3 + --> $DIR/issue-75930-derive-cfg.rs:49:3 | LL | #[print_helper(a)] | ^^^^^^^^^^^^ diff --git a/tests/ui/proc-macro/issue-75930-derive-cfg.stdout b/tests/ui/proc-macro/issue-75930-derive-cfg.stdout index 83afd0d3eae..31a1c44b6df 100644 --- a/tests/ui/proc-macro/issue-75930-derive-cfg.stdout +++ b/tests/ui/proc-macro/issue-75930-derive-cfg.stdout @@ -26,158 +26,158 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:19:1: 19:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:49:1: 49:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_helper", - span: $DIR/issue-75930-derive-cfg.rs:19:3: 19:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:49:3: 49:15 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "a", - span: $DIR/issue-75930-derive-cfg.rs:19:16: 19:17 (#0), + span: $DIR/issue-75930-derive-cfg.rs:49:16: 49:17 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:19:15: 19:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:49:15: 49:18 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:19:2: 19:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:49:2: 49:19 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:21:1: 21:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:51:1: 51:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "allow", - span: $DIR/issue-75930-derive-cfg.rs:21:24: 21:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:51:24: 51:29 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "dead_code", - span: $DIR/issue-75930-derive-cfg.rs:21:30: 21:39 (#0), + span: $DIR/issue-75930-derive-cfg.rs:51:30: 51:39 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:21:29: 21:40 (#0), + span: $DIR/issue-75930-derive-cfg.rs:51:29: 51:40 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:21:1: 21:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:51:1: 51:2 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:23:1: 23:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:53:1: 53:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "derive", - span: $DIR/issue-75930-derive-cfg.rs:23:3: 23:9 (#0), + span: $DIR/issue-75930-derive-cfg.rs:53:3: 53:9 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "Print", - span: $DIR/issue-75930-derive-cfg.rs:23:10: 23:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:53:10: 53:15 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:23:9: 23:16 (#0), + span: $DIR/issue-75930-derive-cfg.rs:53:9: 53:16 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:23:2: 23:17 (#0), + span: $DIR/issue-75930-derive-cfg.rs:53:2: 53:17 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:24:1: 24:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:54:1: 54:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_helper", - span: $DIR/issue-75930-derive-cfg.rs:24:3: 24:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:54:3: 54:15 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "b", - span: $DIR/issue-75930-derive-cfg.rs:24:16: 24:17 (#0), + span: $DIR/issue-75930-derive-cfg.rs:54:16: 54:17 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:24:15: 24:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:54:15: 54:18 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:24:2: 24:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:54:2: 54:19 (#0), }, Ident { ident: "struct", - span: $DIR/issue-75930-derive-cfg.rs:25:1: 25:7 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:1: 55:7 (#0), }, Ident { ident: "Foo", - span: $DIR/issue-75930-derive-cfg.rs:25:8: 25:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:8: 55:11 (#0), }, Punct { ch: '<', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:25:11: 25:12 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:11: 55:12 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:25:12: 25:13 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:12: 55:13 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:25:14: 25:17 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:14: 55:17 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:25:18: 25:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:18: 55:23 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:25:17: 25:24 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:17: 55:24 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:25:13: 25:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:13: 55:25 (#0), }, Ident { ident: "A", - span: $DIR/issue-75930-derive-cfg.rs:25:26: 25:27 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:26: 55:27 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:25:27: 25:28 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:27: 55:28 (#0), }, Ident { ident: "B", - span: $DIR/issue-75930-derive-cfg.rs:25:29: 25:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:29: 55:30 (#0), }, Punct { ch: '>', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:25:30: 25:31 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:30: 55:31 (#0), }, Group { delimiter: Brace, @@ -185,128 +185,128 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:26:5: 26:6 (#0), + span: $DIR/issue-75930-derive-cfg.rs:56:5: 56:6 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:26:7: 26:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:56:7: 56:10 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:26:11: 26:16 (#0), + span: $DIR/issue-75930-derive-cfg.rs:56:11: 56:16 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:26:10: 26:17 (#0), + span: $DIR/issue-75930-derive-cfg.rs:56:10: 56:17 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:26:6: 26:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:56:6: 56:18 (#0), }, Ident { ident: "first", - span: $DIR/issue-75930-derive-cfg.rs:26:19: 26:24 (#0), + span: $DIR/issue-75930-derive-cfg.rs:56:19: 56:24 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:26:24: 26:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:56:24: 56:25 (#0), }, Ident { ident: "String", - span: $DIR/issue-75930-derive-cfg.rs:26:26: 26:32 (#0), + span: $DIR/issue-75930-derive-cfg.rs:56:26: 56:32 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:26:32: 26:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:56:32: 56:33 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:27:5: 27:6 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:5: 57:6 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg_attr", - span: $DIR/issue-75930-derive-cfg.rs:27:7: 27:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:7: 57:15 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:27:16: 27:21 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:16: 57:21 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:27:21: 27:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:21: 57:22 (#0), }, Ident { ident: "deny", - span: $DIR/issue-75930-derive-cfg.rs:27:23: 27:27 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:23: 57:27 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "warnings", - span: $DIR/issue-75930-derive-cfg.rs:27:28: 27:36 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:28: 57:36 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:27:27: 27:37 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:27: 57:37 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:27:15: 27:38 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:15: 57:38 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:27:6: 27:39 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:6: 57:39 (#0), }, Ident { ident: "second", - span: $DIR/issue-75930-derive-cfg.rs:27:40: 27:46 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:40: 57:46 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:27:46: 27:47 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:46: 57:47 (#0), }, Ident { ident: "bool", - span: $DIR/issue-75930-derive-cfg.rs:27:48: 27:52 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:48: 57:52 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:27:52: 27:53 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:52: 57:53 (#0), }, Ident { ident: "third", - span: $DIR/issue-75930-derive-cfg.rs:28:5: 28:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:5: 58:10 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:28:10: 28:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:10: 58:11 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "u8", - span: $DIR/issue-75930-derive-cfg.rs:28:13: 28:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:13: 58:15 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:28:15: 28:16 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:15: 58:16 (#0), }, Group { delimiter: Brace, @@ -314,145 +314,145 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:29:9: 29:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:59:9: 59:10 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:29:11: 29:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:59:11: 59:14 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:29:15: 29:20 (#0), + span: $DIR/issue-75930-derive-cfg.rs:59:15: 59:20 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:29:14: 29:21 (#0), + span: $DIR/issue-75930-derive-cfg.rs:59:14: 59:21 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:29:10: 29:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:59:10: 59:22 (#0), }, Ident { ident: "struct", - span: $DIR/issue-75930-derive-cfg.rs:29:23: 29:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:59:23: 59:29 (#0), }, Ident { ident: "Bar", - span: $DIR/issue-75930-derive-cfg.rs:29:30: 29:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:59:30: 59:33 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:29:33: 29:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:59:33: 59:34 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:30:9: 30:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:9: 60:10 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:30:11: 30:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:11: 60:14 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:30:15: 30:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:15: 60:18 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:30:19: 30:24 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:19: 60:24 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:30:18: 30:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:18: 60:25 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:30:14: 30:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:14: 60:26 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:30:10: 30:27 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:10: 60:27 (#0), }, Ident { ident: "struct", - span: $DIR/issue-75930-derive-cfg.rs:30:28: 30:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:28: 60:34 (#0), }, Ident { ident: "Inner", - span: $DIR/issue-75930-derive-cfg.rs:30:35: 30:40 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:35: 60:40 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:30:40: 30:41 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:40: 60:41 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:31:9: 31:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:61:9: 61:10 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:31:11: 31:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:61:11: 61:14 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:31:15: 31:20 (#0), + span: $DIR/issue-75930-derive-cfg.rs:61:15: 61:20 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:31:14: 31:21 (#0), + span: $DIR/issue-75930-derive-cfg.rs:61:14: 61:21 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:31:10: 31:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:61:10: 61:22 (#0), }, Ident { ident: "let", - span: $DIR/issue-75930-derive-cfg.rs:31:23: 31:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:61:23: 61:26 (#0), }, Ident { ident: "a", - span: $DIR/issue-75930-derive-cfg.rs:31:27: 31:28 (#0), + span: $DIR/issue-75930-derive-cfg.rs:61:27: 61:28 (#0), }, Punct { ch: '=', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:31:29: 31:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:61:29: 61:30 (#0), }, Literal { kind: Integer, symbol: "25", suffix: None, - span: $DIR/issue-75930-derive-cfg.rs:31:31: 31:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:61:31: 61:33 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:31:33: 31:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:61:33: 61:34 (#0), }, Ident { ident: "match", - span: $DIR/issue-75930-derive-cfg.rs:32:9: 32:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:62:9: 62:14 (#0), }, Ident { ident: "true", - span: $DIR/issue-75930-derive-cfg.rs:32:15: 32:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:62:15: 62:19 (#0), }, Group { delimiter: Brace, @@ -460,194 +460,194 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:33:13: 33:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:13: 63:14 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:33:15: 33:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:15: 63:18 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:33:19: 33:24 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:19: 63:24 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:33:18: 33:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:18: 63:25 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:33:14: 33:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:14: 63:26 (#0), }, Ident { ident: "true", - span: $DIR/issue-75930-derive-cfg.rs:33:27: 33:31 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:27: 63:31 (#0), }, Punct { ch: '=', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:33:32: 33:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:32: 63:33 (#0), }, Punct { ch: '>', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:33:33: 33:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:33: 63:34 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/issue-75930-derive-cfg.rs:33:35: 33:37 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:35: 63:37 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:33:37: 33:38 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:37: 63:38 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:34:13: 34:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:13: 64:14 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg_attr", - span: $DIR/issue-75930-derive-cfg.rs:34:15: 34:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:15: 64:23 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:34:24: 34:27 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:24: 64:27 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:34:28: 34:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:28: 64:33 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:34:27: 34:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:27: 64:34 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:34:34: 34:35 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:34: 64:35 (#0), }, Ident { ident: "allow", - span: $DIR/issue-75930-derive-cfg.rs:34:36: 34:41 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:36: 64:41 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "warnings", - span: $DIR/issue-75930-derive-cfg.rs:34:42: 34:50 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:42: 64:50 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:34:41: 34:51 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:41: 64:51 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:34:23: 34:52 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:23: 64:52 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:34:14: 34:53 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:14: 64:53 (#0), }, Ident { ident: "false", - span: $DIR/issue-75930-derive-cfg.rs:34:54: 34:59 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:54: 64:59 (#0), }, Punct { ch: '=', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:34:60: 34:61 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:60: 64:61 (#0), }, Punct { ch: '>', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:34:61: 34:62 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:61: 64:62 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/issue-75930-derive-cfg.rs:34:63: 34:65 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:63: 64:65 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:34:65: 34:66 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:65: 64:66 (#0), }, Ident { ident: "_", - span: $DIR/issue-75930-derive-cfg.rs:35:13: 35:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:65:13: 65:14 (#0), }, Punct { ch: '=', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:35:15: 35:16 (#0), + span: $DIR/issue-75930-derive-cfg.rs:65:15: 65:16 (#0), }, Punct { ch: '>', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:35:16: 35:17 (#0), + span: $DIR/issue-75930-derive-cfg.rs:65:16: 65:17 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/issue-75930-derive-cfg.rs:35:18: 35:20 (#0), + span: $DIR/issue-75930-derive-cfg.rs:65:18: 65:20 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:32:20: 36:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:62:20: 66:10 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:36:10: 36:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:66:10: 66:11 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:38:9: 38:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:68:9: 68:10 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_helper", - span: $DIR/issue-75930-derive-cfg.rs:38:11: 38:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:68:11: 68:23 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "should_be_removed", - span: $DIR/issue-75930-derive-cfg.rs:38:24: 38:41 (#0), + span: $DIR/issue-75930-derive-cfg.rs:68:24: 68:41 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:38:23: 38:42 (#0), + span: $DIR/issue-75930-derive-cfg.rs:68:23: 68:42 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:38:10: 38:43 (#0), + span: $DIR/issue-75930-derive-cfg.rs:68:10: 68:43 (#0), }, Ident { ident: "fn", - span: $DIR/issue-75930-derive-cfg.rs:39:9: 39:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:69:9: 69:11 (#0), }, Ident { ident: "removed_fn", - span: $DIR/issue-75930-derive-cfg.rs:39:12: 39:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:69:12: 69:22 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [], - span: $DIR/issue-75930-derive-cfg.rs:39:22: 39:24 (#0), + span: $DIR/issue-75930-derive-cfg.rs:69:22: 69:24 (#0), }, Group { delimiter: Brace, @@ -655,108 +655,108 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:40:13: 40:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:70:13: 70:14 (#0), }, Punct { ch: '!', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:40:14: 40:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:70:14: 70:15 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:40:16: 40:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:70:16: 70:19 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:40:20: 40:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:70:20: 70:25 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:40:19: 40:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:70:19: 70:26 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:40:15: 40:27 (#0), + span: $DIR/issue-75930-derive-cfg.rs:70:15: 70:27 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:39:25: 41:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:69:25: 71:10 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:43:9: 43:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:9: 73:10 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_helper", - span: $DIR/issue-75930-derive-cfg.rs:43:11: 43:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:11: 73:23 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "c", - span: $DIR/issue-75930-derive-cfg.rs:43:24: 43:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:24: 73:25 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:23: 43:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:23: 73:26 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:10: 43:27 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:10: 73:27 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:43:28: 43:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:28: 73:29 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:43:30: 43:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:30: 73:33 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:43:34: 43:37 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:34: 73:37 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:43:38: 43:43 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:38: 73:43 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:37: 43:44 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:37: 73:44 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:33: 43:45 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:33: 73:45 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:29: 43:46 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:29: 73:46 (#0), }, Ident { ident: "fn", - span: $DIR/issue-75930-derive-cfg.rs:43:47: 43:49 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:47: 73:49 (#0), }, Ident { ident: "kept_fn", - span: $DIR/issue-75930-derive-cfg.rs:43:50: 43:57 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:50: 73:57 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [], - span: $DIR/issue-75930-derive-cfg.rs:43:57: 43:59 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:57: 73:59 (#0), }, Group { delimiter: Brace, @@ -764,82 +764,82 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:44:13: 44:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:13: 74:14 (#0), }, Punct { ch: '!', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:44:14: 44:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:14: 74:15 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:44:16: 44:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:16: 74:19 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:44:20: 44:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:20: 74:23 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:44:24: 44:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:24: 74:29 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:44:23: 44:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:23: 74:30 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:44:19: 44:31 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:19: 74:31 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:44:15: 44:32 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:15: 74:32 (#0), }, Ident { ident: "let", - span: $DIR/issue-75930-derive-cfg.rs:45:13: 45:16 (#0), + span: $DIR/issue-75930-derive-cfg.rs:75:13: 75:16 (#0), }, Ident { ident: "my_val", - span: $DIR/issue-75930-derive-cfg.rs:45:17: 45:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:75:17: 75:23 (#0), }, Punct { ch: '=', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:45:24: 45:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:75:24: 75:25 (#0), }, Ident { ident: "true", - span: $DIR/issue-75930-derive-cfg.rs:45:26: 45:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:75:26: 75:30 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:45:30: 45:31 (#0), + span: $DIR/issue-75930-derive-cfg.rs:75:30: 75:31 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:60: 46:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:60: 76:10 (#0), }, Ident { ident: "enum", - span: $DIR/issue-75930-derive-cfg.rs:48:9: 48:13 (#0), + span: $DIR/issue-75930-derive-cfg.rs:78:9: 78:13 (#0), }, Ident { ident: "TupleEnum", - span: $DIR/issue-75930-derive-cfg.rs:48:14: 48:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:78:14: 78:23 (#0), }, Group { delimiter: Brace, stream: TokenStream [ Ident { ident: "Foo", - span: $DIR/issue-75930-derive-cfg.rs:49:13: 49:16 (#0), + span: $DIR/issue-75930-derive-cfg.rs:79:13: 79:16 (#0), }, Group { delimiter: Parenthesis, @@ -847,166 +847,166 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:50:17: 50:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:80:17: 80:18 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:50:19: 50:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:80:19: 80:22 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:50:23: 50:28 (#0), + span: $DIR/issue-75930-derive-cfg.rs:80:23: 80:28 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:50:22: 50:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:80:22: 80:29 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:50:18: 50:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:80:18: 80:30 (#0), }, Ident { ident: "u8", - span: $DIR/issue-75930-derive-cfg.rs:50:31: 50:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:80:31: 80:33 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:50:33: 50:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:80:33: 80:34 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:51:17: 51:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:81:17: 81:18 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:51:19: 51:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:81:19: 81:22 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:51:23: 51:28 (#0), + span: $DIR/issue-75930-derive-cfg.rs:81:23: 81:28 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:51:22: 51:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:81:22: 81:29 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:51:18: 51:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:81:18: 81:30 (#0), }, Ident { ident: "bool", - span: $DIR/issue-75930-derive-cfg.rs:51:31: 51:35 (#0), + span: $DIR/issue-75930-derive-cfg.rs:81:31: 81:35 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:51:35: 51:36 (#0), + span: $DIR/issue-75930-derive-cfg.rs:81:35: 81:36 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:52:17: 52:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:17: 82:18 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:52:19: 52:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:19: 82:22 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:52:23: 52:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:23: 82:26 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:52:27: 52:32 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:27: 82:32 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:52:26: 52:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:26: 82:33 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:52:22: 52:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:22: 82:34 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:52:18: 52:35 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:18: 82:35 (#0), }, Ident { ident: "i32", - span: $DIR/issue-75930-derive-cfg.rs:52:36: 52:39 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:36: 82:39 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:52:39: 52:40 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:39: 82:40 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:53:17: 53:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:83:17: 83:18 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:53:19: 53:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:83:19: 83:22 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:53:23: 53:28 (#0), + span: $DIR/issue-75930-derive-cfg.rs:83:23: 83:28 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:53:22: 53:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:83:22: 83:29 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:53:18: 53:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:83:18: 83:30 (#0), }, Ident { ident: "String", - span: $DIR/issue-75930-derive-cfg.rs:53:31: 53:37 (#0), + span: $DIR/issue-75930-derive-cfg.rs:83:31: 83:37 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:53:37: 53:38 (#0), + span: $DIR/issue-75930-derive-cfg.rs:83:37: 83:38 (#0), }, Ident { ident: "u8", - span: $DIR/issue-75930-derive-cfg.rs:53:39: 53:41 (#0), + span: $DIR/issue-75930-derive-cfg.rs:83:39: 83:41 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:49:16: 54:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:79:16: 84:14 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:48:24: 55:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:78:24: 85:10 (#0), }, Ident { ident: "struct", - span: $DIR/issue-75930-derive-cfg.rs:57:9: 57:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:87:9: 87:15 (#0), }, Ident { ident: "TupleStruct", - span: $DIR/issue-75930-derive-cfg.rs:57:16: 57:27 (#0), + span: $DIR/issue-75930-derive-cfg.rs:87:16: 87:27 (#0), }, Group { delimiter: Parenthesis, @@ -1014,139 +1014,139 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:58:13: 58:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:88:13: 88:14 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:58:15: 58:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:88:15: 88:18 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:58:19: 58:24 (#0), + span: $DIR/issue-75930-derive-cfg.rs:88:19: 88:24 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:58:18: 58:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:88:18: 88:25 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:58:14: 58:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:88:14: 88:26 (#0), }, Ident { ident: "String", - span: $DIR/issue-75930-derive-cfg.rs:58:27: 58:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:88:27: 88:33 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:58:33: 58:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:88:33: 88:34 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:59:13: 59:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:13: 89:14 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:59:15: 59:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:15: 89:18 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:59:19: 59:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:19: 89:22 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:59:23: 59:28 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:23: 89:28 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:59:22: 59:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:22: 89:29 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:59:18: 59:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:18: 89:30 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:59:14: 59:31 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:14: 89:31 (#0), }, Ident { ident: "i32", - span: $DIR/issue-75930-derive-cfg.rs:59:32: 59:35 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:32: 89:35 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:59:35: 59:36 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:35: 89:36 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:60:13: 60:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:90:13: 90:14 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:60:15: 60:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:90:15: 90:18 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:60:19: 60:24 (#0), + span: $DIR/issue-75930-derive-cfg.rs:90:19: 90:24 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:60:18: 60:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:90:18: 90:25 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:60:14: 60:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:90:14: 90:26 (#0), }, Ident { ident: "bool", - span: $DIR/issue-75930-derive-cfg.rs:60:27: 60:31 (#0), + span: $DIR/issue-75930-derive-cfg.rs:90:27: 90:31 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:60:31: 60:32 (#0), + span: $DIR/issue-75930-derive-cfg.rs:90:31: 90:32 (#0), }, Ident { ident: "u8", - span: $DIR/issue-75930-derive-cfg.rs:61:13: 61:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:91:13: 91:15 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:57:27: 62:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:87:27: 92:10 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:62:10: 62:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:92:10: 92:11 (#0), }, Ident { ident: "fn", - span: $DIR/issue-75930-derive-cfg.rs:64:9: 64:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:94:9: 94:11 (#0), }, Ident { ident: "plain_removed_fn", - span: $DIR/issue-75930-derive-cfg.rs:64:12: 64:28 (#0), + span: $DIR/issue-75930-derive-cfg.rs:94:12: 94:28 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [], - span: $DIR/issue-75930-derive-cfg.rs:64:28: 64:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:94:28: 94:30 (#0), }, Group { delimiter: Brace, @@ -1154,122 +1154,122 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:65:13: 65:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:13: 95:14 (#0), }, Punct { ch: '!', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:65:14: 65:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:14: 95:15 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg_attr", - span: $DIR/issue-75930-derive-cfg.rs:65:16: 65:24 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:16: 95:24 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:65:25: 65:28 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:25: 95:28 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:65:29: 65:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:29: 95:34 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:65:28: 65:35 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:28: 95:35 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:65:35: 65:36 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:35: 95:36 (#0), }, Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:65:37: 65:40 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:37: 95:40 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:65:41: 65:46 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:41: 95:46 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:65:40: 65:47 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:40: 95:47 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:65:24: 65:48 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:24: 95:48 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:65:15: 65:49 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:15: 95:49 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:64:31: 66:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:94:31: 96:10 (#0), }, Literal { kind: Integer, symbol: "0", suffix: None, - span: $DIR/issue-75930-derive-cfg.rs:68:9: 68:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:98:9: 98:10 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:28:17: 69:6 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:17: 99:6 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:28:12: 69:7 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:12: 99:7 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:69:7: 69:8 (#0), + span: $DIR/issue-75930-derive-cfg.rs:99:7: 99:8 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:70:5: 70:6 (#0), + span: $DIR/issue-75930-derive-cfg.rs:100:5: 100:6 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_helper", - span: $DIR/issue-75930-derive-cfg.rs:70:7: 70:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:100:7: 100:19 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "d", - span: $DIR/issue-75930-derive-cfg.rs:70:20: 70:21 (#0), + span: $DIR/issue-75930-derive-cfg.rs:100:20: 100:21 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:70:19: 70:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:100:19: 100:22 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:70:6: 70:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:100:6: 100:23 (#0), }, Ident { ident: "fourth", - span: $DIR/issue-75930-derive-cfg.rs:71:5: 71:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:101:5: 101:11 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:71:11: 71:12 (#0), + span: $DIR/issue-75930-derive-cfg.rs:101:11: 101:12 (#0), }, Ident { ident: "B", - span: $DIR/issue-75930-derive-cfg.rs:71:13: 71:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:101:13: 101:14 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:25:32: 72:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:32: 102:2 (#0), }, ] PRINT-DERIVE INPUT (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[print_helper(b)] struct Foo < B > @@ -1289,141 +1289,141 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:19:1: 19:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:49:1: 49:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_helper", - span: $DIR/issue-75930-derive-cfg.rs:19:3: 19:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:49:3: 49:15 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "a", - span: $DIR/issue-75930-derive-cfg.rs:19:16: 19:17 (#0), + span: $DIR/issue-75930-derive-cfg.rs:49:16: 49:17 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:19:15: 19:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:49:15: 49:18 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:19:2: 19:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:49:2: 49:19 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:21:1: 21:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:51:1: 51:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "allow", - span: $DIR/issue-75930-derive-cfg.rs:21:24: 21:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:51:24: 51:29 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "dead_code", - span: $DIR/issue-75930-derive-cfg.rs:21:30: 21:39 (#0), + span: $DIR/issue-75930-derive-cfg.rs:51:30: 51:39 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:21:29: 21:40 (#0), + span: $DIR/issue-75930-derive-cfg.rs:51:29: 51:40 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:21:1: 21:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:51:1: 51:2 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:24:1: 24:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:54:1: 54:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_helper", - span: $DIR/issue-75930-derive-cfg.rs:24:3: 24:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:54:3: 54:15 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "b", - span: $DIR/issue-75930-derive-cfg.rs:24:16: 24:17 (#0), + span: $DIR/issue-75930-derive-cfg.rs:54:16: 54:17 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:24:15: 24:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:54:15: 54:18 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:24:2: 24:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:54:2: 54:19 (#0), }, Ident { ident: "struct", - span: $DIR/issue-75930-derive-cfg.rs:25:1: 25:7 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:1: 55:7 (#0), }, Ident { ident: "Foo", - span: $DIR/issue-75930-derive-cfg.rs:25:8: 25:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:8: 55:11 (#0), }, Punct { ch: '<', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:25:11: 25:12 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:11: 55:12 (#0), }, Ident { ident: "B", - span: $DIR/issue-75930-derive-cfg.rs:25:29: 25:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:29: 55:30 (#0), }, Punct { ch: '>', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:25:30: 25:31 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:30: 55:31 (#0), }, Group { delimiter: Brace, stream: TokenStream [ Ident { ident: "second", - span: $DIR/issue-75930-derive-cfg.rs:27:40: 27:46 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:40: 57:46 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:27:46: 27:47 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:46: 57:47 (#0), }, Ident { ident: "bool", - span: $DIR/issue-75930-derive-cfg.rs:27:48: 27:52 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:48: 57:52 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:27:52: 27:53 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:52: 57:53 (#0), }, Ident { ident: "third", - span: $DIR/issue-75930-derive-cfg.rs:28:5: 28:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:5: 58:10 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:28:10: 28:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:10: 58:11 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "u8", - span: $DIR/issue-75930-derive-cfg.rs:28:13: 28:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:13: 58:15 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:28:15: 28:16 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:15: 58:16 (#0), }, Group { delimiter: Brace, @@ -1431,58 +1431,58 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:30:9: 30:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:9: 60:10 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:30:11: 30:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:11: 60:14 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:30:15: 30:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:15: 60:18 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:30:19: 30:24 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:19: 60:24 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:30:18: 30:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:18: 60:25 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:30:14: 30:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:14: 60:26 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:30:10: 30:27 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:10: 60:27 (#0), }, Ident { ident: "struct", - span: $DIR/issue-75930-derive-cfg.rs:30:28: 30:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:28: 60:34 (#0), }, Ident { ident: "Inner", - span: $DIR/issue-75930-derive-cfg.rs:30:35: 30:40 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:35: 60:40 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:30:40: 30:41 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:40: 60:41 (#0), }, Ident { ident: "match", - span: $DIR/issue-75930-derive-cfg.rs:32:9: 32:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:62:9: 62:14 (#0), }, Ident { ident: "true", - span: $DIR/issue-75930-derive-cfg.rs:32:15: 32:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:62:15: 62:19 (#0), }, Group { delimiter: Brace, @@ -1490,151 +1490,151 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:34:13: 34:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:13: 64:14 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "allow", - span: $DIR/issue-75930-derive-cfg.rs:34:36: 34:41 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:36: 64:41 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "warnings", - span: $DIR/issue-75930-derive-cfg.rs:34:42: 34:50 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:42: 64:50 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:34:41: 34:51 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:41: 64:51 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:34:13: 34:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:13: 64:14 (#0), }, Ident { ident: "false", - span: $DIR/issue-75930-derive-cfg.rs:34:54: 34:59 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:54: 64:59 (#0), }, Punct { ch: '=', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:34:60: 34:61 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:60: 64:61 (#0), }, Punct { ch: '>', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:34:61: 34:62 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:61: 64:62 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/issue-75930-derive-cfg.rs:34:63: 34:65 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:63: 64:65 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:34:65: 34:66 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:65: 64:66 (#0), }, Ident { ident: "_", - span: $DIR/issue-75930-derive-cfg.rs:35:13: 35:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:65:13: 65:14 (#0), }, Punct { ch: '=', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:35:15: 35:16 (#0), + span: $DIR/issue-75930-derive-cfg.rs:65:15: 65:16 (#0), }, Punct { ch: '>', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:35:16: 35:17 (#0), + span: $DIR/issue-75930-derive-cfg.rs:65:16: 65:17 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/issue-75930-derive-cfg.rs:35:18: 35:20 (#0), + span: $DIR/issue-75930-derive-cfg.rs:65:18: 65:20 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:32:20: 36:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:62:20: 66:10 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:36:10: 36:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:66:10: 66:11 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:43:9: 43:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:9: 73:10 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_helper", - span: $DIR/issue-75930-derive-cfg.rs:43:11: 43:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:11: 73:23 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "c", - span: $DIR/issue-75930-derive-cfg.rs:43:24: 43:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:24: 73:25 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:23: 43:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:23: 73:26 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:10: 43:27 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:10: 73:27 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:43:28: 43:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:28: 73:29 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:43:30: 43:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:30: 73:33 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:43:34: 43:37 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:34: 73:37 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:43:38: 43:43 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:38: 73:43 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:37: 43:44 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:37: 73:44 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:33: 43:45 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:33: 73:45 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:29: 43:46 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:29: 73:46 (#0), }, Ident { ident: "fn", - span: $DIR/issue-75930-derive-cfg.rs:43:47: 43:49 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:47: 73:49 (#0), }, Ident { ident: "kept_fn", - span: $DIR/issue-75930-derive-cfg.rs:43:50: 43:57 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:50: 73:57 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [], - span: $DIR/issue-75930-derive-cfg.rs:43:57: 43:59 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:57: 73:59 (#0), }, Group { delimiter: Brace, @@ -1642,82 +1642,82 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:44:13: 44:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:13: 74:14 (#0), }, Punct { ch: '!', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:44:14: 44:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:14: 74:15 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:44:16: 44:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:16: 74:19 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:44:20: 44:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:20: 74:23 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:44:24: 44:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:24: 74:29 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:44:23: 44:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:23: 74:30 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:44:19: 44:31 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:19: 74:31 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:44:15: 44:32 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:15: 74:32 (#0), }, Ident { ident: "let", - span: $DIR/issue-75930-derive-cfg.rs:45:13: 45:16 (#0), + span: $DIR/issue-75930-derive-cfg.rs:75:13: 75:16 (#0), }, Ident { ident: "my_val", - span: $DIR/issue-75930-derive-cfg.rs:45:17: 45:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:75:17: 75:23 (#0), }, Punct { ch: '=', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:45:24: 45:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:75:24: 75:25 (#0), }, Ident { ident: "true", - span: $DIR/issue-75930-derive-cfg.rs:45:26: 45:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:75:26: 75:30 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:45:30: 45:31 (#0), + span: $DIR/issue-75930-derive-cfg.rs:75:30: 75:31 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:60: 46:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:60: 76:10 (#0), }, Ident { ident: "enum", - span: $DIR/issue-75930-derive-cfg.rs:48:9: 48:13 (#0), + span: $DIR/issue-75930-derive-cfg.rs:78:9: 78:13 (#0), }, Ident { ident: "TupleEnum", - span: $DIR/issue-75930-derive-cfg.rs:48:14: 48:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:78:14: 78:23 (#0), }, Group { delimiter: Brace, stream: TokenStream [ Ident { ident: "Foo", - span: $DIR/issue-75930-derive-cfg.rs:49:13: 49:16 (#0), + span: $DIR/issue-75930-derive-cfg.rs:79:13: 79:16 (#0), }, Group { delimiter: Parenthesis, @@ -1725,64 +1725,64 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:52:17: 52:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:17: 82:18 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:52:19: 52:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:19: 82:22 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:52:23: 52:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:23: 82:26 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:52:27: 52:32 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:27: 82:32 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:52:26: 52:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:26: 82:33 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:52:22: 52:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:22: 82:34 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:52:18: 52:35 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:18: 82:35 (#0), }, Ident { ident: "i32", - span: $DIR/issue-75930-derive-cfg.rs:52:36: 52:39 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:36: 82:39 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:52:39: 52:40 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:39: 82:40 (#0), }, Ident { ident: "u8", - span: $DIR/issue-75930-derive-cfg.rs:53:39: 53:41 (#0), + span: $DIR/issue-75930-derive-cfg.rs:83:39: 83:41 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:49:16: 54:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:79:16: 84:14 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:48:24: 55:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:78:24: 85:10 (#0), }, Ident { ident: "struct", - span: $DIR/issue-75930-derive-cfg.rs:57:9: 57:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:87:9: 87:15 (#0), }, Ident { ident: "TupleStruct", - span: $DIR/issue-75930-derive-cfg.rs:57:16: 57:27 (#0), + span: $DIR/issue-75930-derive-cfg.rs:87:16: 87:27 (#0), }, Group { delimiter: Parenthesis, @@ -1790,115 +1790,115 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:59:13: 59:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:13: 89:14 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:59:15: 59:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:15: 89:18 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:59:19: 59:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:19: 89:22 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:59:23: 59:28 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:23: 89:28 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:59:22: 59:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:22: 89:29 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:59:18: 59:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:18: 89:30 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:59:14: 59:31 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:14: 89:31 (#0), }, Ident { ident: "i32", - span: $DIR/issue-75930-derive-cfg.rs:59:32: 59:35 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:32: 89:35 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:59:35: 59:36 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:35: 89:36 (#0), }, Ident { ident: "u8", - span: $DIR/issue-75930-derive-cfg.rs:61:13: 61:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:91:13: 91:15 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:57:27: 62:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:87:27: 92:10 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:62:10: 62:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:92:10: 92:11 (#0), }, Literal { kind: Integer, symbol: "0", suffix: None, - span: $DIR/issue-75930-derive-cfg.rs:68:9: 68:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:98:9: 98:10 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:28:17: 69:6 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:17: 99:6 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:28:12: 69:7 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:12: 99:7 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:69:7: 69:8 (#0), + span: $DIR/issue-75930-derive-cfg.rs:99:7: 99:8 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:70:5: 70:6 (#0), + span: $DIR/issue-75930-derive-cfg.rs:100:5: 100:6 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_helper", - span: $DIR/issue-75930-derive-cfg.rs:70:7: 70:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:100:7: 100:19 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "d", - span: $DIR/issue-75930-derive-cfg.rs:70:20: 70:21 (#0), + span: $DIR/issue-75930-derive-cfg.rs:100:20: 100:21 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:70:19: 70:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:100:19: 100:22 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:70:6: 70:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:100:6: 100:23 (#0), }, Ident { ident: "fourth", - span: $DIR/issue-75930-derive-cfg.rs:71:5: 71:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:101:5: 101:11 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:71:11: 71:12 (#0), + span: $DIR/issue-75930-derive-cfg.rs:101:11: 101:12 (#0), }, Ident { ident: "B", - span: $DIR/issue-75930-derive-cfg.rs:71:13: 71:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:101:13: 101:14 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:25:32: 72:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:32: 102:2 (#0), }, ] diff --git a/tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr b/tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr index 4f3f9d1eb3a..21f1fdba886 100644 --- a/tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr +++ b/tests/ui/range/range-pattern-out-of-bounds-issue-68972.stderr @@ -2,13 +2,13 @@ error: literal out of range for `u8` --> $DIR/range-pattern-out-of-bounds-issue-68972.rs:5:14 | LL | 251..257 => {} - | ^^^ this value doesn't fit in `u8` whose maximum value is `255` + | ^^^ this value does not fit into the type `u8` whose range is `0..=255` error: literal out of range for `u8` --> $DIR/range-pattern-out-of-bounds-issue-68972.rs:7:15 | LL | 251..=256 => {} - | ^^^ this value doesn't fit in `u8` whose maximum value is `255` + | ^^^ this value does not fit into the type `u8` whose range is `0..=255` error: aborting due to 2 previous errors diff --git a/tests/ui/resolve/issue-55673.fixed b/tests/ui/resolve/issue-55673.fixed new file mode 100644 index 00000000000..261742a26cb --- /dev/null +++ b/tests/ui/resolve/issue-55673.fixed @@ -0,0 +1,21 @@ +// run-rustfix +#![allow(dead_code)] +trait Foo { + type Bar; +} + +fn foo<T: Foo>() +where + T::Bar: std::fmt::Debug, + //~^ ERROR associated type `Baa` not found for `T` +{ +} + +fn bar<T>() +where + T::Bar: std::fmt::Debug, T: Foo + //~^ ERROR associated type `Baa` not found for `T` +{ +} + +fn main() {} diff --git a/tests/ui/resolve/issue-55673.rs b/tests/ui/resolve/issue-55673.rs index 0436bd39742..6ac49be141c 100644 --- a/tests/ui/resolve/issue-55673.rs +++ b/tests/ui/resolve/issue-55673.rs @@ -1,3 +1,5 @@ +// run-rustfix +#![allow(dead_code)] trait Foo { type Bar; } @@ -9,4 +11,11 @@ where { } +fn bar<T>() +where + T::Baa: std::fmt::Debug, + //~^ ERROR associated type `Baa` not found for `T` +{ +} + fn main() {} diff --git a/tests/ui/resolve/issue-55673.stderr b/tests/ui/resolve/issue-55673.stderr index 39318f95905..ffc3252230a 100644 --- a/tests/ui/resolve/issue-55673.stderr +++ b/tests/ui/resolve/issue-55673.stderr @@ -1,9 +1,29 @@ error[E0220]: associated type `Baa` not found for `T` - --> $DIR/issue-55673.rs:7:8 + --> $DIR/issue-55673.rs:9:8 | LL | T::Baa: std::fmt::Debug, | ^^^ there is a similarly named associated type `Bar` in the trait `Foo` + | +help: change the associated type name to use `Bar` from `Foo` + | +LL | T::Bar: std::fmt::Debug, + | ~~~ + +error[E0220]: associated type `Baa` not found for `T` + --> $DIR/issue-55673.rs:16:8 + | +LL | T::Baa: std::fmt::Debug, + | ^^^ there is a similarly named associated type `Bar` in the trait `Foo` + | +help: consider further restricting type parameter `T` + | +LL | T::Baa: std::fmt::Debug, T: Foo + | ~~~~~~~~ +help: and also change the associated type name + | +LL | T::Bar: std::fmt::Debug, + | ~~~ -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs b/tests/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs index 49462f52fb4..927ecd9aee0 100644 --- a/tests/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs +++ b/tests/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs @@ -9,11 +9,9 @@ impl A { trait B { async fn associated(); - //~^ ERROR cannot be declared `async` } impl B for A { async fn associated(); //~ ERROR without body - //~^ ERROR cannot be declared `async` } fn main() {} diff --git a/tests/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr b/tests/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr index 1354abb4f14..da9eeea954a 100644 --- a/tests/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr +++ b/tests/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr @@ -15,39 +15,12 @@ LL | async fn inherent(); | help: provide a definition for the function: `{ <body> }` error: associated function in `impl` without body - --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:5 + --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:14:5 | LL | async fn associated(); | ^^^^^^^^^^^^^^^^^^^^^- | | | help: provide a definition for the function: `{ <body> }` -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:11:5 - | -LL | async fn associated(); - | -----^^^^^^^^^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error[E0706]: functions in traits cannot be declared `async` - --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:5 - | -LL | async fn associated(); - | -----^^^^^^^^^^^^^^^^^ - | | - | `async` because of this - | - = note: `async` trait functions are not currently supported - = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait - = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information - = help: add `#![feature(async_fn_in_trait)]` to the crate attributes to enable - -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0706`. diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.rs b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.rs index 77227ebd834..1933a68c221 100644 --- a/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.rs +++ b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.rs @@ -1,4 +1,3 @@ -#![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] mod child { diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.stderr b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.stderr index c4371a0024c..40f736c215d 100644 --- a/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.stderr +++ b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `Something: Termination` is not satisfied - --> $DIR/issue-103052-2.rs:12:22 + --> $DIR/issue-103052-2.rs:11:22 | LL | fn main() -> Something { | ^^^^^^^^^ the trait `Termination` is not implemented for `Something` | note: required by a bound in `Main::{opaque#0}` - --> $DIR/issue-103052-2.rs:6:27 + --> $DIR/issue-103052-2.rs:5:27 | LL | fn main() -> impl std::process::Termination; | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Main::{opaque#0}` diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr index ad11c090f12..6d436018bf4 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr @@ -1,14 +1,12 @@ -error[E0277]: the trait bound `T: Foo` is not satisfied - --> $DIR/assoc-type-const-bound-usage.rs:12:6 +error[E0308]: mismatched types + --> $DIR/assoc-type-const-bound-usage.rs:12:5 | LL | <T as Foo>::Assoc::foo(); - | ^ the trait `Foo` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `host`, found `true` | -help: consider further restricting this bound - | -LL | const fn foo<T: ~const Foo + Foo>() { - | +++++ + = note: expected constant `host` + found constant `true` error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs index f396deff4fe..8e4de57b019 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs @@ -4,7 +4,6 @@ associated_type_bounds, const_trait_impl, const_cmp, - return_position_impl_trait_in_trait, )] use std::marker::Destruct; diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr index f9078e22791..4a9090d0b53 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr @@ -5,31 +5,31 @@ LL | const_cmp, | ^^^^^^^^^ error: ~const can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:12:30 + --> $DIR/const-impl-trait.rs:11:30 | LL | const fn cmp(a: &impl ~const PartialEq) -> bool { | ^^^^^^^^^ error: ~const can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:16:30 + --> $DIR/const-impl-trait.rs:15:30 | LL | const fn wrap(x: impl ~const PartialEq + ~const Destruct) | ^^^^^^^^^ error: ~const can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:17:20 + --> $DIR/const-impl-trait.rs:16:20 | LL | -> impl ~const PartialEq + ~const Destruct | ^^^^^^^^^ error: ~const can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:24:29 + --> $DIR/const-impl-trait.rs:23:29 | LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy; | ^^^^^^^^^ error: ~const can only be applied to `#[const_trait]` traits - --> $DIR/const-impl-trait.rs:28:29 + --> $DIR/const-impl-trait.rs:27:29 | LL | fn huh() -> impl ~const PartialEq + ~const Destruct + Copy { | ^^^^^^^^^ 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 new file mode 100644 index 00000000000..c38b4b3f1a2 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs @@ -0,0 +1,504 @@ +#![crate_type = "lib"] +#![feature(no_core, lang_items, unboxed_closures, auto_traits, intrinsics, rustc_attrs)] +#![feature(fundamental)] +#![feature(const_trait_impl, effects, const_mut_refs)] +#![allow(internal_features)] +#![no_std] +#![no_core] + +// known-bug: #110395 + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +#[lang = "add"] +#[const_trait] +trait Add<Rhs = Self> { + type Output; + + fn add(self, rhs: Rhs) -> Self::Output; +} + +// FIXME we shouldn't need to have to specify `Rhs`. +impl const Add<i32> for i32 { + type Output = i32; + fn add(self, rhs: i32) -> i32 { + loop {} + } +} + +fn foo() { + let x = 42_i32 + 43_i32; +} + +const fn bar() { + let x = 42_i32 + 43_i32; +} + + +#[lang = "Try"] +#[const_trait] +trait Try: FromResidual { + type Output; + type Residual; + + #[lang = "from_output"] + fn from_output(output: Self::Output) -> Self; + + #[lang = "branch"] + fn branch(self) -> ControlFlow<Self::Residual, Self::Output>; +} + +// FIXME +// #[const_trait] +trait FromResidual<R = <Self as Try>::Residual> { + #[lang = "from_residual"] + fn from_residual(residual: R) -> Self; +} + +enum ControlFlow<B, C = ()> { + #[lang = "Continue"] + Continue(C), + #[lang = "Break"] + Break(B), +} + +#[const_trait] +#[lang = "fn"] +#[rustc_paren_sugar] +trait Fn<Args: Tuple>: ~const FnMut<Args> { + extern "rust-call" fn call(&self, args: Args) -> Self::Output; +} + +#[const_trait] +#[lang = "fn_mut"] +#[rustc_paren_sugar] +trait FnMut<Args: Tuple>: ~const FnOnce<Args> { + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; +} + +#[const_trait] +#[lang = "fn_once"] +#[rustc_paren_sugar] +trait FnOnce<Args: Tuple> { + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +struct ConstFnMutClosure<CapturedData, Function> { + data: CapturedData, + func: Function, +} + +#[lang = "tuple_trait"] +pub trait Tuple {} + +macro_rules! impl_fn_mut_tuple { + ($($var:ident)*) => { + impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const + FnOnce<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function> + where + Function: ~const Fn(($(&mut $var),*), ClosureArguments) -> ClosureReturnValue, + Function: ~const Destruct, + { + type Output = ClosureReturnValue; + + extern "rust-call" fn call_once(mut self, args: ClosureArguments) -> Self::Output { + self.call_mut(args) + } + } + impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const + FnMut<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function> + where + Function: ~const Fn(($(&mut $var),*), ClosureArguments)-> ClosureReturnValue, + Function: ~const Destruct, + { + extern "rust-call" fn call_mut(&mut self, args: ClosureArguments) -> Self::Output { + #[allow(non_snake_case)] + let ($($var),*) = &mut self.data; + (self.func)(($($var),*), args) + } + } + }; +} +//impl_fn_mut_tuple!(A); +//impl_fn_mut_tuple!(A B); +//impl_fn_mut_tuple!(A B C); +//impl_fn_mut_tuple!(A B C D); +//impl_fn_mut_tuple!(A B C D E); + +#[lang = "receiver"] +trait Receiver {} + +impl<T: ?Sized> Receiver for &T {} + +impl<T: ?Sized> Receiver for &mut T {} + +#[lang = "destruct"] +#[const_trait] +trait Destruct {} + +#[lang = "freeze"] +unsafe auto trait Freeze {} + +#[lang = "drop"] +#[const_trait] +trait Drop { + fn drop(&mut self); +} + +/* +#[const_trait] +trait Residual<O> { + type TryType: ~const Try<Output = O, Residual = Self> + Try<Output = O, Residual = Self>; +} +*/ + +const fn size_of<T>() -> usize { + 42 +} + +impl Copy for u8 {} + +impl usize { + #[rustc_allow_incoherent_impl] + const fn repeat_u8(x: u8) -> usize { + usize::from_ne_bytes([x; size_of::<usize>()]) + } + #[rustc_allow_incoherent_impl] + const fn from_ne_bytes(bytes: [u8; size_of::<Self>()]) -> Self { + loop {} + } +} + +#[rustc_do_not_const_check] // hooked by const-eval +const fn panic_display() { + panic_fmt(); +} + +fn panic_fmt() {} + +#[lang = "index"] +#[const_trait] +trait Index<Idx: ?Sized> { + type Output: ?Sized; + + fn index(&self, index: Idx) -> &Self::Output; +} + + +#[const_trait] +unsafe trait SliceIndex<T: ?Sized> { + type Output: ?Sized; + fn index(self, slice: &T) -> &Self::Output; +} + +impl<T, I> const Index<I> for [T] +where + I: ~const SliceIndex<[T]>, +{ + type Output = I::Output; + + #[inline] + fn index(&self, index: I) -> &I::Output { + index.index(self) + } +} +/* FIXME +impl<T, I, const N: usize> const Index<I> for [T; N] +where + [T]: ~const Index<I>, +{ + type Output = <[T] as Index<I>>::Output; + + #[inline] + // FIXME: make `Self::Output` act like `<Self as ~const Index<I>>::Output` + fn index(&self, index: I) -> &<[T] as Index<I>>::Output { + Index::index(self as &[T], index) + } +} +*/ + +#[lang = "unsize"] +trait Unsize<T: ?Sized> { +} + +#[lang = "coerce_unsized"] +trait CoerceUnsized<T: ?Sized> { +} + +impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} + + +#[lang = "deref"] +// #[const_trait] FIXME +trait Deref { + #[lang = "deref_target"] + type Target: ?Sized; + + fn deref(&self) -> &Self::Target; +} + + +impl<T: ?Sized> /* const */ Deref for &T { + type Target = T; + + fn deref(&self) -> &T { + *self + } +} + +impl<T: ?Sized> /* const */ Deref for &mut T { + type Target = T; + + fn deref(&self) -> &T { + *self + } +} + +enum Option<T> { + #[lang = "None"] + None, + #[lang = "Some"] + Some(T), +} + +impl<T> Option<T> { + const fn as_ref(&self) -> Option<&T> { + match *self { + Some(ref x) => Some(x), + None => None, + } + } + + const fn as_mut(&mut self) -> Option<&mut T> { + match *self { + Some(ref mut x) => Some(x), + None => None, + } + } +} + +use Option::*; + +/* +const fn as_deref<T>(opt: &Option<T>) -> Option<&T::Target> +where + T: ~const Deref, +{ + match opt { + Option::Some(t) => Option::Some(t.deref()), + Option::None => Option::None, + } +} +*/ + +#[const_trait] +trait Into<T>: Sized { + fn into(self) -> T; +} + +#[const_trait] +trait From<T>: Sized { + fn from(value: T) -> Self; +} + +impl<T, U> const Into<U> for T +where + U: ~const From<T>, +{ + fn into(self) -> U { + U::from(self) + } +} + +impl<T> const From<T> for T { + fn from(t: T) -> T { + t + } +} + +enum Result<T, E> { + Ok(T), + Err(E), +} +use Result::*; + +fn from_str(s: &str) -> Result<bool, ()> { + match s { + "true" => Ok(true), + "false" => Ok(false), + _ => Err(()), + } +} + +#[lang = "eq"] +#[const_trait] +trait PartialEq<Rhs: ?Sized = Self> { + fn eq(&self, other: &Rhs) -> bool; + fn ne(&self, other: &Rhs) -> bool { + !self.eq(other) + } +} + +// FIXME(effects): again, this should not error without Rhs specified +impl PartialEq<str> for str { + fn eq(&self, other: &str) -> bool { + loop {} + } +} + + +#[lang = "not"] +#[const_trait] +trait Not { + type Output; + fn not(self) -> Self::Output; +} + +impl const Not for bool { + type Output = bool; + fn not(self) -> bool { + !self + } +} + +impl Copy for bool {} +impl<'a> Copy for &'a str {} + +#[lang = "pin"] +#[fundamental] +#[repr(transparent)] +struct Pin<P> { + pointer: P, +} + +impl<P> Pin<P> { + #[lang = "new_unchecked"] + const unsafe fn new_unchecked(pointer: P) -> Pin<P> { + Pin { pointer } + } +} + +impl<'a, T: ?Sized> Pin<&'a T> { + const fn get_ref(self) -> &'a T { + self.pointer + } +} + + +impl<P: Deref> Pin<P> { + /* const */ fn as_ref(&self) -> Pin<&P::Target> + where + P: /* ~const */ Deref, + { + unsafe { Pin::new_unchecked(&*self.pointer) } + } +} + + +impl<'a, T: ?Sized> Pin<&'a mut T> { + const unsafe fn get_unchecked_mut(self) -> &'a mut T { + self.pointer + } +} +/* FIXME lol +impl<T> Option<T> { + const fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&T>> { + match Pin::get_ref(self).as_ref() { + Some(x) => unsafe { Some(Pin::new_unchecked(x)) }, + None => None, + } + } + + const fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> { + unsafe { + match Pin::get_unchecked_mut(self).as_mut() { + Some(x) => Some(Pin::new_unchecked(x)), + None => None, + } + } + } +} +*/ + +impl<P: /* ~const */ Deref> /* const */ Deref for Pin<P> { + type Target = P::Target; + fn deref(&self) -> &P::Target { + Pin::get_ref(Pin::as_ref(self)) + } +} + +impl<T> /* const */ Deref for Option<T> { + type Target = T; + fn deref(&self) -> &T { + loop {} + } +} + +impl<P: Receiver> Receiver for Pin<P> {} + +impl<T: Clone> Clone for RefCell<T> { + fn clone(&self) -> RefCell<T> { + RefCell::new(self.borrow().clone()) + } +} + +struct RefCell<T: ?Sized> { + borrow: UnsafeCell<()>, + value: UnsafeCell<T>, +} +impl<T> RefCell<T> { + const fn new(value: T) -> RefCell<T> { + loop {} + } +} +impl<T: ?Sized> RefCell<T> { + fn borrow(&self) -> Ref<'_, T> { + loop {} + } +} + +#[lang = "unsafe_cell"] +#[repr(transparent)] +struct UnsafeCell<T: ?Sized> { + value: T, +} + +struct Ref<'b, T: ?Sized + 'b> { + value: *const T, + borrow: &'b UnsafeCell<()>, +} + +impl<T: ?Sized> Deref for Ref<'_, T> { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + loop {} + } +} + +#[lang = "clone"] +#[rustc_trivial_field_reads] +#[const_trait] +trait Clone: Sized { + fn clone(&self) -> Self; + fn clone_from(&mut self, source: &Self) + where + Self: ~const Destruct, + { + *self = source.clone() + } +} + +#[lang = "structural_peq"] +trait StructuralPartialEq {} + +#[lang = "structural_teq"] +trait StructuralEq {} + +const fn drop<T: ~const Destruct>(_: T) {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr new file mode 100644 index 00000000000..02429374218 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.stderr @@ -0,0 +1,32 @@ +error[E0369]: cannot add `i32` to `i32` + --> $DIR/minicore.rs:33:20 + | +LL | let x = 42_i32 + 43_i32; + | ------ ^ ------ i32 + | | + | i32 + +error[E0369]: cannot add `i32` to `i32` + --> $DIR/minicore.rs:37:20 + | +LL | let x = 42_i32 + 43_i32; + | ------ ^ ------ i32 + | | + | i32 + +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 + +Some errors have detailed explanations: E0369, E0600. +For more information about an error, try `rustc --explain E0369`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs new file mode 100644 index 00000000000..b30d7743edf --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs @@ -0,0 +1,11 @@ +// check-pass +#![feature(const_trait_impl, effects)] + +pub trait Owo<X = <Self as Uwu>::T> {} + +#[const_trait] +pub trait Uwu: Owo { + type T; +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr index c94563d3591..2a9647da782 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr @@ -1,35 +1,21 @@ -error[E0277]: the trait bound `T: ~const Bar` is not satisfied +error[E0308]: mismatched types --> $DIR/trait-where-clause-const.rs:21:5 | LL | T::b(); - | ^ the trait `Bar` is not implemented for `T` + | ^^^^^^ expected `host`, found `true` | -note: required by a bound in `Foo::b` - --> $DIR/trait-where-clause-const.rs:15:24 - | -LL | fn b() where Self: ~const Bar; - | ^^^^^^^^^^ required by this bound in `Foo::b` -help: consider further restricting this bound - | -LL | const fn test1<T: ~const Foo + Bar + Bar>() { - | +++++ + = note: expected constant `host` + found constant `true` -error[E0277]: the trait bound `T: ~const Bar` is not satisfied - --> $DIR/trait-where-clause-const.rs:23:12 +error[E0308]: mismatched types + --> $DIR/trait-where-clause-const.rs:23:5 | LL | T::c::<T>(); - | ^ the trait `Bar` is not implemented for `T` - | -note: required by a bound in `Foo::c` - --> $DIR/trait-where-clause-const.rs:16:13 - | -LL | fn c<T: ~const Bar>(); - | ^^^^^^^^^^ required by this bound in `Foo::c` -help: consider further restricting this bound + | ^^^^^^^^^^^ expected `host`, found `true` | -LL | const fn test1<T: ~const Foo + Bar + Bar>() { - | +++++ + = note: expected constant `host` + found constant `true` error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/self/self-impl.stderr b/tests/ui/self/self-impl.stderr index 36372b644d6..18ffd15427f 100644 --- a/tests/ui/self/self-impl.stderr +++ b/tests/ui/self/self-impl.stderr @@ -2,13 +2,13 @@ error[E0223]: ambiguous associated type --> $DIR/self-impl.rs:23:16 | LL | let _: <Self>::Baz = true; - | ^^^^^^^^^^^ help: use the fully-qualified path: `<Bar as Foo>::Baz` + | ^^^^^^^^^^^ help: use fully-qualified syntax: `<Bar as Foo>::Baz` error[E0223]: ambiguous associated type --> $DIR/self-impl.rs:25:16 | LL | let _: Self::Baz = true; - | ^^^^^^^^^ help: use the fully-qualified path: `<Bar as Foo>::Baz` + | ^^^^^^^^^ help: use fully-qualified syntax: `<Bar as Foo>::Baz` error: aborting due to 2 previous errors diff --git a/tests/ui/structs/struct-path-associated-type.stderr b/tests/ui/structs/struct-path-associated-type.stderr index acfddaf3760..0c9d2aad5d8 100644 --- a/tests/ui/structs/struct-path-associated-type.stderr +++ b/tests/ui/structs/struct-path-associated-type.stderr @@ -48,19 +48,19 @@ error[E0223]: ambiguous associated type --> $DIR/struct-path-associated-type.rs:32:13 | LL | let s = S::A {}; - | ^^^^ help: use the fully-qualified path: `<S as Tr>::A` + | ^^^^ help: use fully-qualified syntax: `<S as Tr>::A` error[E0223]: ambiguous associated type --> $DIR/struct-path-associated-type.rs:33:13 | LL | let z = S::A::<u8> {}; - | ^^^^ help: use the fully-qualified path: `<S as Tr>::A` + | ^^^^ help: use fully-qualified syntax: `<S as Tr>::A` error[E0223]: ambiguous associated type --> $DIR/struct-path-associated-type.rs:35:9 | LL | S::A {} => {} - | ^^^^ help: use the fully-qualified path: `<S as Tr>::A` + | ^^^^ help: use fully-qualified syntax: `<S as Tr>::A` error: aborting due to 8 previous errors diff --git a/tests/ui/suggestions/issue-102972.fixed b/tests/ui/suggestions/issue-102972.fixed new file mode 100644 index 00000000000..ebd73b2dc14 --- /dev/null +++ b/tests/ui/suggestions/issue-102972.fixed @@ -0,0 +1,41 @@ +// run-rustfix + +fn test1() { + let mut chars = "Hello".chars(); + let iter = chars.by_ref(); + while let Some(_c) = iter.next() { + iter.next(); //~ ERROR cannot borrow `chars` as mutable more than once at a time + } +} + +fn test2() { + let v = vec![1, 2, 3]; + let mut iter = v.iter(); + while let Some(_i) = iter.next() { + iter.next(); //~ ERROR borrow of moved value: `iter` + } +} + +fn test3() { + let v = vec![(), (), ()]; + let mut i = v.iter(); + let iter = i.by_ref(); + while let Some(()) = iter.next() { + iter.next(); //~ ERROR cannot borrow `i` + } +} + +fn test4() { + let v = vec![(), (), ()]; + let mut iter = v.iter(); + while let Some(()) = iter.next() { + iter.next(); //~ ERROR borrow of moved value: `iter` + } +} + +fn main() { + test1(); + test2(); + test3(); + test4(); +} diff --git a/tests/ui/suggestions/issue-102972.rs b/tests/ui/suggestions/issue-102972.rs index 106288b054d..1f8e9776759 100644 --- a/tests/ui/suggestions/issue-102972.rs +++ b/tests/ui/suggestions/issue-102972.rs @@ -1,3 +1,5 @@ +// run-rustfix + fn test1() { let mut chars = "Hello".chars(); for _c in chars.by_ref() { @@ -13,4 +15,25 @@ fn test2() { } } -fn main() { } +fn test3() { + let v = vec![(), (), ()]; + let mut i = v.iter(); + for () in i.by_ref() { + i.next(); //~ ERROR cannot borrow `i` + } +} + +fn test4() { + let v = vec![(), (), ()]; + let mut iter = v.iter(); + for () in iter { + iter.next(); //~ ERROR borrow of moved value: `iter` + } +} + +fn main() { + test1(); + test2(); + test3(); + test4(); +} diff --git a/tests/ui/suggestions/issue-102972.stderr b/tests/ui/suggestions/issue-102972.stderr index 3303d6bbc3f..4b0d3b96f85 100644 --- a/tests/ui/suggestions/issue-102972.stderr +++ b/tests/ui/suggestions/issue-102972.stderr @@ -1,5 +1,5 @@ error[E0499]: cannot borrow `chars` as mutable more than once at a time - --> $DIR/issue-102972.rs:4:9 + --> $DIR/issue-102972.rs:6:9 | LL | for _c in chars.by_ref() { | -------------- @@ -8,9 +8,17 @@ LL | for _c in chars.by_ref() { | first borrow later used here LL | chars.next(); | ^^^^^ second mutable borrow occurs here + | + = note: a for loop advances the iterator for you, the result is stored in `_c` +help: if you want to call `next` on a iterator within the loop, consider using `while let` + | +LL ~ let iter = chars.by_ref(); +LL ~ while let Some(_c) = iter.next() { +LL ~ iter.next(); + | error[E0382]: borrow of moved value: `iter` - --> $DIR/issue-102972.rs:12:9 + --> $DIR/issue-102972.rs:14:9 | LL | let mut iter = v.iter(); | -------- move occurs because `iter` has type `std::slice::Iter<'_, i32>`, which does not implement the `Copy` trait @@ -19,10 +27,52 @@ LL | for _i in iter { LL | iter.next(); | ^^^^ value borrowed here after move | + = note: a for loop advances the iterator for you, the result is stored in `_i` note: `into_iter` takes ownership of the receiver `self`, which moves `iter` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL +help: if you want to call `next` on a iterator within the loop, consider using `while let` + | +LL | while let Some(_i) = iter.next() { + | ~~~~~~~~~~~~~~~ ~~~ +++++++ + +error[E0499]: cannot borrow `i` as mutable more than once at a time + --> $DIR/issue-102972.rs:22:9 + | +LL | for () in i.by_ref() { + | ---------- + | | + | first mutable borrow occurs here + | first borrow later used here +LL | i.next(); + | ^ second mutable borrow occurs here + | + = note: a for loop advances the iterator for you, the result is stored in its pattern +help: if you want to call `next` on a iterator within the loop, consider using `while let` + | +LL ~ let iter = i.by_ref(); +LL ~ while let Some(()) = iter.next() { +LL ~ iter.next(); + | + +error[E0382]: borrow of moved value: `iter` + --> $DIR/issue-102972.rs:30:9 + | +LL | let mut iter = v.iter(); + | -------- move occurs because `iter` has type `std::slice::Iter<'_, ()>`, which does not implement the `Copy` trait +LL | for () in iter { + | ---- `iter` moved due to this implicit call to `.into_iter()` +LL | iter.next(); + | ^^^^ value borrowed here after move + | + = note: a for loop advances the iterator for you, the result is stored in its pattern +note: `into_iter` takes ownership of the receiver `self`, which moves `iter` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL +help: if you want to call `next` on a iterator within the loop, consider using `while let` + | +LL | while let Some(()) = iter.next() { + | ~~~~~~~~~~~~~~~ ~~~ +++++++ -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0382, E0499. For more information about an error, try `rustc --explain E0382`. diff --git a/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.stderr b/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.stderr index 0ca5b9b9207..0d1eed67c55 100644 --- a/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.stderr +++ b/tests/ui/suggestions/suggest-trait-in-ufcs-in-hrtb.stderr @@ -2,7 +2,7 @@ error[E0223]: ambiguous associated type --> $DIR/suggest-trait-in-ufcs-in-hrtb.rs:5:38 | LL | impl<S> Foo for Bar<S> where for<'a> <&'a S>::Item: Foo {} - | ^^^^^^^^^^^^^ help: use the fully-qualified path: `<&'a S as IntoIterator>::Item` + | ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<&'a S as IntoIterator>::Item` error: aborting due to previous error diff --git a/tests/ui/traits/issue-59029-1.stderr b/tests/ui/traits/issue-59029-1.stderr index 51354bcc545..5c47eefcd6c 100644 --- a/tests/ui/traits/issue-59029-1.stderr +++ b/tests/ui/traits/issue-59029-1.stderr @@ -2,13 +2,13 @@ error[E0220]: associated type `Res` not found for `Self` --> $DIR/issue-59029-1.rs:5:52 | LL | trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>; - | ^^^ there is a similarly named associated type `Res` in the trait `Svc` + | ^^^ there is an associated type `Res` in the trait `Svc` error[E0220]: associated type `Res` not found for `Self` --> $DIR/issue-59029-1.rs:5:52 | LL | trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>; - | ^^^ there is a similarly named associated type `Res` in the trait `Svc` + | ^^^ there is an associated type `Res` in the trait `Svc` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr index f5381318925..af2e0763212 100644 --- a/tests/ui/traits/item-privacy.stderr +++ b/tests/ui/traits/item-privacy.stderr @@ -159,13 +159,13 @@ error[E0223]: ambiguous associated type --> $DIR/item-privacy.rs:116:12 | LL | let _: S::B; - | ^^^^ help: use the fully-qualified path: `<S as assoc_ty::B>::B` + | ^^^^ help: use fully-qualified syntax: `<S as assoc_ty::B>::B` error[E0223]: ambiguous associated type --> $DIR/item-privacy.rs:117:12 | LL | let _: S::C; - | ^^^^ help: use the fully-qualified path: `<S as assoc_ty::C>::C` + | ^^^^ help: use fully-qualified syntax: `<S as assoc_ty::C>::C` error[E0624]: associated type `A` is private --> $DIR/item-privacy.rs:119:12 diff --git a/tests/ui/traits/new-solver/deduce-closure-signature-after-normalization.rs b/tests/ui/traits/new-solver/deduce-closure-signature-after-normalization.rs new file mode 100644 index 00000000000..51f62bc2312 --- /dev/null +++ b/tests/ui/traits/new-solver/deduce-closure-signature-after-normalization.rs @@ -0,0 +1,10 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +trait Foo { + fn test() -> impl Fn(u32) -> u32 { + |x| x.count_ones() + } +} + +fn main() {} diff --git a/tests/ui/traits/new-solver/normalize-async-closure-in-trait.rs b/tests/ui/traits/new-solver/normalize-async-closure-in-trait.rs new file mode 100644 index 00000000000..cc16cc87169 --- /dev/null +++ b/tests/ui/traits/new-solver/normalize-async-closure-in-trait.rs @@ -0,0 +1,9 @@ +// compile-flags: -Ztrait-solver=next +// check-pass +// edition:2021 + +trait Foo { + async fn bar() {} +} + +fn main() {} diff --git a/tests/ui/traits/new-solver/specialization-unconstrained.stderr b/tests/ui/traits/new-solver/specialization-unconstrained.stderr index 9915da1a27a..ed4dafa1484 100644 --- a/tests/ui/traits/new-solver/specialization-unconstrained.stderr +++ b/tests/ui/traits/new-solver/specialization-unconstrained.stderr @@ -8,12 +8,6 @@ LL | #![feature(specialization)] = help: consider using `min_specialization` instead, which is more stable and complete = note: `#[warn(incomplete_features)]` on by default -error[E0282]: type annotations needed - --> $DIR/specialization-unconstrained.rs:14:22 - | -LL | default type Id = T; - | ^ cannot infer type for associated type `<T as Default>::Id` - error[E0284]: type annotations needed: cannot satisfy `<u32 as Default>::Id == ()` --> $DIR/specialization-unconstrained.rs:20:5 | @@ -26,6 +20,12 @@ note: required by a bound in `test` LL | fn test<T: Default<Id = U>, U>() {} | ^^^^^^ required by this bound in `test` +error[E0282]: type annotations needed + --> $DIR/specialization-unconstrained.rs:14:22 + | +LL | default type Id = T; + | ^ cannot infer type for associated type `<T as Default>::Id` + error: aborting due to 2 previous errors; 1 warning emitted Some errors have detailed explanations: E0282, E0284. diff --git a/tests/ui/type-alias-impl-trait/not_well_formed.fixed b/tests/ui/type-alias-impl-trait/not_well_formed.fixed new file mode 100644 index 00000000000..d98e83ff6dd --- /dev/null +++ b/tests/ui/type-alias-impl-trait/not_well_formed.fixed @@ -0,0 +1,19 @@ +// run-rustfix +#![feature(type_alias_impl_trait)] +#![allow(dead_code)] + +fn main() {} + +trait TraitWithAssoc { + type Assoc; +} + +type Foo<V: TraitWithAssoc> = impl Trait<V::Assoc>; //~ associated type `Assoc` not found for `V` + +trait Trait<U> {} + +impl<W> Trait<W> for () {} + +fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T> { + () +} diff --git a/tests/ui/type-alias-impl-trait/not_well_formed.rs b/tests/ui/type-alias-impl-trait/not_well_formed.rs index fbb7a4d58e4..18f173a693d 100644 --- a/tests/ui/type-alias-impl-trait/not_well_formed.rs +++ b/tests/ui/type-alias-impl-trait/not_well_formed.rs @@ -1,4 +1,6 @@ +// run-rustfix #![feature(type_alias_impl_trait)] +#![allow(dead_code)] fn main() {} diff --git a/tests/ui/type-alias-impl-trait/not_well_formed.stderr b/tests/ui/type-alias-impl-trait/not_well_formed.stderr index c36b95f47e8..b267e6a7544 100644 --- a/tests/ui/type-alias-impl-trait/not_well_formed.stderr +++ b/tests/ui/type-alias-impl-trait/not_well_formed.stderr @@ -1,8 +1,13 @@ error[E0220]: associated type `Assoc` not found for `V` - --> $DIR/not_well_formed.rs:9:29 + --> $DIR/not_well_formed.rs:11:29 | LL | type Foo<V> = impl Trait<V::Assoc>; - | ^^^^^ there is a similarly named associated type `Assoc` in the trait `TraitWithAssoc` + | ^^^^^ there is an associated type `Assoc` in the trait `TraitWithAssoc` + | +help: consider restricting type parameter `V` + | +LL | type Foo<V: TraitWithAssoc> = impl Trait<V::Assoc>; + | ++++++++++++++++ error: aborting due to previous error diff --git a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr new file mode 100644 index 00000000000..844103d77a8 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr @@ -0,0 +1,29 @@ +error: internal compiler error: no errors encountered even though `delay_span_bug` issued + +error: internal compiler error: {OpaqueTypeKey { def_id: DefId(get_rpit::{opaque#0}), args: [] }: OpaqueTypeDecl { hidden_type: OpaqueHiddenType { span: no-location (#0), ty: Alias(Opaque, AliasTy { args: [], def_id: DefId(Opaque::{opaque#0}) }) } }} + | + = + + +error: internal compiler error: error performing ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: ProvePredicate { predicate: Binder { value: ProjectionPredicate(AliasTy { args: [FnDef(DefId(get_rpit), []), ()], def_id: DefId(ops::function::FnOnce::Output) }, Term::Ty(Alias(Opaque, AliasTy { args: [], def_id: DefId(Opaque::{opaque#0}) }))), bound_vars: [] } } } + --> $DIR/rpit_tait_equality_in_canonical_query.rs:28:5 + | +LL | query(get_rpit); + | ^^^^^^^^^^^^^^^ + | + + --> $DIR/rpit_tait_equality_in_canonical_query.rs:28:5 + | +LL | query(get_rpit); + | ^^^^^^^^^^^^^^^ + + + + + + + +query stack during panic: +end of query stack +error: aborting due to 3 previous errors + diff --git a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs index eefe333da45..0f0002f7797 100644 --- a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs +++ b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs @@ -7,7 +7,14 @@ // revisions: current next //[next] compile-flags: -Ztrait-solver=next -// check-pass +//[next] check-pass + +//[current] known-bug: #108498 +//[current] failure-status: 101 +//[current] normalize-stderr-test: "DefId\(.*?\]::" -> "DefId(" +//[current] normalize-stderr-test: "(?m)note: .*$" -> "" +//[current] normalize-stderr-test: "(?m)^ *\d+: .*\n" -> "" +//[current] normalize-stderr-test: "(?m)^ *at .*\n" -> "" #![feature(type_alias_impl_trait)] diff --git a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query_2.rs b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query_2.rs new file mode 100644 index 00000000000..9d7e647dd94 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query_2.rs @@ -0,0 +1,18 @@ +// The canonical query `Projection(<get_rpit as FnOnce>::Output = Opaque)` +// is the *only* site that defines `Opaque` in MIR typeck. +// +// check-pass + +#![feature(type_alias_impl_trait)] + +type Opaque = impl Sized; + +fn get_rpit() -> impl Sized {} + +fn query(_: impl FnOnce() -> Opaque) {} + +fn test(_: Opaque) { + query(get_rpit); +} + +fn main() {} diff --git a/tests/ui/typeck/issue-107087.stderr b/tests/ui/typeck/issue-107087.stderr index 70f19320802..8921e3f7694 100644 --- a/tests/ui/typeck/issue-107087.stderr +++ b/tests/ui/typeck/issue-107087.stderr @@ -2,7 +2,7 @@ error[E0223]: ambiguous associated type --> $DIR/issue-107087.rs:16:5 | LL | A::B::<>::C - | ^^^^^^^^ help: use the fully-qualified path: `<A<_> as Foo>::B` + | ^^^^^^^^ help: use fully-qualified syntax: `<A<_> as Foo>::B` error: aborting due to previous error diff --git a/tests/ui/typeck/issue-110052.stderr b/tests/ui/typeck/issue-110052.stderr index 0c15c03a740..75374fa6121 100644 --- a/tests/ui/typeck/issue-110052.stderr +++ b/tests/ui/typeck/issue-110052.stderr @@ -2,7 +2,7 @@ error[E0223]: ambiguous associated type --> $DIR/issue-110052.rs:6:30 | LL | for<'iter> dyn Validator<<&'iter I>::Item>:, - | ^^^^^^^^^^^^^^^^ help: use the fully-qualified path: `<&'iter I as IntoIterator>::Item` + | ^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<&'iter I as IntoIterator>::Item` error: aborting due to previous error diff --git a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.rs b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.rs new file mode 100644 index 00000000000..157383fede1 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.rs @@ -0,0 +1,23 @@ +fn test() { + let x = match **x { //~ ERROR + Some(&a) if { panic!() } => {} + }; + let mut p = &x; + + { + let mut closure = expect_sig(|p, y| *p = y); + closure(&mut p, &y); //~ ERROR + //~^ ERROR + } + + deref(p); //~ ERROR +} + +fn expect_sig<F>(f: F) -> F +where + F: FnMut(&mut &i32, &i32), +{ + f +} + +fn main() {} diff --git a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr new file mode 100644 index 00000000000..1470c32d7de --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr @@ -0,0 +1,44 @@ +error[E0425]: cannot find value `x` in this scope + --> $DIR/unboxed-closures-type-mismatch-closure-from-another-scope.rs:2:21 + | +LL | let x = match **x { + | ^ not found in this scope + +error[E0425]: cannot find value `y` in this scope + --> $DIR/unboxed-closures-type-mismatch-closure-from-another-scope.rs:9:26 + | +LL | closure(&mut p, &y); + | ^ help: a local variable with a similar name exists: `p` + +error[E0308]: mismatched types + --> $DIR/unboxed-closures-type-mismatch-closure-from-another-scope.rs:9:17 + | +LL | closure(&mut p, &y); + | ------- ^^^^^^ expected `&mut &i32`, found `&mut &()` + | | + | arguments to this function are incorrect + | + = note: expected mutable reference `&mut &i32` + found mutable reference `&mut &()` +note: closure parameter defined here + --> $DIR/unboxed-closures-type-mismatch-closure-from-another-scope.rs:8:39 + | +LL | let mut closure = expect_sig(|p, y| *p = y); + | ^ + +error[E0425]: cannot find function `deref` in this scope + --> $DIR/unboxed-closures-type-mismatch-closure-from-another-scope.rs:13:5 + | +LL | deref(p); + | ^^^^^ not found in this scope + | +help: use the `.` operator to call the method `Deref::deref` on `&&()` + | +LL - deref(p); +LL + p.deref(); + | + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0308, E0425. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.rs b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.rs index 9f76849e5fb..0999f61b01a 100644 --- a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.rs +++ b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.rs @@ -1,7 +1,35 @@ use std::ops::FnMut; -pub fn main() { +fn main() { let mut f = |x: isize, y: isize| -> isize { x + y }; - let z = f(1_usize, 2); //~ ERROR mismatched types + let z = f(1_usize, 2); //~ ERROR mismatched types println!("{}", z); + let mut g = |x, y| { x + y }; + let y = g(1_i32, 2); + let z = g(1_usize, 2); //~ ERROR mismatched types + println!("{}", z); +} + +trait T { + fn bar(&self) { + let identity = |x| x; + identity(1u8); + identity(1u16); //~ ERROR mismatched types + let identity = |x| x; + identity(&1u8); + identity(&1u16); //~ ERROR mismatched types + } +} + +struct S; + +impl T for S { + fn bar(&self) { + let identity = |x| x; + identity(1u8); + identity(1u16); //~ ERROR mismatched types + let identity = |x| x; + identity(&1u8); + identity(&1u16); //~ ERROR mismatched types + } } diff --git a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr index 455f83f5721..327df50e645 100644 --- a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr +++ b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch.stderr @@ -16,6 +16,127 @@ help: change the type of the numeric literal from `usize` to `isize` LL | let z = f(1_isize, 2); | ~~~~~ -error: aborting due to previous error +error[E0308]: mismatched types + --> $DIR/unboxed-closures-type-mismatch.rs:9:15 + | +LL | let z = g(1_usize, 2); + | - ^^^^^^^ expected `i32`, found `usize` + | | + | arguments to this function are incorrect + | +note: expected because the closure was earlier called with an argument of type `i32` + --> $DIR/unboxed-closures-type-mismatch.rs:8:15 + | +LL | let y = g(1_i32, 2); + | - ^^^^^ expected because this argument is of type `i32` + | | + | in this closure call +note: closure parameter defined here + --> $DIR/unboxed-closures-type-mismatch.rs:7:18 + | +LL | let mut g = |x, y| { x + y }; + | ^ +help: change the type of the numeric literal from `usize` to `i32` + | +LL | let z = g(1_i32, 2); + | ~~~ + +error[E0308]: mismatched types + --> $DIR/unboxed-closures-type-mismatch.rs:17:18 + | +LL | identity(1u16); + | -------- ^^^^ expected `u8`, found `u16` + | | + | arguments to this function are incorrect + | +note: expected because the closure was earlier called with an argument of type `u8` + --> $DIR/unboxed-closures-type-mismatch.rs:16:18 + | +LL | identity(1u8); + | -------- ^^^ expected because this argument is of type `u8` + | | + | in this closure call +note: closure parameter defined here + --> $DIR/unboxed-closures-type-mismatch.rs:15:25 + | +LL | let identity = |x| x; + | ^ +help: change the type of the numeric literal from `u16` to `u8` + | +LL | identity(1u8); + | ~~ + +error[E0308]: mismatched types + --> $DIR/unboxed-closures-type-mismatch.rs:20:18 + | +LL | identity(&1u16); + | -------- ^^^^^ expected `&u8`, found `&u16` + | | + | arguments to this function are incorrect + | + = note: expected reference `&u8` + found reference `&u16` +note: expected because the closure was earlier called with an argument of type `&u8` + --> $DIR/unboxed-closures-type-mismatch.rs:19:18 + | +LL | identity(&1u8); + | -------- ^^^^ expected because this argument is of type `&u8` + | | + | in this closure call +note: closure parameter defined here + --> $DIR/unboxed-closures-type-mismatch.rs:18:25 + | +LL | let identity = |x| x; + | ^ + +error[E0308]: mismatched types + --> $DIR/unboxed-closures-type-mismatch.rs:30:18 + | +LL | identity(1u16); + | -------- ^^^^ expected `u8`, found `u16` + | | + | arguments to this function are incorrect + | +note: expected because the closure was earlier called with an argument of type `u8` + --> $DIR/unboxed-closures-type-mismatch.rs:29:18 + | +LL | identity(1u8); + | -------- ^^^ expected because this argument is of type `u8` + | | + | in this closure call +note: closure parameter defined here + --> $DIR/unboxed-closures-type-mismatch.rs:28:25 + | +LL | let identity = |x| x; + | ^ +help: change the type of the numeric literal from `u16` to `u8` + | +LL | identity(1u8); + | ~~ + +error[E0308]: mismatched types + --> $DIR/unboxed-closures-type-mismatch.rs:33:18 + | +LL | identity(&1u16); + | -------- ^^^^^ expected `&u8`, found `&u16` + | | + | arguments to this function are incorrect + | + = note: expected reference `&u8` + found reference `&u16` +note: expected because the closure was earlier called with an argument of type `&u8` + --> $DIR/unboxed-closures-type-mismatch.rs:32:18 + | +LL | identity(&1u8); + | -------- ^^^^ expected because this argument is of type `&u8` + | | + | in this closure call +note: closure parameter defined here + --> $DIR/unboxed-closures-type-mismatch.rs:31:25 + | +LL | let identity = |x| x; + | ^ + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/triagebot.toml b/triagebot.toml index 4b051db0d73..fbdc28787ff 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -23,6 +23,18 @@ allow-unauthenticated = [ "needs-triage", ] +[review-submitted] +# This label is added when a "request changes" review is submitted. +reviewed_label = "S-waiting-on-author" +# These labels are removed when a "request changes" review is submitted. +review_labels = ["S-waiting-on-review"] + +[review-requested] +# Those labels are removed when PR author requests a review from an assignee +remove_labels = ["S-waiting-on-author"] +# Those labels are added when PR author requests a review from an assignee +add_labels = ["S-waiting-on-review"] + [glacier] [ping.icebreakers-llvm] @@ -402,6 +414,10 @@ message_on_add = """\ Issue #{number} "{title}" has been added. """ +[no-merges] +exclude_titles = ["Rollup of", "subtree update"] +labels = ["has-merge-commits", "S-waiting-on-author"] + [github-releases] format = "rustc" project-name = "Rust" @@ -540,7 +556,7 @@ cc = ["@davidtwco", "@compiler-errors", "@JohnTitor", "@TaKO8Ki"] [mentions."compiler/rustc_smir"] message = "This PR changes Stable MIR" -cc = ["@oli-obk", "@celinval", "@spastorino"] +cc = ["@oli-obk", "@celinval", "@spastorino", "@ouz-a"] [mentions."compiler/stable_mir"] message = "This PR changes Stable MIR" @@ -722,7 +738,7 @@ style-team = [ "/compiler/rustc_traits" = ["compiler", "types"] "/compiler/rustc_type_ir" = ["compiler", "types"] "/library/alloc" = ["libs"] -"/library/core" = ["libs", "@scottmcm"] +"/library/core" = ["libs"] "/library/panic_abort" = ["libs"] "/library/panic_unwind" = ["libs"] "/library/proc_macro" = ["@petrochenkov"] diff --git a/x b/x index ef3eb8b04b4..426b58d0d4e 100755 --- a/x +++ b/x @@ -11,10 +11,13 @@ set -eu sh -n "$0" realpath() { - if [ -d "$1" ]; then - CDPATH='' command cd "$1" && pwd -P + local path="$1" + if [ -L "$path" ]; then + readlink -f "$path" + elif [ -d "$path" ]; then + (cd -P "$path" && pwd) else - echo "$(realpath "$(dirname "$1")")/$(basename "$1")" + echo "$(realpath "$(dirname "$path")")/$(basename "$path")" fi } |
