diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3680136d89f..618a26958ee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,7 +67,7 @@ jobs: - name: disable git crlf conversion run: git config --global core.autocrlf false - name: checkout the source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 2 - name: configure the PR in which the error message will be posted @@ -393,7 +393,7 @@ jobs: - name: dist-x86_64-msvc env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler" - SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist python x.py dist bootstrap --include-default-paths + SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist windows-ci -- python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 os: windows-2019-8core-32gb - name: dist-i686-msvc @@ -435,7 +435,7 @@ jobs: - name: disable git crlf conversion run: git config --global core.autocrlf false - name: checkout the source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 2 - name: configure the PR in which the error message will be posted @@ -555,7 +555,7 @@ jobs: - name: disable git crlf conversion run: git config --global core.autocrlf false - name: checkout the source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 2 - name: configure the PR in which the error message will be posted @@ -662,7 +662,7 @@ jobs: if: "github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'rust-lang-ci/rust'" steps: - name: checkout the source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 2 - name: publish toolstate diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml index 26d2ba636f3..97ed891c491 100644 --- a/.github/workflows/dependencies.yml +++ b/.github/workflows/dependencies.yml @@ -50,7 +50,7 @@ jobs: runs-on: ubuntu-latest steps: - name: checkout the source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: recursive - name: install the bootstrap toolchain @@ -87,7 +87,7 @@ jobs: pull-requests: write steps: - name: checkout the source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: download Cargo.lock from update job uses: actions/download-artifact@v3 diff --git a/.gitignore b/.gitignore index 4c8d1a03764..485968d9c56 100644 --- a/.gitignore +++ b/.gitignore @@ -58,7 +58,6 @@ build/ \#* \#*\# .#* -rustc-ice-*.txt ## Tags tags diff --git a/.mailmap b/.mailmap index eb82cf4de8d..21e1adb43cf 100644 --- a/.mailmap +++ b/.mailmap @@ -328,7 +328,8 @@ Kyle J Strand Kyle J Strand Kyle J Strand Kyle J Strand -Laurențiu Nicola +Laurențiu Nicola Laurentiu Nicola +Laurențiu Nicola lcnr Lee Jeffery Lee Jeffery Lee Wondong @@ -549,6 +550,8 @@ Timothy Maloney Tomas Koutsky Torsten Weber Torsten Weber +Trevor Gross +Trevor Gross Trevor Spiteri Tshepang Mbambo Ty Overby diff --git a/Cargo.lock b/Cargo.lock index d0dde610500..a93078829e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -859,14 +859,38 @@ dependencies = [ "winapi", ] +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + [[package]] name = "darling" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.3", + "darling_macro 0.20.3", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", ] [[package]] @@ -883,13 +907,24 @@ dependencies = [ "syn 2.0.29", ] +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core 0.14.4", + "quote", + "syn 1.0.109", +] + [[package]] name = "darling_macro" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ - "darling_core", + "darling_core 0.20.3", "quote", "syn 2.0.29", ] @@ -920,6 +955,37 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_builder" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +dependencies = [ + "darling 0.14.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -939,7 +1005,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e8ef033054e131169b8f0f9a7af8f5533a9436fadf3c500ed547f730f07090d" dependencies = [ - "darling", + "darling 0.20.3", "proc-macro2", "quote", "syn 2.0.29", @@ -2594,6 +2660,8 @@ dependencies = [ "anyhow", "build_helper", "camino", + "clap", + "derive_builder", "env_logger 0.10.0", "fs_extra", "glob", diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 19a2b3017bc..db008ea139d 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -99,6 +99,22 @@ impl Attribute { } } + pub fn path_matches(&self, name: &[Symbol]) -> bool { + match &self.kind { + AttrKind::Normal(normal) => { + normal.item.path.segments.len() == name.len() + && normal + .item + .path + .segments + .iter() + .zip(name) + .all(|(s, n)| s.args.is_none() && s.ident.name == *n) + } + AttrKind::DocComment(..) => false, + } + } + pub fn is_word(&self) -> bool { if let AttrKind::Normal(normal) = &self.kind { matches!(normal.item.args, AttrArgs::Empty) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 337af89b21f..b40e89e471d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -442,8 +442,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { span: Span, counter: usize, ) -> RegionNameHighlight { - let mut highlight = RegionHighlightMode::new(self.infcx.tcx); - highlight.highlighting_region_vid(needle_fr, counter); + let mut highlight = RegionHighlightMode::default(); + highlight.highlighting_region_vid(self.infcx.tcx, needle_fr, counter); let type_name = self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name; @@ -804,8 +804,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { return None; } - let mut highlight = RegionHighlightMode::new(tcx); - highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); + let mut highlight = RegionHighlightMode::default(); + highlight.highlighting_region_vid(tcx, fr, *self.next_region_name.try_borrow().unwrap()); let type_name = self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name; diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 8d8db4c13fa..207ae8ad844 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -137,6 +137,8 @@ builtin_macros_format_positional_after_named = positional arguments cannot follo .label = positional arguments must be before named arguments .named_args = named argument +builtin_macros_format_remove_raw_ident = remove the `r#` + builtin_macros_format_requires_string = requires at least a format string argument builtin_macros_format_string_invalid = invalid format string: {$desc} @@ -165,6 +167,8 @@ builtin_macros_format_unused_arg = {$named -> builtin_macros_format_unused_args = multiple unused formatting arguments .label = multiple missing formatting specifiers +builtin_macros_format_use_positional = consider using a positional formatting argument instead + builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!` builtin_macros_invalid_crate_attribute = invalid crate attribute @@ -205,8 +209,6 @@ builtin_macros_requires_cfg_pattern = builtin_macros_should_panic = functions using `#[should_panic]` must return `()` -builtin_macros_sugg = consider using a positional formatting argument instead - builtin_macros_test_arg_non_lifetime = functions used as tests can not have any non-lifetime generic parameters builtin_macros_test_args = functions used as tests can not have any arguments diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index 745358fde4b..a000e4895d1 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -18,6 +18,20 @@ pub fn expand_deriving_eq( is_const: bool, ) { let span = cx.with_def_site_ctxt(span); + + let structural_trait_def = TraitDef { + span, + path: path_std!(marker::StructuralEq), + skip_path_as_bound: true, // crucial! + needs_copy_as_bound_if_packed: false, + additional_bounds: Vec::new(), + supports_unions: true, + methods: Vec::new(), + associated_types: Vec::new(), + is_const: false, + }; + structural_trait_def.expand(cx, mitem, item, push); + let trait_def = TraitDef { span, path: path_std!(cmp::Eq), @@ -44,9 +58,6 @@ pub fn expand_deriving_eq( associated_types: Vec::new(), is_const, }; - - super::inject_impl_of_structural_trait(cx, span, item, path_std!(marker::StructuralEq), push); - trait_def.expand_ext(cx, mitem, item, push, true) } diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index a71ecc5db7d..a170468b413 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -72,13 +72,20 @@ pub fn expand_deriving_partial_eq( BlockOrExpr::new_expr(expr) } - super::inject_impl_of_structural_trait( - cx, + let structural_trait_def = TraitDef { span, - item, - path_std!(marker::StructuralPartialEq), - push, - ); + path: path_std!(marker::StructuralPartialEq), + skip_path_as_bound: true, // crucial! + needs_copy_as_bound_if_packed: false, + additional_bounds: Vec::new(), + // We really don't support unions, but that's already checked by the impl generated below; + // a second check here would lead to redundant error messages. + supports_unions: true, + methods: Vec::new(), + associated_types: Vec::new(), + is_const: false, + }; + structural_trait_def.expand(cx, mitem, item, push); // No need to generate `ne`, the default suffices, and not generating it is // faster. diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 6597ee3cf1b..7252658d460 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -88,7 +88,7 @@ //! //! When generating the `expr` for the `A` impl, the `SubstructureFields` is //! -//! ```{.text} +//! ```text //! Struct(vec![FieldInfo { //! span: //! name: Some(), @@ -99,7 +99,7 @@ //! //! For the `B` impl, called with `B(a)` and `B(b)`, //! -//! ```{.text} +//! ```text //! Struct(vec![FieldInfo { //! span: , //! name: None, @@ -113,7 +113,7 @@ //! When generating the `expr` for a call with `self == C0(a)` and `other //! == C0(b)`, the SubstructureFields is //! -//! ```{.text} +//! ```text //! EnumMatching(0, , //! vec![FieldInfo { //! span: @@ -125,7 +125,7 @@ //! //! For `C1 {x}` and `C1 {x}`, //! -//! ```{.text} +//! ```text //! EnumMatching(1, , //! vec![FieldInfo { //! span: @@ -137,7 +137,7 @@ //! //! For the tags, //! -//! ```{.text} +//! ```text //! EnumTag( //! &[, ], ) //! ``` @@ -149,7 +149,7 @@ //! //! A static method on the types above would result in, //! -//! ```{.text} +//! ```text //! StaticStruct(, Named(vec![(, )])) //! //! StaticStruct(, Unnamed(vec![])) @@ -711,7 +711,9 @@ impl<'a> TraitDef<'a> { .collect(); // Require the current trait. - bounds.push(cx.trait_bound(trait_path.clone(), self.is_const)); + if !self.skip_path_as_bound { + bounds.push(cx.trait_bound(trait_path.clone(), self.is_const)); + } // Add a `Copy` bound if required. if is_packed && self.needs_copy_as_bound_if_packed { @@ -722,15 +724,17 @@ impl<'a> TraitDef<'a> { )); } - let predicate = ast::WhereBoundPredicate { - span: self.span, - bound_generic_params: field_ty_param.bound_generic_params, - bounded_ty: field_ty_param.ty, - bounds, - }; + if !bounds.is_empty() { + let predicate = ast::WhereBoundPredicate { + span: self.span, + bound_generic_params: field_ty_param.bound_generic_params, + bounded_ty: field_ty_param.ty, + bounds, + }; - let predicate = ast::WherePredicate::BoundPredicate(predicate); - where_clause.predicates.push(predicate); + let predicate = ast::WherePredicate::BoundPredicate(predicate); + where_clause.predicates.push(predicate); + } } } } diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index d34336e7679..a6f3252e7be 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -2,9 +2,9 @@ use rustc_ast as ast; use rustc_ast::ptr::P; -use rustc_ast::{GenericArg, Impl, ItemKind, MetaItem}; +use rustc_ast::{GenericArg, MetaItem}; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier}; -use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use thin_vec::{thin_vec, ThinVec}; @@ -116,100 +116,6 @@ fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P { })) } -// Injects `impl<...> Structural for ItemType<...> { }`. In particular, -// does *not* add `where T: Structural` for parameters `T` in `...`. -// (That's the main reason we cannot use TraitDef here.) -fn inject_impl_of_structural_trait( - cx: &mut ExtCtxt<'_>, - span: Span, - item: &Annotatable, - structural_path: generic::ty::Path, - push: &mut dyn FnMut(Annotatable), -) { - let Annotatable::Item(item) = item else { - unreachable!(); - }; - - let generics = match &item.kind { - ItemKind::Struct(_, generics) | ItemKind::Enum(_, generics) => generics, - // Do not inject `impl Structural for Union`. (`PartialEq` does not - // support unions, so we will see error downstream.) - ItemKind::Union(..) => return, - _ => unreachable!(), - }; - - // Create generics param list for where clauses and impl headers - let mut generics = generics.clone(); - - let ctxt = span.ctxt(); - - // Create the type of `self`. - // - // in addition, remove defaults from generic params (impls cannot have them). - let self_params: Vec<_> = generics - .params - .iter_mut() - .map(|param| match &mut param.kind { - ast::GenericParamKind::Lifetime => ast::GenericArg::Lifetime( - cx.lifetime(param.ident.span.with_ctxt(ctxt), param.ident), - ), - ast::GenericParamKind::Type { default } => { - *default = None; - ast::GenericArg::Type(cx.ty_ident(param.ident.span.with_ctxt(ctxt), param.ident)) - } - ast::GenericParamKind::Const { ty: _, kw_span: _, default } => { - *default = None; - ast::GenericArg::Const( - cx.const_ident(param.ident.span.with_ctxt(ctxt), param.ident), - ) - } - }) - .collect(); - - let type_ident = item.ident; - - let trait_ref = cx.trait_ref(structural_path.to_path(cx, span, type_ident, &generics)); - let self_type = cx.ty_path(cx.path_all(span, false, vec![type_ident], self_params)); - - // It would be nice to also encode constraint `where Self: Eq` (by adding it - // onto `generics` cloned above). Unfortunately, that strategy runs afoul of - // rust-lang/rust#48214. So we perform that additional check in the compiler - // itself, instead of encoding it here. - - // Keep the lint and stability attributes of the original item, to control - // how the generated implementation is linted. - let mut attrs = ast::AttrVec::new(); - attrs.extend( - item.attrs - .iter() - .filter(|a| { - [sym::allow, sym::warn, sym::deny, sym::forbid, sym::stable, sym::unstable] - .contains(&a.name_or_empty()) - }) - .cloned(), - ); - // Mark as `automatically_derived` to avoid some silly lints. - attrs.push(cx.attr_word(sym::automatically_derived, span)); - - let newitem = cx.item( - span, - Ident::empty(), - attrs, - ItemKind::Impl(Box::new(Impl { - unsafety: ast::Unsafe::No, - polarity: ast::ImplPolarity::Positive, - defaultness: ast::Defaultness::Final, - constness: ast::Const::No, - generics, - of_trait: Some(trait_ref), - self_ty: self_type, - items: ThinVec::new(), - })), - ); - - push(Annotatable::Item(newitem)); -} - fn assert_ty_bounds( cx: &mut ExtCtxt<'_>, stmts: &mut ThinVec, diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index fbf0395bb05..1238773d58b 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -539,18 +539,29 @@ pub(crate) struct InvalidFormatStringLabel { } #[derive(Subdiagnostic)] -#[multipart_suggestion( - builtin_macros_sugg, - style = "verbose", - applicability = "machine-applicable" -)] -pub(crate) struct InvalidFormatStringSuggestion { - #[suggestion_part(code = "{len}")] - pub(crate) captured: Span, - pub(crate) len: String, - #[suggestion_part(code = ", {arg}")] - pub(crate) span: Span, - pub(crate) arg: String, +pub(crate) enum InvalidFormatStringSuggestion { + #[multipart_suggestion( + builtin_macros_format_use_positional, + style = "verbose", + applicability = "machine-applicable" + )] + UsePositional { + #[suggestion_part(code = "{len}")] + captured: Span, + len: String, + #[suggestion_part(code = ", {arg}")] + span: Span, + arg: String, + }, + #[suggestion( + builtin_macros_format_remove_raw_ident, + code = "", + applicability = "machine-applicable" + )] + RemoveRawIdent { + #[primary_span] + span: Span, + }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index ede95dbf897..8397b5e4221 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -260,20 +260,29 @@ fn make_format_args( 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 err.should_be_replaced_with_positional_argument { - let captured_arg_span = - fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end)); - if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) { - let span = match args.unnamed_args().last() { - Some(arg) => arg.expr.span, - None => fmt_span, - }; - e.sugg_ = Some(errors::InvalidFormatStringSuggestion { - captured: captured_arg_span, - len: args.unnamed_args().len().to_string(), - span: span.shrink_to_hi(), - arg, - }); + match err.suggestion { + parse::Suggestion::None => {} + parse::Suggestion::UsePositional => { + let captured_arg_span = + fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end)); + if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) { + let span = match args.unnamed_args().last() { + Some(arg) => arg.expr.span, + None => fmt_span, + }; + e.sugg_ = Some(errors::InvalidFormatStringSuggestion::UsePositional { + captured: captured_arg_span, + len: args.unnamed_args().len().to_string(), + span: span.shrink_to_hi(), + arg, + }); + } + } + parse::Suggestion::RemoveRawIdent(span) => { + if is_source_literal { + let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end)); + e.sugg_ = Some(errors::InvalidFormatStringSuggestion::RemoveRawIdent { span }) + } } } ecx.emit_err(e); diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index d847e524f8c..0d16da48067 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs @@ -100,11 +100,11 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { } _ => unreachable!("{:?}", self.layout.abi), }, - PassMode::Cast(ref cast, pad_i32) => { + PassMode::Cast { ref cast, pad_i32 } => { assert!(!pad_i32, "padding support not yet implemented"); cast_target_to_abi_params(cast) } - PassMode::Indirect { attrs, extra_attrs: None, on_stack } => { + PassMode::Indirect { attrs, meta_attrs: None, on_stack } => { if on_stack { // Abi requires aligning struct size to pointer size let size = self.layout.size.align_to(tcx.data_layout.pointer_align.abi); @@ -117,11 +117,11 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { smallvec![apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs)] } } - PassMode::Indirect { attrs, extra_attrs: Some(extra_attrs), on_stack } => { + PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => { assert!(!on_stack); smallvec![ apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs), - apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), extra_attrs), + apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), meta_attrs), ] } } @@ -148,14 +148,14 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { } _ => unreachable!("{:?}", self.layout.abi), }, - PassMode::Cast(ref cast, _) => { + PassMode::Cast { ref cast, .. } => { (None, cast_target_to_abi_params(cast).into_iter().collect()) } - PassMode::Indirect { attrs: _, extra_attrs: None, on_stack } => { + PassMode::Indirect { attrs: _, meta_attrs: None, on_stack } => { assert!(!on_stack); (Some(AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructReturn)), vec![]) } - PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { + PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { unreachable!("unsized return value") } } @@ -229,7 +229,7 @@ pub(super) fn adjust_arg_for_abi<'tcx>( let (a, b) = arg.load_scalar_pair(fx); smallvec![a, b] } - PassMode::Cast(ref cast, _) => to_casted_value(fx, arg, cast), + PassMode::Cast { ref cast, .. } => to_casted_value(fx, arg, cast), PassMode::Indirect { .. } => { if is_owned { match arg.force_stack(fx) { @@ -287,14 +287,14 @@ pub(super) fn cvalue_for_param<'tcx>( assert_eq!(block_params.len(), 2, "{:?}", block_params); Some(CValue::by_val_pair(block_params[0], block_params[1], arg_abi.layout)) } - PassMode::Cast(ref cast, _) => { + PassMode::Cast { ref cast, .. } => { Some(from_casted_value(fx, &block_params, arg_abi.layout, cast)) } - PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { + PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => { assert_eq!(block_params.len(), 1, "{:?}", block_params); Some(CValue::by_ref(Pointer::new(block_params[0]), arg_abi.layout)) } - PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { + PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { assert_eq!(block_params.len(), 2, "{:?}", block_params); Some(CValue::by_ref_unsized( Pointer::new(block_params[0]), diff --git a/compiler/rustc_codegen_cranelift/src/abi/returning.rs b/compiler/rustc_codegen_cranelift/src/abi/returning.rs index 14e54d5ee38..646fb4a3cdc 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/returning.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/returning.rs @@ -13,7 +13,7 @@ pub(super) fn codegen_return_param<'tcx>( block_params_iter: &mut impl Iterator, ) -> CPlace<'tcx> { let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode { - PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(..) => { + PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast { .. } => { let is_ssa = ssa_analyzed[RETURN_PLACE].is_ssa(fx, fx.fn_abi.as_ref().unwrap().ret.layout.ty); ( @@ -26,7 +26,7 @@ pub(super) fn codegen_return_param<'tcx>( smallvec![], ) } - PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { + PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => { let ret_param = block_params_iter.next().unwrap(); assert_eq!(fx.bcx.func.dfg.value_type(ret_param), fx.pointer_type); ( @@ -34,7 +34,7 @@ pub(super) fn codegen_return_param<'tcx>( smallvec![ret_param], ) } - PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { + PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { unreachable!("unsized return value") } }; @@ -62,7 +62,7 @@ pub(super) fn codegen_with_call_return_arg<'tcx>( ) { let (ret_temp_place, return_ptr) = match ret_arg_abi.mode { PassMode::Ignore => (None, None), - PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { + PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => { if let Some(ret_ptr) = ret_place.try_to_ptr() { // This is an optimization to prevent unnecessary copies of the return value when // the return place is already a memory place as opposed to a register. @@ -73,10 +73,10 @@ pub(super) fn codegen_with_call_return_arg<'tcx>( (Some(place), Some(place.to_ptr().get_addr(fx))) } } - PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { + PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { unreachable!("unsized return value") } - PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(..) => (None, None), + PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast { .. } => (None, None), }; let call_inst = f(fx, return_ptr); @@ -93,21 +93,21 @@ pub(super) fn codegen_with_call_return_arg<'tcx>( ret_place .write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout)); } - PassMode::Cast(ref cast, _) => { + PassMode::Cast { ref cast, .. } => { let results = fx.bcx.inst_results(call_inst).iter().copied().collect::>(); let result = super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast); ret_place.write_cvalue(fx, result); } - PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { + PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => { if let Some(ret_temp_place) = ret_temp_place { // If ret_temp_place is None, it is not necessary to copy the return value. let ret_temp_value = ret_temp_place.to_cvalue(fx); ret_place.write_cvalue(fx, ret_temp_value); } } - PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { + PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { unreachable!("unsized return value") } } @@ -116,10 +116,10 @@ pub(super) fn codegen_with_call_return_arg<'tcx>( /// Codegen a return instruction with the right return value(s) if any. pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) { match fx.fn_abi.as_ref().unwrap().ret.mode { - PassMode::Ignore | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { + PassMode::Ignore | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => { fx.bcx.ins().return_(&[]); } - PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { + PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { unreachable!("unsized return value") } PassMode::Direct(_) => { @@ -132,7 +132,7 @@ pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, '_>) { let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx); fx.bcx.ins().return_(&[ret_val_a, ret_val_b]); } - PassMode::Cast(ref cast, _) => { + PassMode::Cast { ref cast, .. } => { let place = fx.get_local_place(RETURN_PLACE); let ret_val = place.to_cvalue(fx); let ret_vals = super::pass_mode::to_casted_value(fx, ret_val, cast); diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 54f82dcc8ae..9b5a6b89191 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -250,7 +250,10 @@ pub(crate) fn verify_func( } fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { - if !crate::constant::check_constants(fx) { + if let Err(err) = + fx.mir.post_mono_checks(fx.tcx, ty::ParamEnv::reveal_all(), |c| Ok(fx.monomorphize(c))) + { + err.emit_err(fx.tcx); fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]); fx.bcx.switch_to_block(fx.block_map[START_BLOCK]); // compilation should have been aborted diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 8c67760a0b9..0d9bd3cf240 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -2,9 +2,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir::interpret::{ - read_target_uint, AllocId, ConstValue, ErrorHandled, GlobalAlloc, Scalar, -}; +use rustc_middle::mir::interpret::{read_target_uint, AllocId, ConstValue, GlobalAlloc, Scalar}; use cranelift_module::*; @@ -33,16 +31,6 @@ impl ConstantCx { } } -pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool { - let mut all_constants_ok = true; - for constant in &fx.mir.required_consts { - if eval_mir_constant(fx, constant).is_none() { - all_constants_ok = false; - } - } - all_constants_ok -} - pub(crate) fn codegen_static(tcx: TyCtxt<'_>, module: &mut dyn Module, def_id: DefId) { let mut constants_cx = ConstantCx::new(); constants_cx.todo.push(TodoItem::Static(def_id)); @@ -76,30 +64,20 @@ pub(crate) fn codegen_tls_ref<'tcx>( pub(crate) fn eval_mir_constant<'tcx>( fx: &FunctionCx<'_, '_, 'tcx>, constant: &Constant<'tcx>, -) -> Option<(ConstValue<'tcx>, Ty<'tcx>)> { +) -> (ConstValue<'tcx>, Ty<'tcx>) { let cv = fx.monomorphize(constant.literal); + // This cannot fail because we checked all required_consts in advance. let val = cv .eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span)) - .map_err(|err| match err { - ErrorHandled::Reported(_) => { - fx.tcx.sess.span_err(constant.span, "erroneous constant encountered"); - } - ErrorHandled::TooGeneric => { - span_bug!(constant.span, "codegen encountered polymorphic constant: {:?}", err); - } - }) - .ok(); - val.map(|val| (val, cv.ty())) + .expect("erroneous constant not captured by required_consts"); + (val, cv.ty()) } pub(crate) fn codegen_constant_operand<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, constant: &Constant<'tcx>, ) -> CValue<'tcx> { - let (const_val, ty) = eval_mir_constant(fx, constant).unwrap_or_else(|| { - span_bug!(constant.span, "erroneous constant not captured by required_consts") - }); - + let (const_val, ty) = eval_mir_constant(fx, constant); codegen_const_value(fx, const_val, ty) } @@ -459,7 +437,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( operand: &Operand<'tcx>, ) -> Option> { match operand { - Operand::Constant(const_) => Some(eval_mir_constant(fx, const_).unwrap().0), + Operand::Constant(const_) => Some(eval_mir_constant(fx, const_).0), // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored // inside a temporary before being passed to the intrinsic requiring the const argument. // This code tries to find a single constant defining definition of the referenced local. diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index 518e3da07a4..eba90949b5e 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -242,8 +242,7 @@ pub(crate) fn codegen_inline_asm<'tcx>( } } InlineAsmOperand::Const { ref value } => { - let (const_value, ty) = crate::constant::eval_mir_constant(fx, value) - .unwrap_or_else(|| span_bug!(span, "asm const cannot be resolved")); + let (const_value, ty) = crate::constant::eval_mir_constant(fx, value); let value = rustc_codegen_ssa::common::asm_const_to_str( fx.tcx, span, diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 377dc753f68..a49530ebb4c 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -113,7 +113,7 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { match self.ret.mode { PassMode::Ignore => cx.type_void(), PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx), - PassMode::Cast(ref cast, _) => cast.gcc_type(cx), + PassMode::Cast { ref cast, .. } => cast.gcc_type(cx), PassMode::Indirect { .. } => { argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx))); cx.type_void() @@ -129,21 +129,21 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 1)); continue; } - PassMode::Indirect { extra_attrs: Some(_), .. } => { + PassMode::Indirect { meta_attrs: Some(_), .. } => { unimplemented!(); } - PassMode::Cast(ref cast, pad_i32) => { + PassMode::Cast { ref cast, pad_i32 } => { // add padding if pad_i32 { argument_tys.push(Reg::i32().gcc_type(cx)); } cast.gcc_type(cx) } - PassMode::Indirect { extra_attrs: None, on_stack: true, .. } => { + PassMode::Indirect { meta_attrs: None, on_stack: true, .. } => { on_stack_param_indices.insert(argument_tys.len()); arg.memory_ty(cx) }, - PassMode::Indirect { extra_attrs: None, on_stack: false, .. } => cx.type_ptr_to(arg.memory_ty(cx)), + PassMode::Indirect { meta_attrs: None, on_stack: false, .. } => cx.type_ptr_to(arg.memory_ty(cx)), }; argument_tys.push(arg_ty); } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index f8c32c6dbbb..68a087a1d7f 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -144,7 +144,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { sym::volatile_load | sym::unaligned_volatile_load => { let tp_ty = fn_args.type_at(0); let mut ptr = args[0].immediate(); - if let PassMode::Cast(ty, _) = &fn_abi.ret.mode { + if let PassMode::Cast { cast: ty, .. } = &fn_abi.ret.mode { ptr = self.pointercast(ptr, self.type_ptr_to(ty.gcc_type(self))); } let load = self.volatile_load(ptr.get_type(), ptr); @@ -353,7 +353,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { }; if !fn_abi.ret.is_ignore() { - if let PassMode::Cast(ty, _) = &fn_abi.ret.mode { + if let PassMode::Cast { cast: ty, .. } = &fn_abi.ret.mode { let ptr_llty = self.type_ptr_to(ty.gcc_type(self)); let ptr = self.pointercast(result.llval, ptr_llty); self.store(llval, ptr, result.align); @@ -449,7 +449,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { else if self.is_unsized_indirect() { bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); } - else if let PassMode::Cast(ref cast, _) = self.mode { + else if let PassMode::Cast { ref cast, .. } = self.mode { // FIXME(eddyb): Figure out when the simpler Store is safe, clang // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. let can_store_through_cast_ptr = false; @@ -511,10 +511,10 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { PassMode::Pair(..) => { OperandValue::Pair(next(), next()).store(bx, dst); }, - PassMode::Indirect { extra_attrs: Some(_), .. } => { + PassMode::Indirect { meta_attrs: Some(_), .. } => { OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst); }, - PassMode::Direct(_) | PassMode::Indirect { extra_attrs: None, .. } | PassMode::Cast(..) => { + PassMode::Direct(_) | PassMode::Indirect { meta_attrs: None, .. } | PassMode::Cast { .. } => { let next_arg = next(); self.store(bx, next_arg, dst); }, diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 64587f98b8a..9e834b83df4 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -211,7 +211,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst) } else if self.is_unsized_indirect() { bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); - } else if let PassMode::Cast(cast, _) = &self.mode { + } else if let PassMode::Cast { cast, pad_i32: _ } = &self.mode { // FIXME(eddyb): Figure out when the simpler Store is safe, clang // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. let can_store_through_cast_ptr = false; @@ -274,12 +274,12 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { PassMode::Pair(..) => { OperandValue::Pair(next(), next()).store(bx, dst); } - PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { + PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst); } PassMode::Direct(_) - | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } - | PassMode::Cast(..) => { + | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } + | PassMode::Cast { .. } => { let next_arg = next(); self.store(bx, next_arg, dst); } @@ -332,7 +332,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { let llreturn_ty = match &self.ret.mode { PassMode::Ignore => cx.type_void(), PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_llvm_type(cx), - PassMode::Cast(cast, _) => cast.llvm_type(cx), + PassMode::Cast { cast, pad_i32: _ } => cast.llvm_type(cx), PassMode::Indirect { .. } => { llargument_tys.push(cx.type_ptr()); cx.type_void() @@ -351,6 +351,11 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { // guarnateeing that we generate ABI-compatible LLVM IR. Things get tricky for // aggregates... if matches!(arg.layout.abi, abi::Abi::Aggregate { .. }) { + assert!( + arg.layout.is_sized(), + "`PassMode::Direct` for unsized type: {}", + arg.layout.ty + ); // This really shouldn't happen, since `immediate_llvm_type` will use // `layout.fields` to turn this Rust type into an LLVM type. This means all // sorts of Rust type details leak into the ABI. However wasm sadly *does* @@ -378,8 +383,10 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true)); continue; } - PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => { - assert!(arg.layout.is_unsized()); + PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack } => { + // `Indirect` with metadata is only for unsized types, and doesn't work with + // on-stack passing. + assert!(arg.layout.is_unsized() && !on_stack); // Construct the type of a (wide) pointer to `ty`, and pass its two fields. // Any two ABI-compatible unsized types have the same metadata type and // moreover the same metadata value leads to the same dynamic size and @@ -390,7 +397,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 1, true)); continue; } - PassMode::Cast(cast, pad_i32) => { + PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => { + assert!(arg.layout.is_sized()); + cx.type_ptr() + } + PassMode::Cast { cast, pad_i32 } => { + // `Cast` means "transmute to `CastType`"; that only makes sense for sized types. + assert!(arg.layout.is_sized()); // add padding if *pad_i32 { llargument_tys.push(Reg::i32().llvm_type(cx)); @@ -399,7 +412,6 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { // We assume here that ABI-compatible Rust types have the same cast type. cast.llvm_type(cx) } - PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => cx.type_ptr(), }; llargument_tys.push(llarg_ty); } @@ -442,13 +454,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { PassMode::Direct(attrs) => { attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn); } - PassMode::Indirect { attrs, extra_attrs: _, on_stack } => { + PassMode::Indirect { attrs, meta_attrs: _, on_stack } => { assert!(!on_stack); let i = apply(attrs); let sret = llvm::CreateStructRetAttr(cx.llcx, self.ret.layout.llvm_type(cx)); attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[sret]); } - PassMode::Cast(cast, _) => { + PassMode::Cast { cast, pad_i32: _ } => { cast.attrs.apply_attrs_to_llfn(llvm::AttributePlace::ReturnValue, cx, llfn); } _ => {} @@ -456,25 +468,25 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { for arg in self.args.iter() { match &arg.mode { PassMode::Ignore => {} - PassMode::Indirect { attrs, extra_attrs: None, on_stack: true } => { + PassMode::Indirect { attrs, meta_attrs: None, on_stack: true } => { let i = apply(attrs); let byval = llvm::CreateByValAttr(cx.llcx, arg.layout.llvm_type(cx)); attributes::apply_to_llfn(llfn, llvm::AttributePlace::Argument(i), &[byval]); } PassMode::Direct(attrs) - | PassMode::Indirect { attrs, extra_attrs: None, on_stack: false } => { + | PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => { apply(attrs); } - PassMode::Indirect { attrs, extra_attrs: Some(extra_attrs), on_stack } => { + PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => { assert!(!on_stack); apply(attrs); - apply(extra_attrs); + apply(meta_attrs); } PassMode::Pair(a, b) => { apply(a); apply(b); } - PassMode::Cast(cast, pad_i32) => { + PassMode::Cast { cast, pad_i32 } => { if *pad_i32 { apply(&ArgAttributes::new()); } @@ -504,13 +516,13 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { PassMode::Direct(attrs) => { attrs.apply_attrs_to_callsite(llvm::AttributePlace::ReturnValue, bx.cx, callsite); } - PassMode::Indirect { attrs, extra_attrs: _, on_stack } => { + PassMode::Indirect { attrs, meta_attrs: _, on_stack } => { assert!(!on_stack); let i = apply(bx.cx, attrs); let sret = llvm::CreateStructRetAttr(bx.cx.llcx, self.ret.layout.llvm_type(bx)); attributes::apply_to_callsite(callsite, llvm::AttributePlace::Argument(i), &[sret]); } - PassMode::Cast(cast, _) => { + PassMode::Cast { cast, pad_i32: _ } => { cast.attrs.apply_attrs_to_callsite( llvm::AttributePlace::ReturnValue, &bx.cx, @@ -532,7 +544,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { for arg in self.args.iter() { match &arg.mode { PassMode::Ignore => {} - PassMode::Indirect { attrs, extra_attrs: None, on_stack: true } => { + PassMode::Indirect { attrs, meta_attrs: None, on_stack: true } => { let i = apply(bx.cx, attrs); let byval = llvm::CreateByValAttr(bx.cx.llcx, arg.layout.llvm_type(bx)); attributes::apply_to_callsite( @@ -542,18 +554,18 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { ); } PassMode::Direct(attrs) - | PassMode::Indirect { attrs, extra_attrs: None, on_stack: false } => { + | PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => { apply(bx.cx, attrs); } - PassMode::Indirect { attrs, extra_attrs: Some(extra_attrs), on_stack: _ } => { + PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack: _ } => { apply(bx.cx, attrs); - apply(bx.cx, extra_attrs); + apply(bx.cx, meta_attrs); } PassMode::Pair(a, b) => { apply(bx.cx, a); apply(bx.cx, b); } - PassMode::Cast(cast, pad_i32) => { + PassMode::Cast { cast, pad_i32 } => { if *pad_i32 { apply(bx.cx, &ArgAttributes::new()); } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index a9b06030e70..9289c37d763 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -165,7 +165,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { sym::volatile_load | sym::unaligned_volatile_load => { let tp_ty = fn_args.type_at(0); let ptr = args[0].immediate(); - let load = if let PassMode::Cast(ty, _) = &fn_abi.ret.mode { + let load = if let PassMode::Cast { cast: ty, pad_i32: _ } = &fn_abi.ret.mode { let llty = ty.llvm_type(self); self.volatile_load(llty, ptr) } else { @@ -386,7 +386,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { }; if !fn_abi.ret.is_ignore() { - if let PassMode::Cast(_, _) = &fn_abi.ret.mode { + if let PassMode::Cast { .. } = &fn_abi.ret.mode { self.store(llval, result.llval, result.align); } else { OperandRef::from_immediate_or_packed_pair(self, llval, result.layout) diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 9ce13ff469c..d0a078505d2 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -19,8 +19,6 @@ codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$e codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error} -codegen_ssa_erroneous_constant = erroneous constant encountered - codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$error} codegen_ssa_expected_coverage_symbol = expected `coverage(off)` or `coverage(on)` @@ -174,8 +172,6 @@ codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error} codegen_ssa_option_gcc_only = option `-Z gcc-ld` is used even though linker flavor is not gcc -codegen_ssa_polymorphic_constant_too_generic = codegen encountered polymorphic constant: TooGeneric - codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status} .note = {$output} diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index fa49095c9e8..bfd572a2eea 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -595,20 +595,6 @@ pub struct InvalidWindowsSubsystem { pub subsystem: Symbol, } -#[derive(Diagnostic)] -#[diag(codegen_ssa_erroneous_constant)] -pub struct ErroneousConstant { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(codegen_ssa_polymorphic_constant_too_generic)] -pub struct PolymorphicConstantTooGeneric { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(codegen_ssa_shuffle_indices_evaluation)] pub struct ShuffleIndicesEvaluation { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index d8f6b4ed836..b738a49bf11 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -416,7 +416,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - PassMode::Cast(cast_ty, _) => { + PassMode::Cast { cast: cast_ty, pad_i32: _ } => { let op = match self.locals[mir::RETURN_PLACE] { LocalRef::Operand(op) => op, LocalRef::PendingOperand => bug!("use of return before def"), @@ -1088,9 +1088,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { InlineAsmOperandRef::InOut { reg, late, in_value, out_place } } mir::InlineAsmOperand::Const { ref value } => { - let const_value = self - .eval_mir_constant(value) - .unwrap_or_else(|_| span_bug!(span, "asm const cannot be resolved")); + let const_value = self.eval_mir_constant(value); let string = common::asm_const_to_str( bx.tcx(), span, @@ -1310,7 +1308,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) { match arg.mode { PassMode::Ignore => return, - PassMode::Cast(_, true) => { + PassMode::Cast { pad_i32: true, .. } => { // Fill padding with undef value, where applicable. llargs.push(bx.const_undef(bx.reg_backend_type(&Reg::i32()))); } @@ -1322,7 +1320,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } _ => bug!("codegen_argument: {:?} invalid for pair argument", op), }, - PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => match op.val { + PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => match op.val { Ref(a, Some(b), _) => { llargs.push(a); llargs.push(b); @@ -1347,7 +1345,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { op.val.store(bx, scratch); (scratch.llval, scratch.align, true) } - PassMode::Cast(..) => { + PassMode::Cast { .. } => { let scratch = PlaceRef::alloca(bx, arg.layout); op.val.store(bx, scratch); (scratch.llval, scratch.align, true) @@ -1400,7 +1398,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if by_ref && !arg.is_indirect() { // Have to load the argument, maybe while casting it. - if let PassMode::Cast(ty, _) = &arg.mode { + if let PassMode::Cast { cast: ty, .. } = &arg.mode { let llty = bx.cast_backend_type(ty); llval = bx.load(llty, llval, align.min(arg.layout.align.abi)); } else { @@ -1744,7 +1742,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } DirectOperand(index) => { // If there is a cast, we have to store and reload. - let op = if let PassMode::Cast(..) = ret_abi.mode { + let op = if let PassMode::Cast { .. } = ret_abi.mode { let tmp = PlaceRef::alloca(bx, ret_abi.layout); tmp.storage_live(bx); bx.store_arg(&ret_abi, llval, tmp); diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 4d7bd60ceca..263b41ed880 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -14,34 +14,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &self, bx: &mut Bx, constant: &mir::Constant<'tcx>, - ) -> Result, ErrorHandled> { - let val = self.eval_mir_constant(constant)?; + ) -> OperandRef<'tcx, Bx::Value> { + let val = self.eval_mir_constant(constant); let ty = self.monomorphize(constant.ty()); - Ok(OperandRef::from_const(bx, val, ty)) + OperandRef::from_const(bx, val, ty) } - pub fn eval_mir_constant( - &self, - constant: &mir::Constant<'tcx>, - ) -> Result, ErrorHandled> { + pub fn eval_mir_constant(&self, constant: &mir::Constant<'tcx>) -> ConstValue<'tcx> { self.monomorphize(constant.literal) .eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span)) - .map_err(|err| { - match err { - ErrorHandled::Reported(_) => { - self.cx - .tcx() - .sess - .emit_err(errors::ErroneousConstant { span: constant.span }); - } - ErrorHandled::TooGeneric => { - self.cx.tcx().sess.diagnostic().emit_bug( - errors::PolymorphicConstantTooGeneric { span: constant.span }, - ); - } - } - err - }) + .expect("erroneous constant not captured by required_consts") } /// This is a convenience helper for `simd_shuffle_indices`. It has the precondition diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index ac705a5f35c..d1560114763 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -579,23 +579,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if let Some(dbg_var) = dbg_var { let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue }; - if let Ok(operand) = self.eval_mir_constant_to_operand(bx, &c) { - self.set_debug_loc(bx, var.source_info); - let base = Self::spill_operand_to_stack( - operand, - Some(var.name.to_string()), - bx, - ); + let operand = self.eval_mir_constant_to_operand(bx, &c); + self.set_debug_loc(bx, var.source_info); + let base = + Self::spill_operand_to_stack(operand, Some(var.name.to_string()), bx); - bx.dbg_var_addr( - dbg_var, - dbg_loc, - base.llval, - Size::ZERO, - &[], - fragment, - ); - } + bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], fragment); } } } diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 8821fb21fd0..8efef440522 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -462,7 +462,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; if !fn_abi.ret.is_ignore() { - if let PassMode::Cast(..) = &fn_abi.ret.mode { + if let PassMode::Cast { .. } = &fn_abi.ret.mode { bx.store(llval, result.llval, result.align); } else { OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout) diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index c4408f2db4c..1e905a7c78e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -3,7 +3,6 @@ use crate::traits::*; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; use rustc_middle::mir; -use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::traversal; use rustc_middle::mir::UnwindTerminateReason; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout}; @@ -212,23 +211,14 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx); - // Evaluate all required consts; codegen later assumes that CTFE will never fail. - let mut all_consts_ok = true; - for const_ in &mir.required_consts { - if let Err(err) = fx.eval_mir_constant(const_) { - all_consts_ok = false; - match err { - // errored or at least linted - ErrorHandled::Reported(_) => {} - ErrorHandled::TooGeneric => { - span_bug!(const_.span, "codegen encountered polymorphic constant: {:?}", err) - } - } - } - } - if !all_consts_ok { - // We leave the IR in some half-built state here, and rely on this code not even being - // submitted to LLVM once an error was raised. + // Rust post-monomorphization checks; we later rely on them. + if let Err(err) = + mir.post_mono_checks(cx.tcx(), ty::ParamEnv::reveal_all(), |c| Ok(fx.monomorphize(c))) + { + err.emit_err(cx.tcx()); + // This IR shouldn't ever be emitted, but let's try to guard against any of this code + // ever running. + start_bx.abort(); return; } @@ -327,7 +317,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( for i in 0..tupled_arg_tys.len() { let arg = &fx.fn_abi.args[idx]; idx += 1; - if let PassMode::Cast(_, true) = arg.mode { + if let PassMode::Cast { pad_i32: true, .. } = arg.mode { llarg_idx += 1; } let pr_field = place.project_field(bx, i); @@ -351,7 +341,7 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let arg = &fx.fn_abi.args[idx]; idx += 1; - if let PassMode::Cast(_, true) = arg.mode { + if let PassMode::Cast { pad_i32: true, .. } = arg.mode { llarg_idx += 1; } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 1926bb8df52..e192d16ff38 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -575,12 +575,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_consume(bx, place.as_ref()) } - mir::Operand::Constant(ref constant) => { - // This cannot fail because we checked all required_consts in advance. - self.eval_mir_constant_to_operand(bx, constant).unwrap_or_else(|_err| { - span_bug!(constant.span, "erroneous constant not captured by required_consts") - }) - } + mir::Operand::Constant(ref constant) => self.eval_mir_constant_to_operand(bx, constant), } } } diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 020402fe25e..d23e2a9f3e4 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -83,9 +83,6 @@ const_eval_dyn_call_vtable_mismatch = const_eval_dyn_star_call_vtable_mismatch = `dyn*` call on a pointer whose vtable does not match its type -const_eval_erroneous_constant = - erroneous constant used - const_eval_error = {$error_kind -> [static] could not evaluate static initializer [const] evaluation of constant value failed diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 2d20d553ef7..bf1e0a37073 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -4,7 +4,7 @@ use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, IntoDiagnostic, IntoDi use rustc_middle::mir::AssertKind; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::{layout::LayoutError, ConstInt}; -use rustc_span::{ErrorGuaranteed, Span, Symbol}; +use rustc_span::{ErrorGuaranteed, Span, Symbol, DUMMY_SP}; use super::InterpCx; use crate::errors::{self, FrameNote, ReportErrorExt}; @@ -134,11 +134,11 @@ where // Don't emit a new diagnostic for these errors, they are already reported elsewhere or // should remain silent. err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => { - ErrorHandled::TooGeneric + ErrorHandled::TooGeneric(span.unwrap_or(DUMMY_SP)) } - err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar), + err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar, span.unwrap_or(DUMMY_SP)), err_inval!(Layout(LayoutError::ReferencesError(guar))) => { - ErrorHandled::Reported(guar.into()) + ErrorHandled::Reported(guar.into(), span.unwrap_or(DUMMY_SP)) } // Report remaining errors. _ => { @@ -152,7 +152,7 @@ where // Use *our* span to label the interp error err.span_label(our_span, msg); - ErrorHandled::Reported(err.emit().into()) + ErrorHandled::Reported(err.emit().into(), span) } } } 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 454baf2a745..807794a2a59 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -212,7 +212,7 @@ pub fn eval_to_const_value_raw_provider<'tcx>( key.param_env = key.param_env.with_user_facing(); match tcx.eval_to_const_value_raw(key) { // try again with reveal all as requested - Err(ErrorHandled::TooGeneric) => {} + Err(ErrorHandled::TooGeneric(_)) => {} // deduplicate calls other => return other, } @@ -259,7 +259,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>( key.param_env = key.param_env.with_user_facing(); match tcx.eval_to_allocation_raw(key) { // try again with reveal all as requested - Err(ErrorHandled::TooGeneric) => {} + Err(ErrorHandled::TooGeneric(_)) => {} // deduplicate calls other => return other, } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index c3c6cbe3991..b1599dd6894 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -239,13 +239,6 @@ pub struct LongRunningWarn { pub item_span: Span, } -#[derive(Diagnostic)] -#[diag(const_eval_erroneous_constant)] -pub(crate) struct ErroneousConstUsed { - #[primary_span] - pub span: Span, -} - #[derive(Subdiagnostic)] #[note(const_eval_non_const_impl)] pub(crate) struct NonConstImplNote { diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 966ce66c7ad..cb14e165b5c 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -7,7 +7,7 @@ use hir::CRATE_HIR_ID; use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; use rustc_index::IndexVec; use rustc_middle::mir; -use rustc_middle::mir::interpret::{ErrorHandled, InterpError, InvalidMetaKind, ReportedErrorInfo}; +use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{ self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers, @@ -21,10 +21,10 @@ use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayou use super::{ AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace, - MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, Pointer, PointerArithmetic, + MemPlaceMeta, Memory, MemoryKind, OpTy, Operand, Place, PlaceTy, Pointer, PointerArithmetic, Projectable, Provenance, Scalar, StackPopJump, }; -use crate::errors::{self, ErroneousConstUsed}; +use crate::errors; use crate::util; use crate::{fluent_generated as fluent, ReportErrorExt}; @@ -556,7 +556,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { >( &self, value: T, - ) -> Result> { + ) -> Result { self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value) } @@ -566,7 +566,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>, value: T, - ) -> Result> { + ) -> Result { frame .instance .try_subst_mir_and_normalize_erasing_regions( @@ -574,7 +574,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.param_env, ty::EarlyBinder::bind(value), ) - .map_err(|_| err_inval!(TooGeneric)) + .map_err(|_| ErrorHandled::TooGeneric(self.cur_span())) } /// The `args` are assumed to already be in our interpreter "universe" (param_env). @@ -750,11 +750,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check). if M::POST_MONO_CHECKS { - for ct in &body.required_consts { - let span = ct.span; - let ct = self.subst_from_current_frame_and_normalize_erasing_regions(ct.literal)?; - self.eval_mir_constant(&ct, Some(span), None)?; - } + // `ctfe_query` does some error message decoration that we want to be in effect here. + self.ctfe_query(None, |tcx| { + body.post_mono_checks(*tcx, self.param_env, |c| { + self.subst_from_current_frame_and_normalize_erasing_regions(c) + }) + })?; } // done @@ -1059,28 +1060,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, span: Option, query: impl FnOnce(TyCtxtAt<'tcx>) -> Result, - ) -> InterpResult<'tcx, T> { + ) -> Result { // Use a precise span for better cycle errors. query(self.tcx.at(span.unwrap_or_else(|| self.cur_span()))).map_err(|err| { - match err { - ErrorHandled::Reported(err) => { - if !err.is_tainted_by_errors() && let Some(span) = span { - // To make it easier to figure out where this error comes from, also add a note at the current location. - self.tcx.sess.emit_note(ErroneousConstUsed { span }); - } - err_inval!(AlreadyReported(err)) - } - ErrorHandled::TooGeneric => err_inval!(TooGeneric), - } - .into() + err.emit_note(*self.tcx); + err }) } pub fn eval_global( &self, - gid: GlobalId<'tcx>, - span: Option, + instance: ty::Instance<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { + let gid = GlobalId { instance, promoted: None }; // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics // and thus don't care about the parameter environment. While we could just use // `self.param_env`, that would mean we invoke the query to evaluate the static @@ -1091,10 +1083,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } else { self.param_env }; - let val = self.ctfe_query(span, |tcx| tcx.eval_to_allocation_raw(param_env.and(gid)))?; + let val = self.ctfe_query(None, |tcx| tcx.eval_to_allocation_raw(param_env.and(gid)))?; self.raw_const_to_mplace(val) } + pub fn eval_mir_constant( + &self, + val: &mir::ConstantKind<'tcx>, + span: Option, + layout: Option>, + ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { + let const_val = self.ctfe_query(span, |tcx| val.eval(*tcx, self.param_env, span))?; + self.const_val_to_op(const_val, val.ty(), layout) + } + #[must_use] pub fn dump_place( &self, diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 8b33dbb677f..082c0f5b84e 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -8,15 +8,14 @@ use either::{Either, Left, Right}; use rustc_hir::def::Namespace; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter}; -use rustc_middle::ty::{ConstInt, Ty, ValTree}; +use rustc_middle::ty::{ConstInt, Ty}; use rustc_middle::{mir, ty}; -use rustc_span::Span; use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size}; use super::{ - alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, Frame, GlobalId, - InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, PlaceTy, Pointer, - Projectable, Provenance, Scalar, + alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, Frame, InterpCx, + InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, PlaceTy, Pointer, Projectable, + Provenance, Scalar, }; /// An `Immediate` represents a single immediate self-contained Rust value. @@ -136,7 +135,11 @@ impl std::fmt::Display for ImmTy<'_, Prov> { impl std::fmt::Debug for ImmTy<'_, Prov> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("ImmTy").field("imm", &self.imm).field("ty", &self.layout.ty).finish() + // Printing `layout` results in too much noise; just print a nice version of the type. + f.debug_struct("ImmTy") + .field("imm", &self.imm) + .field("ty", &format_args!("{}", self.layout.ty)) + .finish() } } @@ -305,7 +308,11 @@ pub struct OpTy<'tcx, Prov: Provenance = AllocId> { impl std::fmt::Debug for OpTy<'_, Prov> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("OpTy").field("op", &self.op).field("ty", &self.layout.ty).finish() + // Printing `layout` results in too much noise; just print a nice version of the type. + f.debug_struct("OpTy") + .field("op", &self.op) + .field("ty", &format_args!("{}", self.layout.ty)) + .finish() } } @@ -693,54 +700,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(op) } - fn eval_ty_constant( - &self, - val: ty::Const<'tcx>, - span: Option, - ) -> InterpResult<'tcx, ValTree<'tcx>> { - Ok(match val.kind() { - ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(..) => { - throw_inval!(TooGeneric) - } - // FIXME(generic_const_exprs): `ConstKind::Expr` should be able to be evaluated - ty::ConstKind::Expr(_) => throw_inval!(TooGeneric), - ty::ConstKind::Error(reported) => { - throw_inval!(AlreadyReported(reported.into())) - } - ty::ConstKind::Unevaluated(uv) => { - let instance = self.resolve(uv.def, uv.args)?; - let cid = GlobalId { instance, promoted: None }; - self.ctfe_query(span, |tcx| tcx.eval_to_valtree(self.param_env.and(cid)))? - .unwrap_or_else(|| bug!("unable to create ValTree for {uv:?}")) - } - ty::ConstKind::Bound(..) | ty::ConstKind::Infer(..) => { - span_bug!(self.cur_span(), "unexpected ConstKind in ctfe: {val:?}") - } - ty::ConstKind::Value(valtree) => valtree, - }) - } - - pub fn eval_mir_constant( - &self, - val: &mir::ConstantKind<'tcx>, - span: Option, - layout: Option>, - ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - match *val { - mir::ConstantKind::Ty(ct) => { - let ty = ct.ty(); - let valtree = self.eval_ty_constant(ct, span)?; - let const_val = self.tcx.valtree_to_const_val((ty, valtree)); - self.const_val_to_op(const_val, ty, layout) - } - mir::ConstantKind::Val(val, ty) => self.const_val_to_op(val, ty, layout), - mir::ConstantKind::Unevaluated(uv, _) => { - let instance = self.resolve(uv.def, uv.args)?; - Ok(self.eval_global(GlobalId { instance, promoted: uv.promoted }, span)?.into()) - } - } - } - pub(crate) fn const_val_to_op( &self, val_val: ConstValue<'tcx>, diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 90f2b470179..0f66df5c30d 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -117,9 +117,10 @@ pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> { impl std::fmt::Debug for MPlaceTy<'_, Prov> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // Printing `layout` results in too much noise; just print a nice version of the type. f.debug_struct("MPlaceTy") .field("mplace", &self.mplace) - .field("ty", &self.layout.ty) + .field("ty", &format_args!("{}", self.layout.ty)) .finish() } } @@ -237,7 +238,11 @@ pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> { impl std::fmt::Debug for PlaceTy<'_, Prov> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("PlaceTy").field("place", &self.place).field("ty", &self.layout.ty).finish() + // Printing `layout` results in too much noise; just print a nice version of the type. + f.debug_struct("PlaceTy") + .field("place", &self.place) + .field("ty", &format_args!("{}", self.layout.ty)) + .finish() } } diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index 85ef2de9b5e..4075481e561 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -51,7 +51,7 @@ pub fn dominators(graph: &G) -> Dominators { // Traverse the graph, collecting a number of things: // // * Preorder mapping (to it, and back to the actual ordering) - // * Postorder mapping (used exclusively for rank_partial_cmp on the final product) + // * Postorder mapping (used exclusively for `cmp_in_dominator_order` on the final product) // * Parents for each vertex in the preorder tree // // These are all done here rather than through one of the 'standard' @@ -342,8 +342,8 @@ impl Dominators { /// 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 /// meaning.) This method cannot be used to determine if either Node dominates the other. - pub fn rank_partial_cmp(&self, lhs: Node, rhs: Node) -> Option { - self.post_order_rank[rhs].partial_cmp(&self.post_order_rank[lhs]) + pub fn cmp_in_dominator_order(&self, lhs: Node, rhs: Node) -> Ordering { + self.post_order_rank[rhs].cmp(&self.post_order_rank[lhs]) } /// Returns true if `a` dominates `b`. diff --git a/compiler/rustc_error_codes/src/error_codes/E0691.md b/compiler/rustc_error_codes/src/error_codes/E0691.md index 483c74c0ff5..a5bedd61e92 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0691.md +++ b/compiler/rustc_error_codes/src/error_codes/E0691.md @@ -1,9 +1,11 @@ +#### Note: this error code is no longer emitted by the compiler. + A struct, enum, or union with the `repr(transparent)` representation hint contains a zero-sized field that requires non-trivial alignment. Erroneous code example: -```compile_fail,E0691 +```ignore (error is no longer emitted) #![feature(repr_align)] #[repr(align(32))] diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index fcb112eadfe..f3b88f46bae 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -401,6 +401,8 @@ declare_features! ( /// Allows function attribute `#[coverage(on/off)]`, to control coverage /// instrumentation of that function. (active, coverage_attribute, "CURRENT_RUSTC_VERSION", 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), /// Allows non-builtin attributes in inner attribute position. (active, custom_inner_attributes, "1.30.0", Some(54726), None), /// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`. @@ -414,7 +416,7 @@ declare_features! ( /// Allows having using `suggestion` in the `#[deprecated]` attribute. (active, deprecated_suggestion, "1.61.0", Some(94785), None), /// Allows using the `#[diagnostic]` attribute tool namespace - (active, diagnostic_namespace, "1.73.0", Some(94785), None), + (active, diagnostic_namespace, "1.73.0", Some(111996), None), /// Controls errors in trait implementations. (active, do_not_recommend, "1.67.0", Some(51992), None), /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index b4b794d4e09..04ebe22a9eb 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -699,6 +699,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_pass_by_value, Normal, template!(Word), ErrorFollowing, "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference." ), + rustc_attr!( + rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing, + "#[rustc_never_returns_null_ptr] is used to mark functions returning non-null pointers." + ), rustc_attr!( rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, @only_local: true, "#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`." diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 50da2278312..18f7a18625e 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -95,6 +95,34 @@ hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a par hir_analysis_impl_not_marked_default_err = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default` .note = parent implementation is in crate `{$cname}` +hir_analysis_inherent_dyn = cannot define inherent `impl` for a dyn auto trait + .label = impl requires at least one non-auto trait + .note = define and implement a new trait or type instead + +hir_analysis_inherent_nominal = no nominal type found for inherent implementation + .label = impl requires a nominal type + .note = either implement a trait on it or create a newtype to wrap it instead +hir_analysis_inherent_primitive_ty = cannot define inherent `impl` for primitive types + .help = consider using an extension trait instead + +hir_analysis_inherent_primitive_ty_note = you could also try moving the reference to uses of `{$subty}` (such as `self`) within the implementation + +hir_analysis_inherent_ty_outside = cannot define inherent `impl` for a type outside of the crate where the type is defined + .help = consider moving this inherent impl into the crate defining the type if possible + .span_help = alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type and `#[rustc_allow_incoherent_impl]` to the relevant impl items + +hir_analysis_inherent_ty_outside_new = cannot define inherent `impl` for a type outside of the crate where the type is defined + .label = impl for type defined outside of crate. + .note = define and implement a trait or new type instead + +hir_analysis_inherent_ty_outside_primitive = cannot define inherent `impl` for primitive types outside of `core` + .help = consider moving this inherent impl into `core` if possible + .span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items + +hir_analysis_inherent_ty_outside_relevant = cannot define inherent `impl` for a type outside of the crate where the type is defined + .help = consider moving this inherent impl into the crate defining the type if possible + .span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items + hir_analysis_invalid_union_field = field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union .note = union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` @@ -276,13 +304,13 @@ hir_analysis_transparent_enum_variant = transparent enum needs exactly one varia .many_label = too many variants in `{$path}` .multi_label = variant here -hir_analysis_transparent_non_zero_sized = transparent {$desc} needs at most one non-zero-sized field, but has {$field_count} - .label = needs at most one non-zero-sized field, but has {$field_count} - .labels = this field is non-zero-sized +hir_analysis_transparent_non_zero_sized = transparent {$desc} needs at most one field with non-trivial size or alignment, but has {$field_count} + .label = needs at most one field with non-trivial size or alignment, but has {$field_count} + .labels = this field has non-zero size or requires alignment -hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$desc} needs at most one non-zero-sized field, but has {$field_count} - .label = needs at most one non-zero-sized field, but has {$field_count} - .labels = this field is non-zero-sized +hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$desc} needs at most one field with non-trivial size or alignment, but has {$field_count} + .label = needs at most one field with non-trivial size or alignment, but has {$field_count} + .labels = this field has non-zero size or requires alignment hir_analysis_typeof_reserved_keyword_used = `typeof` is a reserved keyword but unimplemented diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 9a57cc6dbab..13826264a22 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1138,19 +1138,19 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) return; } - // For each field, figure out if it's known to be a ZST and align(1), with "known" - // respecting #[non_exhaustive] attributes. + // For each field, figure out if it's known to have "trivial" layout (i.e., is a 1-ZST), with + // "known" respecting #[non_exhaustive] attributes. let field_infos = adt.all_fields().map(|field| { let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did)); let param_env = tcx.param_env(field.did); let layout = tcx.layout_of(param_env.and(ty)); // We are currently checking the type this field came from, so it must be local let span = tcx.hir().span_if_local(field.did).unwrap(); - let zst = layout.is_ok_and(|layout| layout.is_zst()); - let align = layout.ok().map(|layout| layout.align.abi.bytes()); - if !zst { - return (span, zst, align, None); + let trivial = layout.is_ok_and(|layout| layout.is_1zst()); + if !trivial { + return (span, trivial, None); } + // Even some 1-ZST fields are not allowed though, if they have `non_exhaustive`. fn check_non_exhaustive<'tcx>( tcx: TyCtxt<'tcx>, @@ -1184,58 +1184,52 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) } } - (span, zst, align, check_non_exhaustive(tcx, ty).break_value()) + (span, trivial, check_non_exhaustive(tcx, ty).break_value()) }); - let non_zst_fields = field_infos + let non_trivial_fields = field_infos .clone() - .filter_map(|(span, zst, _align, _non_exhaustive)| if !zst { Some(span) } else { None }); - let non_zst_count = non_zst_fields.clone().count(); - if non_zst_count >= 2 { - bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, tcx.def_span(adt.did())); + .filter_map(|(span, trivial, _non_exhaustive)| if !trivial { Some(span) } else { None }); + let non_trivial_count = non_trivial_fields.clone().count(); + if non_trivial_count >= 2 { + bad_non_zero_sized_fields( + tcx, + adt, + non_trivial_count, + non_trivial_fields, + tcx.def_span(adt.did()), + ); + return; } - let incompatible_zst_fields = - field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count(); - let incompat = incompatible_zst_fields + non_zst_count >= 2 && non_zst_count < 2; - for (span, zst, align, non_exhaustive) in field_infos { - if zst && align != Some(1) { - let mut err = struct_span_err!( - tcx.sess, - span, - E0691, - "zero-sized field in transparent {} has alignment larger than 1", - adt.descr(), - ); - - if let Some(align_bytes) = align { - err.span_label( + let mut prev_non_exhaustive_1zst = false; + for (span, _trivial, non_exhaustive_1zst) in field_infos { + if let Some((descr, def_id, args, non_exhaustive)) = non_exhaustive_1zst { + // If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts. + // Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst. + if non_trivial_count > 0 || prev_non_exhaustive_1zst { + tcx.struct_span_lint_hir( + REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, + tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()), span, - format!("has alignment of {align_bytes}, which is larger than 1"), - ); + "zero-sized fields in `repr(transparent)` cannot \ + contain external non-exhaustive types", + |lint| { + let note = if non_exhaustive { + "is marked with `#[non_exhaustive]`" + } else { + "contains private fields" + }; + let field_ty = tcx.def_path_str_with_args(def_id, args); + lint.note(format!( + "this {descr} contains `{field_ty}`, which {note}, \ + and makes it not a breaking change to become \ + non-zero-sized in the future." + )) + }, + ) } else { - err.span_label(span, "may have alignment larger than 1"); + prev_non_exhaustive_1zst = true; } - - err.emit(); - } - if incompat && let Some((descr, def_id, args, non_exhaustive)) = non_exhaustive { - tcx.struct_span_lint_hir( - REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, - tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()), - span, - "zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types", - |lint| { - let note = if non_exhaustive { - "is marked with `#[non_exhaustive]`" - } else { - "contains private fields" - }; - let field_ty = tcx.def_path_str_with_args(def_id, args); - lint - .note(format!("this {descr} contains `{field_ty}`, which {note}, \ - and makes it not a breaking change to become non-zero-sized in the future.")) - }, - ) } } } diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index a94c75f918a..aa7c9e504c1 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -7,7 +7,6 @@ //! `tcx.inherent_impls(def_id)`). That value, however, //! is computed by selecting an idea from this table. -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -15,6 +14,8 @@ use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams}; use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt}; use rustc_span::symbol::sym; +use crate::errors; + /// On-demand query: yields a map containing all types mapped to their inherent impls. pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls { let mut collect = InherentCollect { tcx, impls_map: Default::default() }; @@ -45,14 +46,6 @@ struct InherentCollect<'tcx> { impls_map: CrateInherentImpls, } -const INTO_CORE: &str = "consider moving this inherent impl into `core` if possible"; -const INTO_DEFINING_CRATE: &str = - "consider moving this inherent impl into the crate defining the type if possible"; -const ADD_ATTR_TO_TY: &str = "alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type \ - and `#[rustc_allow_incoherent_impl]` to the relevant impl items"; -const ADD_ATTR: &str = - "alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items"; - impl<'tcx> InherentCollect<'tcx> { fn check_def_id(&mut self, impl_def_id: LocalDefId, self_ty: Ty<'tcx>, ty_def_id: DefId) { if let Some(ty_def_id) = ty_def_id.as_local() { @@ -69,30 +62,17 @@ impl<'tcx> InherentCollect<'tcx> { if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) { let impl_span = self.tcx.def_span(impl_def_id); - struct_span_err!( - self.tcx.sess, - impl_span, - E0390, - "cannot define inherent `impl` for a type outside of the crate where the type is defined", - ) - .help(INTO_DEFINING_CRATE) - .span_help(impl_span, ADD_ATTR_TO_TY) - .emit(); + self.tcx.sess.emit_err(errors::InherentTyOutside { span: impl_span }); return; } for &impl_item in items { if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) { let impl_span = self.tcx.def_span(impl_def_id); - struct_span_err!( - self.tcx.sess, - impl_span, - E0390, - "cannot define inherent `impl` for a type outside of the crate where the type is defined", - ) - .help(INTO_DEFINING_CRATE) - .span_help(self.tcx.def_span(impl_item), ADD_ATTR) - .emit(); + self.tcx.sess.emit_err(errors::InherentTyOutsideRelevant { + span: impl_span, + help_span: self.tcx.def_span(impl_item), + }); return; } } @@ -104,16 +84,7 @@ impl<'tcx> InherentCollect<'tcx> { } } else { let impl_span = self.tcx.def_span(impl_def_id); - struct_span_err!( - self.tcx.sess, - impl_span, - E0116, - "cannot define inherent `impl` for a type outside of the crate \ - where the type is defined" - ) - .span_label(impl_span, "impl for type defined outside of crate.") - .note("define and implement a trait or new type instead") - .emit(); + self.tcx.sess.emit_err(errors::InherentTyOutsideNew { span: impl_span }); } } @@ -124,34 +95,20 @@ impl<'tcx> InherentCollect<'tcx> { for &impl_item in items { if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) { let span = self.tcx.def_span(impl_def_id); - struct_span_err!( - self.tcx.sess, + self.tcx.sess.emit_err(errors::InherentTyOutsidePrimitive { span, - E0390, - "cannot define inherent `impl` for primitive types outside of `core`", - ) - .help(INTO_CORE) - .span_help(self.tcx.def_span(impl_item), ADD_ATTR) - .emit(); + help_span: self.tcx.def_span(impl_item), + }); return; } } } else { let span = self.tcx.def_span(impl_def_id); - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0390, - "cannot define inherent `impl` for primitive types", - ); - err.help("consider using an extension trait instead"); + let mut note = None; if let ty::Ref(_, subty, _) = ty.kind() { - err.note(format!( - "you could also try moving the reference to \ - uses of `{subty}` (such as `self`) within the implementation" - )); + note = Some(errors::InherentPrimitiveTyNote { subty: *subty }); } - err.emit(); + self.tcx.sess.emit_err(errors::InherentPrimitiveTy { span, note }); return; } } @@ -178,15 +135,7 @@ impl<'tcx> InherentCollect<'tcx> { self.check_def_id(id, self_ty, data.principal_def_id().unwrap()); } ty::Dynamic(..) => { - struct_span_err!( - self.tcx.sess, - item_span, - E0785, - "cannot define inherent `impl` for a dyn auto trait" - ) - .span_label(item_span, "impl requires at least one non-auto trait") - .note("define and implement a new trait or type instead") - .emit(); + self.tcx.sess.emit_err(errors::InherentDyn { span: item_span }); } ty::Bool | ty::Char @@ -202,17 +151,7 @@ impl<'tcx> InherentCollect<'tcx> { | ty::FnPtr(_) | ty::Tuple(..) => self.check_primitive_impl(id, self_ty), ty::Alias(..) | ty::Param(_) => { - let mut err = struct_span_err!( - self.tcx.sess, - item_span, - E0118, - "no nominal type found for inherent implementation" - ); - - err.span_label(item_span, "impl requires a nominal type") - .note("either implement a trait on it or create a newtype to wrap it instead"); - - err.emit(); + self.tcx.sess.emit_err(errors::InherentNominal { span: item_span }); } ty::FnDef(..) | ty::Closure(..) diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 7614913f4bf..b83ef8d07db 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -943,3 +943,75 @@ pub struct AssocBoundOnConst { pub span: Span, pub descr: &'static str, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_inherent_ty_outside, code = "E0390")] +#[help] +pub struct InherentTyOutside { + #[primary_span] + #[help(hir_analysis_span_help)] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_inherent_ty_outside_relevant, code = "E0390")] +#[help] +pub struct InherentTyOutsideRelevant { + #[primary_span] + pub span: Span, + #[help(hir_analysis_span_help)] + pub help_span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_inherent_ty_outside_new, code = "E0116")] +#[note] +pub struct InherentTyOutsideNew { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_inherent_ty_outside_primitive, code = "E0390")] +#[help] +pub struct InherentTyOutsidePrimitive { + #[primary_span] + pub span: Span, + #[help(hir_analysis_span_help)] + pub help_span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_inherent_primitive_ty, code = "E0390")] +#[help] +pub struct InherentPrimitiveTy<'a> { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub note: Option>, +} + +#[derive(Subdiagnostic)] +#[note(hir_analysis_inherent_primitive_ty_note)] +pub struct InherentPrimitiveTyNote<'a> { + pub subty: Ty<'a>, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_inherent_dyn, code = "E0785")] +#[note] +pub struct InherentDyn { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_inherent_nominal, code = "E0118")] +#[note] +pub struct InherentNominal { + #[primary_span] + #[label] + pub span: Span, +} diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index b0f333b79ca..ef788935efb 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -117,7 +117,7 @@ use rustc_hir::def::DefKind; fluent_messages! { "../messages.ftl" } fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) { - const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `win64`, `sysv64` or `efiapi`"; + const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `aapcs`, `win64`, `sysv64` or `efiapi`"; const CONVENTIONS_STABLE: &str = "`C` or `cdecl`"; const UNSTABLE_EXPLAIN: &str = "using calling conventions other than `C` or `cdecl` for varargs functions is unstable"; diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 034ffc17a7a..921a5f5154a 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -16,6 +16,21 @@ hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}` *[other] , perhaps you need to restrict type parameter `{$action_or_ty}` with it } +hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool` + .suggestion = compare with zero instead + .help = compare with zero instead + .label = unsupported cast + +hir_typeck_cast_enum_drop = cannot cast enum `{$expr_ty}` into integer `{$cast_ty}` because it implements `Drop` + +hir_typeck_cast_unknown_pointer = cannot cast {$to -> + [true] to + *[false] from + } a pointer of an unknown kind + .label_to = needs more type information + .note = the type information given here is insufficient to check whether the pointer cast is valid + .label_from = the type information given here is insufficient to check whether the pointer cast is valid + hir_typeck_const_select_must_be_const = this argument must be a `const fn` .help = consult the documentation on `const_eval_select` for more information @@ -29,10 +44,16 @@ hir_typeck_convert_using_method = try using `{$sugg}` to convert `{$found}` to ` hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private +hir_typeck_deref_is_empty = this expression `Deref`s to `{$deref_ty}` which implements `is_empty` + hir_typeck_expected_default_return_type = expected `()` because of default return type hir_typeck_expected_return_type = expected `{$expected}` because of return type +hir_typeck_explicit_destructor = explicit use of destructor method + .label = explicit destructor calls not allowed + .suggestion = consider using `drop` function + hir_typeck_field_multiply_specified_in_initializer = field `{$ident}` specified more than once .label = used more than once @@ -52,8 +73,17 @@ hir_typeck_functional_record_update_on_non_struct = hir_typeck_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml` hir_typeck_help_set_edition_standalone = pass `--edition {$edition}` to `rustc` -hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize` +hir_typeck_int_to_fat = cannot cast `{$expr_ty}` to a pointer that {$known_wide -> + [true] is + *[false] may be + } wide +hir_typeck_int_to_fat_label = creating a `{$cast_ty}` requires both an address and {$metadata} +hir_typeck_int_to_fat_label_nightly = consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts` + +hir_typeck_invalid_callee = expected function, found {$ty} + +hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize` hir_typeck_lang_start_incorrect_number_params = incorrect number of parameters for the `start` lang item hir_typeck_lang_start_incorrect_number_params_note_expected_count = the `start` lang item should have four parameters, but found {$found_param_count} @@ -63,9 +93,22 @@ hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` la hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect .suggestion = change the type from `{$found_ty}` to `{$expected_ty}` +hir_typeck_lossy_provenance_int2ptr = + strict provenance disallows casting integer `{$expr_ty}` to pointer `{$cast_ty}` + .suggestion = use `.with_addr()` to adjust a valid pointer in the same allocation, to this address + .help = if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::from_exposed_addr()` instead + +hir_typeck_lossy_provenance_ptr2int = + under strict provenance it is considered bad style to cast pointer `{$expr_ty}` to integer `{$cast_ty}` + .suggestion = use `.addr()` to obtain the address of a pointer + .help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead + hir_typeck_method_call_on_unknown_raw_pointee = cannot call a method on a raw pointer with an unknown pointee type +hir_typeck_missing_fn_lang_items = failed to find an overloaded call trait for closure call + .help = make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods + hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}` hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method -> @@ -92,6 +135,9 @@ hir_typeck_return_stmt_outside_of_fn_body = .encl_body_label = the {$statement_kind} is part of this body... .encl_fn_label = ...not the enclosing function body +hir_typeck_rustcall_incorrect_args = + functions with the "rust-call" ABI must take a single non-self tuple argument + hir_typeck_struct_expr_non_exhaustive = cannot create non-exhaustive {$what} using struct expression @@ -101,8 +147,18 @@ hir_typeck_suggest_boxing_when_appropriate = store this in the heap by calling ` hir_typeck_suggest_ptr_null_mut = consider using `core::ptr::null_mut` instead +hir_typeck_trivial_cast = trivial {$numeric -> + [true] numeric cast + *[false] cast + }: `{$expr_ty}` as `{$cast_ty}` + .help = cast can be replaced by coercion; this might require a temporary variable + hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field + +hir_typeck_use_is_empty = + consider using the `is_empty` method on `{$expr_ty}` to determine if it contains anything + hir_typeck_yield_expr_outside_of_generator = yield expression outside of generator literal diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 02371f85ac3..b39919ece71 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -2,9 +2,9 @@ use super::method::probe::ProbeScope; use super::method::MethodCallee; use super::{Expectation, FnCtxt, TupleArgumentsFlag}; -use crate::type_error_struct; +use crate::errors; use rustc_ast::util::parser::PREC_POSTFIX; -use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, StashKey}; +use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, DefKind, Namespace, Res}; use rustc_hir::def_id::DefId; @@ -44,23 +44,15 @@ pub fn check_legal_trait_for_method_call( trait_id: DefId, ) { if tcx.lang_items().drop_trait() == Some(trait_id) { - let mut err = struct_span_err!(tcx.sess, span, E0040, "explicit use of destructor method"); - err.span_label(span, "explicit destructor calls not allowed"); - - let (sp, suggestion) = receiver - .and_then(|s| tcx.sess.source_map().span_to_snippet(s).ok()) - .filter(|snippet| !snippet.is_empty()) - .map(|snippet| (expr_span, format!("drop({snippet})"))) - .unwrap_or_else(|| (span, "drop".to_string())); - - err.span_suggestion( - sp, - "consider using `drop` function", - suggestion, - Applicability::MaybeIncorrect, - ); - - err.emit(); + let sugg = if let Some(receiver) = receiver.filter(|s| !s.is_empty()) { + errors::ExplicitDestructorCallSugg::Snippet { + lo: expr_span.shrink_to_lo(), + hi: receiver.shrink_to_hi().to(expr_span.shrink_to_hi()), + } + } else { + errors::ExplicitDestructorCallSugg::Empty(span) + }; + tcx.sess.emit_err(errors::ExplicitDestructorCall { span, sugg }); } } @@ -387,6 +379,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Unit testing: function items annotated with // `#[rustc_evaluate_where_clauses]` trigger special output // to let us test the trait evaluation system. + // Untranslatable diagnostics are okay for rustc internals + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) { let predicates = self.tcx.predicates_of(def_id); let predicates = predicates.instantiate(self.tcx, args); @@ -478,10 +473,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); self.require_type_is_sized(ty, sp, traits::RustCall); } else { - self.tcx.sess.span_err( - sp, - "functions with the \"rust-call\" ABI must take a single non-self tuple argument", - ); + self.tcx.sess.emit_err(errors::RustCallIncorrectArgs { span: sp }); } } @@ -610,17 +602,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let callee_ty = self.resolve_vars_if_possible(callee_ty); - let mut err = type_error_struct!( - self.tcx.sess, - callee_expr.span, - callee_ty, - E0618, - "expected function, found {}", - match &unit_variant { + let mut err = self.tcx.sess.create_err(errors::InvalidCallee { + span: callee_expr.span, + ty: match &unit_variant { Some((_, kind, path)) => format!("{kind} `{path}`"), None => format!("`{callee_ty}`"), - } - ); + }, + }); + if callee_ty.references_error() { + err.downgrade_to_delayed_bug(); + } self.identify_bad_closure_def_and_call( &mut err, @@ -891,15 +882,7 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> { None => { // This can happen if `#![no_core]` is used and the `fn/fn_mut/fn_once` // lang items are not defined (issue #86238). - let mut err = fcx.inh.tcx.sess.struct_span_err( - self.call_expr.span, - "failed to find an overloaded call trait for closure call", - ); - err.help( - "make sure the `fn`/`fn_mut`/`fn_once` lang items are defined \ - and have correctly defined `call`/`call_mut`/`call_once` methods", - ); - err.emit(); + fcx.inh.tcx.sess.emit_err(errors::MissingFnLangItems { span: self.call_expr.span }); } } } diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index e8d4e6b447f..fa779701e61 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -30,11 +30,10 @@ use super::FnCtxt; +use crate::errors; use crate::type_error_struct; use hir::ExprKind; -use rustc_errors::{ - struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, -}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::mir::Mutability; @@ -321,33 +320,15 @@ impl<'a, 'tcx> CastCheck<'tcx> { .emit(); } CastError::CastToBool => { - let mut err = struct_span_err!( - fcx.tcx.sess, - self.span, - E0054, - "cannot cast `{}` as `bool`", - self.expr_ty - ); - - if self.expr_ty.is_numeric() { - match fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) { - Ok(snippet) => { - err.span_suggestion( - self.span, - "compare with zero instead", - format!("{snippet} != 0"), - Applicability::MachineApplicable, - ); - } - Err(_) => { - err.span_help(self.span, "compare with zero instead"); - } - } + let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); + let help = if self.expr_ty.is_numeric() { + errors::CannotCastToBoolHelp::Numeric( + self.expr_span.shrink_to_hi().with_hi(self.span.hi()), + ) } else { - err.span_label(self.span, "unsupported cast"); - } - - err.emit(); + errors::CannotCastToBoolHelp::Unsupported(self.span) + }; + fcx.tcx.sess.emit_err(errors::CannotCastToBool { span: self.span, expr_ty, help }); } CastError::CastToChar => { let mut err = type_error_struct!( @@ -536,33 +517,20 @@ impl<'a, 'tcx> CastCheck<'tcx> { .emit(); } CastError::IntToFatCast(known_metadata) => { - let mut err = struct_span_err!( - fcx.tcx.sess, - self.cast_span, - E0606, - "cannot cast `{}` to a pointer that {} wide", - fcx.ty_to_string(self.expr_ty), - if known_metadata.is_some() { "is" } else { "may be" } - ); - - err.span_label( - self.cast_span, - format!( - "creating a `{}` requires both an address and {}", - self.cast_ty, - known_metadata.unwrap_or("type-specific metadata"), - ), - ); - - if fcx.tcx.sess.is_nightly_build() { - err.span_label( - self.expr_span, - "consider casting this expression to `*const ()`, \ - then using `core::ptr::from_raw_parts`", - ); - } - - err.emit(); + let expr_if_nightly = fcx.tcx.sess.is_nightly_build().then_some(self.expr_span); + let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); + let expr_ty = fcx.ty_to_string(self.expr_ty); + let metadata = known_metadata.unwrap_or("type-specific metadata"); + let known_wide = known_metadata.is_some(); + let span = self.cast_span; + fcx.tcx.sess.emit_err(errors::IntToWide { + span, + metadata, + expr_ty, + cast_ty, + expr_if_nightly, + known_wide, + }); } CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => { let unknown_cast_to = match e { @@ -570,27 +538,16 @@ impl<'a, 'tcx> CastCheck<'tcx> { CastError::UnknownExprPtrKind => false, _ => bug!(), }; - let mut err = struct_span_err!( - fcx.tcx.sess, - if unknown_cast_to { self.cast_span } else { self.span }, - E0641, - "cannot cast {} a pointer of an unknown kind", - if unknown_cast_to { "to" } else { "from" } - ); - if unknown_cast_to { - err.span_label(self.cast_span, "needs more type information"); - err.note( - "the type information given here is insufficient to check whether \ - the pointer cast is valid", - ); + let (span, sub) = if unknown_cast_to { + (self.cast_span, errors::CastUnknownPointerSub::To(self.cast_span)) } else { - err.span_label( - self.span, - "the type information given here is insufficient to check whether \ - the pointer cast is valid", - ); - } - err.emit(); + (self.cast_span, errors::CastUnknownPointerSub::From(self.span)) + }; + fcx.tcx.sess.emit_err(errors::CastUnknownPointer { + span, + to: unknown_cast_to, + sub, + }); } CastError::ForeignNonExhaustiveAdt => { make_invalid_casting_error( @@ -674,31 +631,18 @@ impl<'a, 'tcx> CastCheck<'tcx> { } fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) { - let t_cast = self.cast_ty; - let t_expr = self.expr_ty; - let (adjective, lint) = if t_cast.is_numeric() && t_expr.is_numeric() { - ("numeric ", lint::builtin::TRIVIAL_NUMERIC_CASTS) + let (numeric, lint) = if self.cast_ty.is_numeric() && self.expr_ty.is_numeric() { + (true, lint::builtin::TRIVIAL_NUMERIC_CASTS) } else { - ("", lint::builtin::TRIVIAL_CASTS) + (false, lint::builtin::TRIVIAL_CASTS) }; - fcx.tcx.struct_span_lint_hir( + let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); + let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); + fcx.tcx.emit_spanned_lint( lint, self.expr.hir_id, self.span, - DelayDm(|| { - format!( - "trivial {}cast: `{}` as `{}`", - adjective, - fcx.ty_to_string(t_expr), - fcx.ty_to_string(t_cast) - ) - }), - |lint| { - lint.help( - "cast can be replaced by coercion; this might \ - require a temporary variable", - ) - }, + errors::TrivialCast { numeric, expr_ty, cast_ty }, ); } @@ -991,93 +935,67 @@ impl<'a, 'tcx> CastCheck<'tcx> { if let ty::Adt(d, _) = self.expr_ty.kind() && d.has_dtor(fcx.tcx) { - fcx.tcx.struct_span_lint_hir( + let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); + let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); + + fcx.tcx.emit_spanned_lint( lint::builtin::CENUM_IMPL_DROP_CAST, self.expr.hir_id, self.span, - DelayDm(|| format!( - "cannot cast enum `{}` into integer `{}` because it implements `Drop`", - self.expr_ty, self.cast_ty - )), - |lint| { - lint - }, + errors::CastEnumDrop { + expr_ty, + cast_ty, + } ); } } fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::IntTy) { - fcx.tcx.struct_span_lint_hir( + let expr_prec = self.expr.precedence().order(); + let needs_parens = expr_prec < rustc_ast::util::parser::PREC_POSTFIX; + + let needs_cast = !matches!(t_c, ty::cast::IntTy::U(ty::UintTy::Usize)); + let cast_span = self.expr_span.shrink_to_hi().to(self.cast_span); + let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); + let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); + let expr_span = self.expr_span.shrink_to_lo(); + let sugg = match (needs_parens, needs_cast) { + (true, true) => errors::LossyProvenancePtr2IntSuggestion::NeedsParensCast { + expr_span, + cast_span, + cast_ty, + }, + (true, false) => { + errors::LossyProvenancePtr2IntSuggestion::NeedsParens { expr_span, cast_span } + } + (false, true) => { + errors::LossyProvenancePtr2IntSuggestion::NeedsCast { cast_span, cast_ty } + } + (false, false) => errors::LossyProvenancePtr2IntSuggestion::Other { cast_span }, + }; + + let lint = errors::LossyProvenancePtr2Int { expr_ty, cast_ty, sugg }; + fcx.tcx.emit_spanned_lint( lint::builtin::LOSSY_PROVENANCE_CASTS, self.expr.hir_id, self.span, - DelayDm(|| format!( - "under strict provenance it is considered bad style to cast pointer `{}` to integer `{}`", - self.expr_ty, self.cast_ty - )), - |lint| { - let msg = "use `.addr()` to obtain the address of a pointer"; - - let expr_prec = self.expr.precedence().order(); - let needs_parens = expr_prec < rustc_ast::util::parser::PREC_POSTFIX; - - let scalar_cast = match t_c { - ty::cast::IntTy::U(ty::UintTy::Usize) => String::new(), - _ => format!(" as {}", self.cast_ty), - }; - - let cast_span = self.expr_span.shrink_to_hi().to(self.cast_span); - - if needs_parens { - let suggestions = vec![ - (self.expr_span.shrink_to_lo(), String::from("(")), - (cast_span, format!(").addr(){scalar_cast}")), - ]; - - lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect); - } else { - lint.span_suggestion( - cast_span, - msg, - format!(".addr(){scalar_cast}"), - Applicability::MaybeIncorrect, - ); - } - - lint.help( - "if you can't comply with strict provenance and need to expose the pointer \ - provenance you can use `.expose_addr()` instead" - ); - - lint - }, + lint, ); } fn fuzzy_provenance_int2ptr_lint(&self, fcx: &FnCtxt<'a, 'tcx>) { - fcx.tcx.struct_span_lint_hir( + let sugg = errors::LossyProvenanceInt2PtrSuggestion { + lo: self.expr_span.shrink_to_lo(), + hi: self.expr_span.shrink_to_hi().to(self.cast_span), + }; + let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); + let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); + let lint = errors::LossyProvenanceInt2Ptr { expr_ty, cast_ty, sugg }; + fcx.tcx.emit_spanned_lint( lint::builtin::FUZZY_PROVENANCE_CASTS, self.expr.hir_id, self.span, - DelayDm(|| format!( - "strict provenance disallows casting integer `{}` to pointer `{}`", - self.expr_ty, self.cast_ty - )), - |lint| { - let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address"; - let suggestions = vec![ - (self.expr_span.shrink_to_lo(), String::from("(...).with_addr(")), - (self.expr_span.shrink_to_hi().to(self.cast_span), String::from(")")), - ]; - - lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect); - lint.help( - "if you can't comply with strict provenance and don't have a pointer with \ - the correct provenance you can use `std::ptr::from_exposed_addr()` instead" - ); - - lint - }, + lint, ); } @@ -1093,26 +1011,19 @@ impl<'a, 'tcx> CastCheck<'tcx> { if let Some((deref_ty, _)) = derefed { // Give a note about what the expr derefs to. if deref_ty != self.expr_ty.peel_refs() { - err.span_note( - self.expr_span, - format!( - "this expression `Deref`s to `{}` which implements `is_empty`", - fcx.ty_to_string(deref_ty) - ), - ); + err.subdiagnostic(errors::DerefImplsIsEmpty { + span: self.expr_span, + deref_ty: fcx.ty_to_string(deref_ty), + }); } // Create a multipart suggestion: add `!` and `.is_empty()` in // place of the cast. - let suggestion = vec![ - (self.expr_span.shrink_to_lo(), "!".to_string()), - (self.span.with_lo(self.expr_span.hi()), ".is_empty()".to_string()), - ]; - - err.multipart_suggestion_verbose(format!( - "consider using the `is_empty` method on `{}` to determine if it contains anything", - fcx.ty_to_string(self.expr_ty), - ), suggestion, Applicability::MaybeIncorrect); + err.subdiagnostic(errors::UseIsEmpty { + lo: self.expr_span.shrink_to_lo(), + hi: self.span.with_lo(self.expr_span.hi()), + expr_ty: fcx.ty_to_string(self.expr_ty), + }); } } } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 255fe5e0206..7152585d440 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -6,7 +6,7 @@ use rustc_errors::{ AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg, MultiSpan, SubdiagnosticMessage, }; -use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; use rustc_span::{ edition::{Edition, LATEST_STABLE_EDITION}, @@ -54,6 +54,13 @@ impl IntoDiagnosticArg for ReturnLikeStatementKind { } } +#[derive(Diagnostic)] +#[diag(hir_typeck_rustcall_incorrect_args)] +pub struct RustCallIncorrectArgs { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(hir_typeck_yield_expr_outside_of_generator, code = "E0627")] pub struct YieldExprOutsideOfGenerator { @@ -76,6 +83,14 @@ pub struct MethodCallOnUnknownRawPointee { pub span: Span, } +#[derive(Diagnostic)] +#[diag(hir_typeck_missing_fn_lang_items)] +#[help] +pub struct MissingFnLangItems { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(hir_typeck_functional_record_update_on_non_struct, code = "E0436")] pub struct FunctionalRecordUpdateOnNonStruct { @@ -129,6 +144,29 @@ pub enum ExpectedReturnTypeLabel<'tcx> { }, } +#[derive(Diagnostic)] +#[diag(hir_typeck_explicit_destructor, code = "E0040")] +pub struct ExplicitDestructorCall { + #[primary_span] + #[label] + pub span: Span, + #[subdiagnostic] + pub sugg: ExplicitDestructorCallSugg, +} + +#[derive(Subdiagnostic)] +pub enum ExplicitDestructorCallSugg { + #[suggestion(hir_typeck_suggestion, code = "drop", applicability = "maybe-incorrect")] + Empty(#[primary_span] Span), + #[multipart_suggestion(hir_typeck_suggestion, style = "short")] + Snippet { + #[suggestion_part(code = "drop(")] + lo: Span, + #[suggestion_part(code = ")")] + hi: Span, + }, +} + #[derive(Diagnostic)] #[diag(hir_typeck_missing_parentheses_in_range, code = "E0689")] pub struct MissingParenthesesInRange { @@ -231,6 +269,69 @@ pub struct LangStartIncorrectRetTy<'tcx> { pub found_ty: Ty<'tcx>, } +#[derive(LintDiagnostic)] +#[diag(hir_typeck_lossy_provenance_int2ptr)] +#[help] +pub struct LossyProvenanceInt2Ptr<'tcx> { + pub expr_ty: Ty<'tcx>, + pub cast_ty: Ty<'tcx>, + #[subdiagnostic] + pub sugg: LossyProvenanceInt2PtrSuggestion, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(hir_typeck_suggestion, applicability = "has-placeholders")] +pub struct LossyProvenanceInt2PtrSuggestion { + #[suggestion_part(code = "(...).with_addr(")] + pub lo: Span, + #[suggestion_part(code = ")")] + pub hi: Span, +} + +#[derive(LintDiagnostic)] +#[diag(hir_typeck_lossy_provenance_ptr2int)] +#[help] +pub struct LossyProvenancePtr2Int<'tcx> { + pub expr_ty: Ty<'tcx>, + pub cast_ty: Ty<'tcx>, + #[subdiagnostic] + pub sugg: LossyProvenancePtr2IntSuggestion<'tcx>, +} + +#[derive(Subdiagnostic)] +pub enum LossyProvenancePtr2IntSuggestion<'tcx> { + #[multipart_suggestion(hir_typeck_suggestion, applicability = "maybe-incorrect")] + NeedsParensCast { + #[suggestion_part(code = "(")] + expr_span: Span, + #[suggestion_part(code = ").addr() as {cast_ty}")] + cast_span: Span, + cast_ty: Ty<'tcx>, + }, + #[multipart_suggestion(hir_typeck_suggestion, applicability = "maybe-incorrect")] + NeedsParens { + #[suggestion_part(code = "(")] + expr_span: Span, + #[suggestion_part(code = ").addr()")] + cast_span: Span, + }, + #[suggestion( + hir_typeck_suggestion, + code = ".addr() as {cast_ty}", + applicability = "maybe-incorrect" + )] + NeedsCast { + #[primary_span] + cast_span: Span, + cast_ty: Ty<'tcx>, + }, + #[suggestion(hir_typeck_suggestion, code = ".addr()", applicability = "maybe-incorrect")] + Other { + #[primary_span] + cast_span: Span, + }, +} + #[derive(Subdiagnostic)] pub enum HelpUseLatestEdition { #[help(hir_typeck_help_set_edition_cargo)] @@ -252,6 +353,28 @@ impl HelpUseLatestEdition { } } +#[derive(Diagnostic)] +#[diag(hir_typeck_invalid_callee, code = "E0618")] +pub struct InvalidCallee { + #[primary_span] + pub span: Span, + pub ty: String, +} + +#[derive(Diagnostic)] +#[diag(hir_typeck_int_to_fat, code = "E0606")] +pub struct IntToWide<'tcx> { + #[primary_span] + #[label(hir_typeck_int_to_fat_label)] + pub span: Span, + pub metadata: &'tcx str, + pub expr_ty: String, + pub cast_ty: Ty<'tcx>, + #[label(hir_typeck_int_to_fat_label_nightly)] + pub expr_if_nightly: Option, + pub known_wide: bool, +} + #[derive(Subdiagnostic)] pub enum OptionResultRefMismatch { #[suggestion( @@ -350,6 +473,20 @@ pub struct UnionPatDotDot { pub span: Span, } +#[derive(Subdiagnostic)] +#[multipart_suggestion( + hir_typeck_use_is_empty, + applicability = "maybe-incorrect", + style = "verbose" +)] +pub struct UseIsEmpty { + #[suggestion_part(code = "!")] + pub lo: Span, + #[suggestion_part(code = ".is_empty()")] + pub hi: Span, + pub expr_ty: String, +} + #[derive(Diagnostic)] #[diag(hir_typeck_arg_mismatch_indeterminate)] pub struct ArgMismatchIndeterminate { @@ -396,6 +533,15 @@ pub struct SuggestPtrNullMut { pub span: Span, } +#[derive(LintDiagnostic)] +#[diag(hir_typeck_trivial_cast)] +#[help] +pub struct TrivialCast<'tcx> { + pub numeric: bool, + pub expr_ty: Ty<'tcx>, + pub cast_ty: Ty<'tcx>, +} + #[derive(Diagnostic)] #[diag(hir_typeck_no_associated_item, code = "E0599")] pub struct NoAssociatedItem { @@ -418,6 +564,74 @@ pub struct CandidateTraitNote { pub action_or_ty: String, } +#[derive(Diagnostic)] +#[diag(hir_typeck_cannot_cast_to_bool, code = "E0054")] +pub struct CannotCastToBool<'tcx> { + #[primary_span] + pub span: Span, + pub expr_ty: Ty<'tcx>, + #[subdiagnostic] + pub help: CannotCastToBoolHelp, +} + +#[derive(LintDiagnostic)] +#[diag(hir_typeck_cast_enum_drop)] +pub struct CastEnumDrop<'tcx> { + pub expr_ty: Ty<'tcx>, + pub cast_ty: Ty<'tcx>, +} + +#[derive(Diagnostic)] +#[diag(hir_typeck_cast_unknown_pointer, code = "E0641")] +pub struct CastUnknownPointer { + #[primary_span] + pub span: Span, + pub to: bool, + #[subdiagnostic] + pub sub: CastUnknownPointerSub, +} + +pub enum CastUnknownPointerSub { + To(Span), + From(Span), +} + +impl rustc_errors::AddToDiagnostic for CastUnknownPointerSub { + fn add_to_diagnostic_with(self, diag: &mut rustc_errors::Diagnostic, f: F) + where + F: Fn( + &mut Diagnostic, + rustc_errors::SubdiagnosticMessage, + ) -> rustc_errors::SubdiagnosticMessage, + { + match self { + CastUnknownPointerSub::To(span) => { + let msg = f(diag, crate::fluent_generated::hir_typeck_label_to.into()); + diag.span_label(span, msg); + let msg = f(diag, crate::fluent_generated::hir_typeck_note.into()); + diag.note(msg); + } + CastUnknownPointerSub::From(span) => { + let msg = f(diag, crate::fluent_generated::hir_typeck_label_from.into()); + diag.span_label(span, msg); + } + } + } +} + +#[derive(Subdiagnostic)] +pub enum CannotCastToBoolHelp { + #[suggestion( + hir_typeck_suggestion, + applicability = "machine-applicable", + code = " != 0", + style = "verbose" + )] + Numeric(#[primary_span] Span), + #[label(hir_typeck_label)] + Unsupported(#[primary_span] Span), +} + #[derive(Diagnostic)] #[diag(hir_typeck_ctor_is_private, code = "E0603")] pub struct CtorIsPrivate { @@ -426,6 +640,14 @@ pub struct CtorIsPrivate { pub def: String, } +#[derive(Subdiagnostic)] +#[note(hir_typeck_deref_is_empty)] +pub struct DerefImplsIsEmpty { + #[primary_span] + pub span: Span, + pub deref_ty: String, +} + #[derive(Subdiagnostic)] #[multipart_suggestion( hir_typeck_convert_using_method, diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 1a41786d251..ba469bd029d 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -195,7 +195,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { assert_eq!(self.tcx.hir().body_owner_def_id(body.id()), closure_def_id); let mut delegate = InferBorrowKind { - fcx: self, closure_def_id, capture_information: Default::default(), fake_reads: Default::default(), @@ -1607,34 +1606,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Truncate the capture so that the place being borrowed is in accordance with RFC 1240, /// which states that it's unsafe to take a reference into a struct marked `repr(packed)`. fn restrict_repr_packed_field_ref_capture<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, mut place: Place<'tcx>, mut curr_borrow_kind: ty::UpvarCapture, ) -> (Place<'tcx>, ty::UpvarCapture) { let pos = place.projections.iter().enumerate().position(|(i, p)| { let ty = place.ty_before_projection(i); - // Return true for fields of packed structs, unless those fields have alignment 1. + // Return true for fields of packed structs. match p.kind { ProjectionKind::Field(..) => match ty.kind() { ty::Adt(def, _) if def.repr().packed() => { - // We erase regions here because they cannot be hashed - match tcx.layout_of(param_env.and(tcx.erase_regions(p.ty))) { - Ok(layout) if layout.align.abi.bytes() == 1 => { - // if the alignment is 1, the type can't be further - // disaligned. - debug!( - "restrict_repr_packed_field_ref_capture: ({:?}) - align = 1", - place - ); - false - } - _ => { - debug!("restrict_repr_packed_field_ref_capture: ({:?}) - true", place); - true - } - } + // We stop here regardless of field alignment. Field alignment can change as + // types change, including the types of private fields in other crates, and that + // shouldn't affect how we compute our captures. + true } _ => false, @@ -1689,9 +1674,7 @@ fn drop_location_span(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> Span { tcx.sess.source_map().end_point(owner_span) } -struct InferBorrowKind<'a, 'tcx> { - fcx: &'a FnCtxt<'a, 'tcx>, - +struct InferBorrowKind<'tcx> { // The def-id of the closure whose kind and upvar accesses are being inferred. closure_def_id: LocalDefId, @@ -1725,7 +1708,7 @@ struct InferBorrowKind<'a, 'tcx> { fake_reads: Vec<(Place<'tcx>, FakeReadCause, hir::HirId)>, } -impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { +impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> { fn fake_read( &mut self, place: &PlaceWithHirId<'tcx>, @@ -1740,12 +1723,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { let (place, _) = restrict_capture_precision(place.place.clone(), dummy_capture_kind); - let (place, _) = restrict_repr_packed_field_ref_capture( - self.fcx.tcx, - self.fcx.param_env, - place, - dummy_capture_kind, - ); + let (place, _) = restrict_repr_packed_field_ref_capture(place, dummy_capture_kind); self.fake_reads.push((place, cause, diag_expr_id)); } @@ -1780,12 +1758,8 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { // We only want repr packed restriction to be applied to reading references into a packed // struct, and not when the data is being moved. Therefore we call this method here instead // of in `restrict_capture_precision`. - let (place, mut capture_kind) = restrict_repr_packed_field_ref_capture( - self.fcx.tcx, - self.fcx.param_env, - place_with_id.place.clone(), - capture_kind, - ); + let (place, mut capture_kind) = + restrict_repr_packed_field_ref_capture(place_with_id.place.clone(), capture_kind); // Raw pointers don't inherit mutability if place_with_id.place.deref_tys().any(Ty::is_unsafe_ptr) { 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 f903f7a49ef..4aec28b051f 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 @@ -385,7 +385,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { let highlight_trait_ref = |trait_ref| Highlighted { tcx: self.tcx(), - highlight: RegionHighlightMode::new(self.tcx()), + highlight: RegionHighlightMode::default(), value: trait_ref, }; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 12d38ced030..d2ba9966f03 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -67,9 +67,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } impl<'tcx> HighlightBuilder<'tcx> { - fn build(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> RegionHighlightMode<'tcx> { + fn build(ty: Ty<'tcx>) -> RegionHighlightMode<'tcx> { let mut builder = - HighlightBuilder { highlight: RegionHighlightMode::new(tcx), counter: 1 }; + HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1 }; builder.visit_ty(ty); builder.highlight } @@ -85,12 +85,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } } - let expected_highlight = HighlightBuilder::build(self.tcx(), expected); + let expected_highlight = HighlightBuilder::build(expected); let expected = self .cx .extract_inference_diagnostics_data(expected.into(), Some(expected_highlight)) .name; - let found_highlight = HighlightBuilder::build(self.tcx(), found); + let found_highlight = HighlightBuilder::build(found); let found = self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name; diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs index 2402a7ea7c7..ed1a2a11719 100644 --- a/compiler/rustc_infer/src/infer/free_regions.rs +++ b/compiler/rustc_infer/src/infer/free_regions.rs @@ -4,7 +4,7 @@ //! and use that to decide when one free region outlives another, and so forth. use rustc_data_structures::transitive_relation::TransitiveRelation; -use rustc_middle::ty::{Lift, Region, TyCtxt}; +use rustc_middle::ty::{Region, TyCtxt}; /// Combines a `FreeRegionMap` and a `TyCtxt`. /// @@ -101,10 +101,3 @@ impl<'tcx> FreeRegionMap<'tcx> { result } } - -impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> { - type Lifted = FreeRegionMap<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option> { - self.relation.maybe_map(|fr| tcx.lift(fr)).map(|relation| FreeRegionMap { relation }) - } -} diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 3706c9646af..4cf9d44ed65 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1600,9 +1600,12 @@ impl<'tcx> InferCtxt<'tcx> { if let Some(ct) = tcx.thir_abstract_const(unevaluated.def)? { let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, args)); if let Err(e) = ct.error_reported() { - return Err(ErrorHandled::Reported(e.into())); + return Err(ErrorHandled::Reported( + e.into(), + span.unwrap_or(rustc_span::DUMMY_SP), + )); } else if ct.has_non_region_infer() || ct.has_non_region_param() { - return Err(ErrorHandled::TooGeneric); + return Err(ErrorHandled::TooGeneric(span.unwrap_or(rustc_span::DUMMY_SP))); } else { args = replace_param_and_infer_args_with_placeholder(tcx, args); } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 37e242c6e40..0634e44c562 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -568,6 +568,13 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu ) { sess.emit_fatal(errors::MultipleOutputTypesToStdout); } + + let crate_name = sess + .opts + .crate_name + .clone() + .or_else(|| rustc_attr::find_crate_name(attrs).map(|n| n.to_string())); + match sess.io.output_file { None => { // "-" as input file will cause the parser to read from stdin so we @@ -576,15 +583,11 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu let dirpath = sess.io.output_dir.clone().unwrap_or_default(); // If a crate name is present, we use it as the link name - let stem = sess - .opts - .crate_name - .clone() - .or_else(|| rustc_attr::find_crate_name(attrs).map(|n| n.to_string())) - .unwrap_or_else(|| sess.io.input.filestem().to_owned()); + let stem = crate_name.clone().unwrap_or_else(|| sess.io.input.filestem().to_owned()); OutputFilenames::new( dirpath, + crate_name.unwrap_or_else(|| stem.replace('-', "_")), stem, None, sess.io.temps_dir.clone(), @@ -609,9 +612,12 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu sess.emit_warning(errors::IgnoringOutDir); } + let out_filestem = + out_file.filestem().unwrap_or_default().to_str().unwrap().to_string(); OutputFilenames::new( out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(), - out_file.filestem().unwrap_or_default().to_str().unwrap().to_string(), + crate_name.unwrap_or_else(|| out_filestem.replace('-', "_")), + out_filestem, ofile, sess.io.temps_dir.clone(), sess.opts.cg.extra_filename.clone(), diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index ba50c9e00e3..7377c6e2f35 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -453,6 +453,8 @@ lint_ptr_null_checks_fn_ptr = function pointers are not nullable, so checking th .help = wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value .label = expression has type `{$orig_ty}` +lint_ptr_null_checks_fn_ret = returned pointer of `{$fn_name}` call is never null, so checking it for null will always return false + lint_ptr_null_checks_ref = references are not nullable, so checking them for null will always return false .label = expression has type `{$orig_ty}` diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 3e26d6dc32d..c091c260a47 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -635,6 +635,8 @@ pub enum PtrNullChecksDiag<'a> { #[label] label: Span, }, + #[diag(lint_ptr_null_checks_fn_ret)] + FnRet { fn_name: Ident }, } // for_loops_over_fallibles.rs diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs index 02aff91032f..0de72d8d3db 100644 --- a/compiler/rustc_lint/src/ptr_nulls.rs +++ b/compiler/rustc_lint/src/ptr_nulls.rs @@ -31,12 +31,30 @@ declare_lint! { declare_lint_pass!(PtrNullChecks => [USELESS_PTR_NULL_CHECKS]); -/// This function detects and returns the original expression from a series of consecutive casts, -/// ie. `(my_fn as *const _ as *mut _).cast_mut()` would return the expression for `my_fn`. -fn ptr_cast_chain<'a>(cx: &'a LateContext<'_>, mut e: &'a Expr<'a>) -> Option<&'a Expr<'a>> { +/// This function checks if the expression is from a series of consecutive casts, +/// ie. `(my_fn as *const _ as *mut _).cast_mut()` and whether the original expression is either +/// a fn ptr, a reference, or a function call whose definition is +/// annotated with `#![rustc_never_returns_null_ptr]`. +/// If this situation is present, the function returns the appropriate diagnostic. +fn incorrect_check<'a, 'tcx: 'a>( + cx: &'a LateContext<'tcx>, + mut e: &'a Expr<'a>, +) -> Option> { let mut had_at_least_one_cast = false; loop { e = e.peel_blocks(); + 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) { + 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) { + return Some(PtrNullChecksDiag::FnRet { fn_name }); + } e = if let ExprKind::Cast(expr, t) = e.kind && let TyKind::Ptr(_) = t.kind { had_at_least_one_cast = true; @@ -46,33 +64,21 @@ fn ptr_cast_chain<'a>(cx: &'a LateContext<'_>, mut e: &'a Expr<'a>) -> Option<&' && 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 let ExprKind::Call(path, [arg]) = 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_from_ref | sym::ptr_from_mut)) { - had_at_least_one_cast = true; - arg } else if had_at_least_one_cast { - return Some(e); + let orig_ty = cx.typeck_results().expr_ty(e); + return if orig_ty.is_fn() { + Some(PtrNullChecksDiag::FnPtr { orig_ty, label: e.span }) + } else if orig_ty.is_ref() { + Some(PtrNullChecksDiag::Ref { orig_ty, label: e.span }) + } else { + None + }; } else { return None; }; } } -fn incorrect_check<'a>(cx: &LateContext<'a>, expr: &Expr<'_>) -> Option> { - let expr = ptr_cast_chain(cx, expr)?; - - let orig_ty = cx.typeck_results().expr_ty(expr); - if orig_ty.is_fn() { - Some(PtrNullChecksDiag::FnPtr { orig_ty, label: expr.span }) - } else if orig_ty.is_ref() { - Some(PtrNullChecksDiag::Ref { orig_ty, label: expr.span }) - } else { - None - } -} - impl<'tcx> LateLintPass<'tcx> for PtrNullChecks { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { match expr.kind { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 672a7a20148..860366fdd61 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3405,8 +3405,8 @@ declare_lint_pass! { UNFULFILLED_LINT_EXPECTATIONS, UNINHABITED_STATIC, UNKNOWN_CRATE_TYPES, - UNKNOWN_DIAGNOSTIC_ATTRIBUTES, UNKNOWN_LINTS, + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNNAMEABLE_TEST_ITEMS, UNNAMEABLE_TYPES, UNREACHABLE_CODE, @@ -4420,7 +4420,8 @@ declare_lint! { } declare_lint! { - /// The `unknown_diagnostic_attributes` lint detects unrecognized diagnostic attributes. + /// The `unknown_or_malformed_diagnostic_attributes` lint detects unrecognized or otherwise malformed + /// diagnostic attributes. /// /// ### Example /// @@ -4432,15 +4433,17 @@ declare_lint! { /// /// {{produces}} /// + /// /// ### Explanation /// /// It is usually a mistake to specify a diagnostic attribute that does not exist. Check /// the spelling, and check the diagnostic attribute listing for the correct name. Also /// consider if you are using an old version of the compiler, and the attribute /// is only available in a newer version. - pub UNKNOWN_DIAGNOSTIC_ATTRIBUTES, + pub UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, Warn, - "unrecognized diagnostic attribute" + "unrecognized or malformed diagnostic attribute", + @feature_gate = sym::diagnostic_namespace; } declare_lint! { diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index fefb1e0fbe0..461b5290e69 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -239,16 +239,22 @@ enum class LLVMRustCodeGenOptLevel { Aggressive, }; -static CodeGenOpt::Level fromRust(LLVMRustCodeGenOptLevel Level) { +#if LLVM_VERSION_GE(18, 0) + using CodeGenOptLevelEnum = llvm::CodeGenOptLevel; +#else + using CodeGenOptLevelEnum = llvm::CodeGenOpt::Level; +#endif + +static CodeGenOptLevelEnum fromRust(LLVMRustCodeGenOptLevel Level) { switch (Level) { case LLVMRustCodeGenOptLevel::None: - return CodeGenOpt::None; + return CodeGenOptLevelEnum::None; case LLVMRustCodeGenOptLevel::Less: - return CodeGenOpt::Less; + return CodeGenOptLevelEnum::Less; case LLVMRustCodeGenOptLevel::Default: - return CodeGenOpt::Default; + return CodeGenOptLevelEnum::Default; case LLVMRustCodeGenOptLevel::Aggressive: - return CodeGenOpt::Aggressive; + return CodeGenOptLevelEnum::Aggressive; default: report_fatal_error("Bad CodeGenOptLevel."); } @@ -554,9 +560,17 @@ enum class LLVMRustFileType { static CodeGenFileType fromRust(LLVMRustFileType Type) { switch (Type) { case LLVMRustFileType::AssemblyFile: +#if LLVM_VERSION_GE(18, 0) + return CodeGenFileType::AssemblyFile; +#else return CGFT_AssemblyFile; +#endif case LLVMRustFileType::ObjectFile: +#if LLVM_VERSION_GE(18, 0) + return CodeGenFileType::ObjectFile; +#else return CGFT_ObjectFile; +#endif default: report_fatal_error("Bad FileType."); } diff --git a/compiler/rustc_metadata/src/fs.rs b/compiler/rustc_metadata/src/fs.rs index 2a9662b809a..7eb2a347db2 100644 --- a/compiler/rustc_metadata/src/fs.rs +++ b/compiler/rustc_metadata/src/fs.rs @@ -5,7 +5,6 @@ use crate::errors::{ use crate::{encode_metadata, EncodedMetadata}; use rustc_data_structures::temp_dir::MaybeTempDir; -use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; use rustc_session::config::{OutFileName, OutputType}; use rustc_session::output::filename_for_metadata; @@ -40,8 +39,7 @@ pub fn emit_wrapper_file( } pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) { - let crate_name = tcx.crate_name(LOCAL_CRATE); - let out_filename = filename_for_metadata(tcx.sess, crate_name, tcx.output_filenames(())); + let out_filename = filename_for_metadata(tcx.sess, tcx.output_filenames(())); // To avoid races with another rustc process scanning the output directory, // we need to write the file somewhere else and atomically move it to its // final destination, with an `fs::rename` call. In order for the rename to diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index 108a10b506b..82162fd8571 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -52,6 +52,8 @@ middle_drop_check_overflow = overflow while adding drop-check rules for {$ty} .note = overflowed on {$overflow_ty} +middle_erroneous_constant = erroneous constant encountered + middle_layout_references_error = the type has an unknown layout diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index b346cd45391..3c553657087 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -144,5 +144,12 @@ pub struct UnsupportedFnAbi { pub abi: &'static str, } +#[derive(Diagnostic)] +#[diag(middle_erroneous_constant)] +pub struct ErroneousConstant { + #[primary_span] + pub span: Span, +} + /// Used by `rustc_const_eval` pub use crate::fluent_generated::middle_adjust_for_foreign_abi_error; diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index b17f1512886..2f2597d6b22 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -34,7 +34,7 @@ use std::ops::Index; /// variables have been rewritten to "canonical vars". These are /// numbered starting from 0 in order of first appearance. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct Canonical<'tcx, V> { pub value: V, pub max_universe: ty::UniverseIndex, @@ -72,7 +72,7 @@ impl<'tcx> ty::TypeFoldable> for CanonicalVarInfos<'tcx> { /// variables. You will need to supply it later to instantiate the /// canonicalized query response. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct CanonicalVarValues<'tcx> { pub var_values: ty::GenericArgsRef<'tcx>, } @@ -311,7 +311,7 @@ pub enum CanonicalTyVarKind { /// After we execute a query with a canonicalized key, we get back a /// `Canonical>`. You can use /// `instantiate_query_result` to access the data in this result. -#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)] +#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct QueryResponse<'tcx, R> { pub var_values: CanonicalVarValues<'tcx>, pub region_constraints: QueryRegionConstraints<'tcx>, @@ -326,7 +326,7 @@ pub struct QueryResponse<'tcx, R> { } #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct QueryRegionConstraints<'tcx> { pub outlives: Vec>, pub member_constraints: Vec>, @@ -432,7 +432,7 @@ impl<'tcx, V> Canonical<'tcx, V> { pub type QueryOutlivesConstraint<'tcx> = (ty::OutlivesPredicate, Region<'tcx>>, ConstraintCategory<'tcx>); -TrivialTypeTraversalAndLiftImpls! { +TrivialTypeTraversalImpls! { crate::infer::canonical::Certainty, crate::infer::canonical::CanonicalTyVarKind, } diff --git a/compiler/rustc_middle/src/infer/mod.rs b/compiler/rustc_middle/src/infer/mod.rs index 493bb8a6823..1384611e146 100644 --- a/compiler/rustc_middle/src/infer/mod.rs +++ b/compiler/rustc_middle/src/infer/mod.rs @@ -13,7 +13,7 @@ use rustc_span::Span; /// R0 member of [O1..On] /// ``` #[derive(Debug, Clone, PartialEq, Eq, Hash)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct MemberConstraint<'tcx> { /// The `DefId` and args of the opaque type causing this constraint. /// Used for error reporting. diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index fca16d8e509..c1884bb8068 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -42,7 +42,7 @@ macro_rules! span_bug { // the impls for you. #[macro_export] -macro_rules! CloneLiftImpls { +macro_rules! TrivialLiftImpls { ($($ty:ty),+ $(,)?) => { $( impl<'tcx> $crate::ty::Lift<'tcx> for $ty { @@ -96,6 +96,6 @@ macro_rules! TrivialTypeTraversalImpls { macro_rules! TrivialTypeTraversalAndLiftImpls { ($($t:tt)*) => { TrivialTypeTraversalImpls! { $($t)* } - CloneLiftImpls! { $($t)* } + TrivialLiftImpls! { $($t)* } } } diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 70d8f3bd54b..cd770c395e4 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -178,7 +178,7 @@ impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> { } } -TrivialTypeTraversalAndLiftImpls! { Cache } +TrivialTypeTraversalImpls! { Cache } impl Encodable for Cache { #[inline] diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 7e3be0b5d5f..eb4614745d5 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,8 +1,9 @@ use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar}; +use crate::error; use crate::mir::interpret::ConstValue; use crate::query::TyCtxtAt; -use crate::ty::{layout, tls, Ty, ValTree}; +use crate::ty::{layout, tls, Ty, TyCtxt, ValTree}; use rustc_data_structures::sync::Lock; use rustc_errors::{ @@ -11,7 +12,7 @@ use rustc_errors::{ }; use rustc_macros::HashStable; use rustc_session::CtfeBacktrace; -use rustc_span::def_id::DefId; +use rustc_span::{def_id::DefId, Span, DUMMY_SP}; use rustc_target::abi::{call, Align, Size, VariantIdx, WrappingRange}; use std::borrow::Cow; @@ -21,16 +22,51 @@ use std::{any::Any, backtrace::Backtrace, fmt}; pub enum ErrorHandled { /// Already reported an error for this evaluation, and the compilation is /// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`. - Reported(ReportedErrorInfo), + Reported(ReportedErrorInfo, Span), /// Don't emit an error, the evaluation failed because the MIR was generic /// and the args didn't fully monomorphize it. - TooGeneric, + TooGeneric(Span), } impl From for ErrorHandled { #[inline] fn from(error: ErrorGuaranteed) -> ErrorHandled { - ErrorHandled::Reported(error.into()) + ErrorHandled::Reported(error.into(), DUMMY_SP) + } +} + +impl ErrorHandled { + pub fn with_span(self, span: Span) -> Self { + match self { + ErrorHandled::Reported(err, _span) => ErrorHandled::Reported(err, span), + ErrorHandled::TooGeneric(_span) => ErrorHandled::TooGeneric(span), + } + } + + pub fn emit_err(&self, tcx: TyCtxt<'_>) -> ErrorGuaranteed { + match self { + &ErrorHandled::Reported(err, span) => { + if !err.is_tainted_by_errors && !span.is_dummy() { + tcx.sess.emit_err(error::ErroneousConstant { span }); + } + err.error + } + &ErrorHandled::TooGeneric(span) => tcx.sess.delay_span_bug( + span, + "encountered TooGeneric error when monomorphic data was expected", + ), + } + } + + pub fn emit_note(&self, tcx: TyCtxt<'_>) { + match self { + &ErrorHandled::Reported(err, span) => { + if !err.is_tainted_by_errors && !span.is_dummy() { + tcx.sess.emit_note(error::ErroneousConstant { span }); + } + } + &ErrorHandled::TooGeneric(_) => {} + } } } @@ -45,12 +81,6 @@ impl ReportedErrorInfo { pub fn tainted_by_errors(error: ErrorGuaranteed) -> ReportedErrorInfo { ReportedErrorInfo { is_tainted_by_errors: true, error } } - - /// Returns true if evaluation failed because MIR was tainted by errors. - #[inline] - pub fn is_tainted_by_errors(self) -> bool { - self.is_tainted_by_errors - } } impl From for ReportedErrorInfo { @@ -67,7 +97,7 @@ impl Into for ReportedErrorInfo { } } -TrivialTypeTraversalAndLiftImpls! { ErrorHandled } +TrivialTypeTraversalImpls! { ErrorHandled } pub type EvalToAllocationRawResult<'tcx> = Result, ErrorHandled>; pub type EvalToConstValueResult<'tcx> = Result, ErrorHandled>; @@ -162,6 +192,16 @@ impl From for InterpErrorInfo<'_> { } } +impl From for InterpErrorInfo<'_> { + fn from(err: ErrorHandled) -> Self { + InterpError::InvalidProgram(match err { + ErrorHandled::Reported(r, _span) => InvalidProgramInfo::AlreadyReported(r), + ErrorHandled::TooGeneric(_span) => InvalidProgramInfo::TooGeneric, + }) + .into() + } +} + impl<'tcx> From> for InterpErrorInfo<'tcx> { fn from(kind: InterpError<'tcx>) -> Self { InterpErrorInfo(Box::new(InterpErrorInfoInner { diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 44d1dcbbe17..8c00746a180 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -162,7 +162,7 @@ pub use self::pointer::{Pointer, PointerArithmetic, Provenance}; /// - A constant /// - A static #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, Lift, TypeFoldable, TypeVisitable)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct GlobalId<'tcx> { /// For a constant or static, the `Instance` of the item itself. /// For a promoted global, the `Instance` of the function they belong to. diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index fc659ce18a4..fbf6403eabe 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -61,8 +61,10 @@ impl<'tcx> TyCtxt<'tcx> { let cid = GlobalId { instance, promoted: ct.promoted }; self.const_eval_global_id(param_env, cid, span) } - Ok(None) => Err(ErrorHandled::TooGeneric), - Err(err) => Err(ErrorHandled::Reported(err.into())), + // For errors during resolution, we deliberately do not point at the usage site of the constant, + // since for these errors the place the constant is used shouldn't matter. + Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)), + Err(err) => Err(ErrorHandled::Reported(err.into(), DUMMY_SP)), } } @@ -117,8 +119,10 @@ impl<'tcx> TyCtxt<'tcx> { } }) } - Ok(None) => Err(ErrorHandled::TooGeneric), - Err(err) => Err(ErrorHandled::Reported(err.into())), + // For errors during resolution, we deliberately do not point at the usage site of the constant, + // since for these errors the place the constant is used shouldn't matter. + Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)), + Err(err) => Err(ErrorHandled::Reported(err.into(), DUMMY_SP)), } } @@ -143,7 +147,8 @@ impl<'tcx> TyCtxt<'tcx> { // improve caching of queries. let inputs = self.erase_regions(param_env.and(cid)); if let Some(span) = span { - self.at(span).eval_to_const_value_raw(inputs) + // The query doesn't know where it is being invoked, so we need to fix the span. + self.at(span).eval_to_const_value_raw(inputs).map_err(|e| e.with_span(span)) } else { self.eval_to_const_value_raw(inputs) } @@ -162,7 +167,8 @@ impl<'tcx> TyCtxt<'tcx> { let inputs = self.erase_regions(param_env.and(cid)); debug!(?inputs); if let Some(span) = span { - self.at(span).eval_to_valtree(inputs) + // The query doesn't know where it is being invoked, so we need to fix the span. + self.at(span).eval_to_valtree(inputs).map_err(|e| e.with_span(span)) } else { self.eval_to_valtree(inputs) } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 8df3a79b4d4..b8032733868 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -565,6 +565,34 @@ impl<'tcx> Body<'tcx> { pub fn is_custom_mir(&self) -> bool { self.injection_phase.is_some() } + + /// *Must* be called once the full substitution for this body is known, to ensure that the body + /// is indeed fit for code generation or consumption more generally. + /// + /// Sadly there's no nice way to represent an "arbitrary normalizer", so we take one for + /// constants specifically. (`Option` could be used for that, but the fact + /// that `Instance::args_for_mir_body` is private and instead instance exposes normalization + /// functions makes it seem like exposing the generic args is not the intended strategy.) + /// + /// Also sadly, CTFE doesn't even know whether it runs on MIR that is already polymorphic or still monomorphic, + /// so we cannot just immediately ICE on TooGeneric. + /// + /// Returns Ok(()) if everything went fine, and `Err` if a problem occurred and got reported. + pub fn post_mono_checks( + &self, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + normalize_const: impl Fn(ConstantKind<'tcx>) -> Result, ErrorHandled>, + ) -> Result<(), ErrorHandled> { + // For now, the only thing we have to check is is to ensure that all the constants used in + // the body successfully evaluate. + for &const_ in &self.required_consts { + let c = normalize_const(const_.literal)?; + c.eval(tcx, param_env, Some(const_.span))?; + } + + Ok(()) + } } #[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)] @@ -744,7 +772,7 @@ pub enum BindingForm<'tcx> { RefForGuard, } -TrivialTypeTraversalAndLiftImpls! { BindingForm<'tcx> } +TrivialTypeTraversalImpls! { BindingForm<'tcx> } mod binding_form_impl { use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -2295,7 +2323,7 @@ pub struct Constant<'tcx> { } #[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)] -#[derive(Lift, TypeFoldable, TypeVisitable)] +#[derive(TypeFoldable, TypeVisitable)] pub enum ConstantKind<'tcx> { /// This constant came from the type system. /// @@ -2397,10 +2425,10 @@ impl<'tcx> ConstantKind<'tcx> { pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self { match self.eval(tcx, param_env, None) { Ok(val) => Self::Val(val, self.ty()), - Err(ErrorHandled::Reported(guar)) => { + Err(ErrorHandled::Reported(guar, _span)) => { Self::Ty(ty::Const::new_error(tcx, guar.into(), self.ty())) } - Err(ErrorHandled::TooGeneric) => self, + Err(ErrorHandled::TooGeneric(_span)) => self, } } @@ -2615,7 +2643,7 @@ impl<'tcx> ConstantKind<'tcx> { } /// An unevaluated (potentially generic) constant used in MIR. -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] #[derive(Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct UnevaluatedConst<'tcx> { pub def: DefId, diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 71bec49af93..0c80610b308 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -334,7 +334,7 @@ rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16); /// /// See also `rustc_const_eval::borrow_check::constraints`. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] -#[derive(TyEncodable, TyDecodable, HashStable, Lift, TypeVisitable, TypeFoldable)] +#[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)] pub enum ConstraintCategory<'tcx> { Return(ReturnConstraint), Yield, diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index 06874741bb0..8d427fdb6f5 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -5,7 +5,7 @@ use rustc_ast::InlineAsmTemplatePiece; use super::*; use crate::ty; -TrivialTypeTraversalAndLiftImpls! { +TrivialTypeTraversalImpls! { BlockTailInfo, MirPhase, SourceInfo, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index bf340846f10..9e358ea4eba 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1140,6 +1140,7 @@ rustc_queries! { query reachable_set(_: ()) -> &'tcx LocalDefIdSet { arena_cache desc { "reachability" } + cache_on_disk_if { true } } /// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body; diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 3465759b913..1340e674568 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -13,7 +13,7 @@ use crate::infer::canonical::Canonical; use crate::mir::ConstraintCategory; use crate::ty::abstract_const::NotConstEvaluatable; use crate::ty::GenericArgsRef; -use crate::ty::{self, AdtKind, Ty, TyCtxt}; +use crate::ty::{self, AdtKind, Ty}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diagnostic}; @@ -86,7 +86,7 @@ pub enum Reveal { /// /// We do not want to intern this as there are a lot of obligation causes which /// only live for a short period of time. -#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)] +#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] #[derive(TypeVisitable, TypeFoldable)] pub struct ObligationCause<'tcx> { pub span: Span, @@ -194,7 +194,7 @@ impl<'tcx> ObligationCause<'tcx> { } } -#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)] +#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] #[derive(TypeVisitable, TypeFoldable)] pub struct UnifyReceiverContext<'tcx> { pub assoc_item: ty::AssocItem, @@ -202,7 +202,7 @@ pub struct UnifyReceiverContext<'tcx> { pub args: GenericArgsRef<'tcx>, } -#[derive(Clone, PartialEq, Eq, Lift, Default, HashStable)] +#[derive(Clone, PartialEq, Eq, Default, HashStable)] #[derive(TypeVisitable, TypeFoldable, TyEncodable, TyDecodable)] pub struct InternedObligationCauseCode<'tcx> { /// `None` for `ObligationCauseCode::MiscObligation` (a common case, occurs ~60% of @@ -238,7 +238,7 @@ impl<'tcx> std::ops::Deref for InternedObligationCauseCode<'tcx> { } } -#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)] +#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] #[derive(TypeVisitable, TypeFoldable)] pub enum ObligationCauseCode<'tcx> { /// Not well classified or should be obvious from the span. @@ -470,7 +470,7 @@ pub enum WellFormedLoc { }, } -#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)] +#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] #[derive(TypeVisitable, TypeFoldable)] pub struct ImplDerivedObligationCause<'tcx> { pub derived: DerivedObligationCause<'tcx>, @@ -524,14 +524,7 @@ pub enum StatementAsExpression { NeedsBoxing, } -impl<'tcx> ty::Lift<'tcx> for StatementAsExpression { - type Lifted = StatementAsExpression; - fn lift_to_tcx(self, _tcx: TyCtxt<'tcx>) -> Option { - Some(self) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)] +#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] #[derive(TypeVisitable, TypeFoldable)] pub struct MatchExpressionArmCause<'tcx> { pub arm_block_id: Option, @@ -547,7 +540,7 @@ pub struct MatchExpressionArmCause<'tcx> { } #[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[derive(Lift, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)] +#[derive(TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)] pub struct IfExpressionCause<'tcx> { pub then_id: hir::HirId, pub else_id: hir::HirId, @@ -557,7 +550,7 @@ pub struct IfExpressionCause<'tcx> { pub opt_suggest_box_span: Option, } -#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)] +#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] #[derive(TypeVisitable, TypeFoldable)] pub struct DerivedObligationCause<'tcx> { /// The trait predicate of the parent obligation that led to the @@ -570,7 +563,7 @@ pub struct DerivedObligationCause<'tcx> { pub parent_code: InternedObligationCauseCode<'tcx>, } -#[derive(Clone, Debug, TypeVisitable, Lift)] +#[derive(Clone, Debug, TypeVisitable)] pub enum SelectionError<'tcx> { /// The trait is not implemented. Unimplemented, @@ -593,7 +586,7 @@ pub enum SelectionError<'tcx> { OpaqueTypeAutoTraitLeakageUnknown(DefId), } -#[derive(Clone, Debug, TypeVisitable, Lift)] +#[derive(Clone, Debug, TypeVisitable)] pub struct SelectionOutputTypeParameterMismatch<'tcx> { pub found_trait_ref: ty::PolyTraitRef<'tcx>, pub expected_trait_ref: ty::PolyTraitRef<'tcx>, @@ -638,7 +631,7 @@ pub type SelectionResult<'tcx, T> = Result, SelectionError<'tcx>>; /// ### The type parameter `N` /// /// See explanation on `ImplSourceUserDefinedData`. -#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] +#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] #[derive(TypeFoldable, TypeVisitable)] pub enum ImplSource<'tcx, N> { /// ImplSource identifying a particular impl. @@ -704,7 +697,7 @@ impl<'tcx, N> ImplSource<'tcx, N> { /// is `Obligation`, as one might expect. During codegen, however, this /// is `()`, because codegen only requires a shallow resolution of an /// impl, and nested obligations are satisfied later. -#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] +#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] #[derive(TypeFoldable, TypeVisitable)] pub struct ImplSourceUserDefinedData<'tcx, N> { pub impl_def_id: DefId, @@ -736,7 +729,7 @@ pub enum BuiltinImplSource { TupleUnsizing, } -TrivialTypeTraversalAndLiftImpls! { BuiltinImplSource } +TrivialTypeTraversalImpls! { BuiltinImplSource } #[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)] pub enum ObjectSafetyViolation { diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 950a59e9695..975e3e3ac62 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -17,8 +17,7 @@ pub mod type_op { use crate::ty::{Predicate, Ty, TyCtxt, UserType}; use std::fmt; - #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)] - #[derive(TypeFoldable, TypeVisitable)] + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)] pub struct AscribeUserType<'tcx> { pub mir_ty: Ty<'tcx>, pub user_ty: UserType<'tcx>, @@ -30,22 +29,19 @@ pub mod type_op { } } - #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)] - #[derive(TypeFoldable, TypeVisitable)] + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)] pub struct Eq<'tcx> { pub a: Ty<'tcx>, pub b: Ty<'tcx>, } - #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)] - #[derive(TypeFoldable, TypeVisitable)] + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)] pub struct Subtype<'tcx> { pub sub: Ty<'tcx>, pub sup: Ty<'tcx>, } - #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)] - #[derive(TypeFoldable, TypeVisitable)] + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)] pub struct ProvePredicate<'tcx> { pub predicate: Predicate<'tcx>, } @@ -56,8 +52,7 @@ pub mod type_op { } } - #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)] - #[derive(TypeFoldable, TypeVisitable)] + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, TypeVisitable)] pub struct Normalize { pub value: T, } @@ -101,7 +96,7 @@ impl<'tcx> From> for NoSolution { } } -#[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable, Lift)] +#[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable)] pub struct DropckOutlivesResult<'tcx> { pub kinds: Vec>, pub overflows: Vec>, @@ -194,7 +189,7 @@ pub struct MethodAutoderefBadTy<'tcx> { } /// Result from the `normalize_projection_ty` query. -#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)] +#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct NormalizationResult<'tcx> { /// Result of normalization. pub normalized_ty: Ty<'tcx>, @@ -207,7 +202,7 @@ pub struct NormalizationResult<'tcx> { /// case they are called implied bounds). They are fed to the /// `OutlivesEnv` which in turn is supplied to the region checker and /// other parts of the inference system. -#[derive(Clone, Debug, TypeFoldable, TypeVisitable, Lift, HashStable)] +#[derive(Clone, Debug, TypeFoldable, TypeVisitable, HashStable)] pub enum OutlivesBound<'tcx> { RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>), RegionSubParam(ty::Region<'tcx>, ty::ParamTy), diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index ffae3579889..90bc5dd8f69 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -305,7 +305,7 @@ impl From for OverflowError { } } -TrivialTypeTraversalAndLiftImpls! { OverflowError } +TrivialTypeTraversalImpls! { OverflowError } impl<'tcx> From for SelectionError<'tcx> { fn from(overflow_error: OverflowError) -> SelectionError<'tcx> { diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs index d8b3a061b77..c3ed40867cf 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect.rs @@ -14,10 +14,16 @@ pub enum CacheHit { Global, } +#[derive(Eq, PartialEq)] +pub enum GoalEvaluationKind { + Root, + Nested { is_normalizes_to_hack: IsNormalizesToHack }, +} + #[derive(Eq, PartialEq)] pub struct GoalEvaluation<'tcx> { pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>, - pub is_normalizes_to_hack: IsNormalizesToHack, + pub kind: GoalEvaluationKind, pub evaluation: CanonicalGoalEvaluation<'tcx>, pub returned_goals: Vec>>, } @@ -25,12 +31,12 @@ pub struct GoalEvaluation<'tcx> { #[derive(Eq, PartialEq)] pub struct CanonicalGoalEvaluation<'tcx> { pub goal: CanonicalInput<'tcx>, - pub kind: GoalEvaluationKind<'tcx>, + pub kind: CanonicalGoalEvaluationKind<'tcx>, pub result: QueryResult<'tcx>, } #[derive(Eq, PartialEq)] -pub enum GoalEvaluationKind<'tcx> { +pub enum CanonicalGoalEvaluationKind<'tcx> { Overflow, CacheHit(CacheHit), Uncached { revisions: Vec> }, @@ -52,22 +58,31 @@ pub struct GoalEvaluationStep<'tcx> { pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, /// The actual evaluation of the goal, always `ProbeKind::Root`. - pub evaluation: GoalCandidate<'tcx>, + pub evaluation: Probe<'tcx>, } +/// A self-contained computation during trait solving. This either +/// corresponds to a `EvalCtxt::probe(_X)` call or the root evaluation +/// of a goal. #[derive(Eq, PartialEq)] -pub struct GoalCandidate<'tcx> { - pub added_goals_evaluations: Vec>, - pub candidates: Vec>, +pub struct Probe<'tcx> { + pub steps: Vec>, pub kind: ProbeKind<'tcx>, } -impl Debug for GoalCandidate<'_> { +impl Debug for Probe<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - ProofTreeFormatter::new(f).format_candidate(self) + ProofTreeFormatter::new(f).format_probe(self) } } +#[derive(Eq, PartialEq)] +pub enum ProbeStep<'tcx> { + AddGoal(Goal<'tcx, ty::Predicate<'tcx>>), + EvaluateGoals(AddedGoalsEvaluation<'tcx>), + NestedProbe(Probe<'tcx>), +} + #[derive(Debug, PartialEq, Eq)] pub enum ProbeKind<'tcx> { /// The root inference context while proving a goal. diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs index d916e80a625..d33e83ae1ed 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs @@ -40,9 +40,12 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { } pub(super) fn format_goal_evaluation(&mut self, eval: &GoalEvaluation<'_>) -> std::fmt::Result { - let goal_text = match eval.is_normalizes_to_hack { - IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL", - IsNormalizesToHack::No => "GOAL", + let goal_text = match eval.kind { + GoalEvaluationKind::Root => "ROOT GOAL", + GoalEvaluationKind::Nested { is_normalizes_to_hack } => match is_normalizes_to_hack { + IsNormalizesToHack::No => "GOAL", + IsNormalizesToHack::Yes => "NORMALIZES-TO HACK GOAL", + }, }; writeln!(self.f, "{}: {:?}", goal_text, eval.uncanonicalized_goal)?; self.nested(|this| this.format_canonical_goal_evaluation(&eval.evaluation))?; @@ -68,16 +71,16 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { writeln!(self.f, "GOAL: {:?}", eval.goal)?; match &eval.kind { - GoalEvaluationKind::Overflow => { + CanonicalGoalEvaluationKind::Overflow => { writeln!(self.f, "OVERFLOW: {:?}", eval.result) } - GoalEvaluationKind::CacheHit(CacheHit::Global) => { + CanonicalGoalEvaluationKind::CacheHit(CacheHit::Global) => { writeln!(self.f, "GLOBAL CACHE HIT: {:?}", eval.result) } - GoalEvaluationKind::CacheHit(CacheHit::Provisional) => { + CanonicalGoalEvaluationKind::CacheHit(CacheHit::Provisional) => { writeln!(self.f, "PROVISIONAL CACHE HIT: {:?}", eval.result) } - GoalEvaluationKind::Uncached { revisions } => { + CanonicalGoalEvaluationKind::Uncached { revisions } => { for (n, step) in revisions.iter().enumerate() { writeln!(self.f, "REVISION {n}")?; self.nested(|this| this.format_evaluation_step(step))?; @@ -92,11 +95,11 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { evaluation_step: &GoalEvaluationStep<'_>, ) -> std::fmt::Result { writeln!(self.f, "INSTANTIATED: {:?}", evaluation_step.instantiated_goal)?; - self.format_candidate(&evaluation_step.evaluation) + self.format_probe(&evaluation_step.evaluation) } - pub(super) fn format_candidate(&mut self, candidate: &GoalCandidate<'_>) -> std::fmt::Result { - match &candidate.kind { + pub(super) fn format_probe(&mut self, probe: &Probe<'_>) -> std::fmt::Result { + match &probe.kind { ProbeKind::Root { result } => { writeln!(self.f, "ROOT RESULT: {result:?}") } @@ -118,11 +121,12 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { }?; self.nested(|this| { - for candidate in &candidate.candidates { - this.format_candidate(candidate)?; - } - for nested in &candidate.added_goals_evaluations { - this.format_added_goals_evaluation(nested)?; + for step in &probe.steps { + match step { + ProbeStep::AddGoal(goal) => writeln!(this.f, "ADDED GOAL: {goal:?}")?, + ProbeStep::EvaluateGoals(eval) => this.format_added_goals_evaluation(eval)?, + ProbeStep::NestedProbe(probe) => this.format_probe(probe)?, + } } Ok(()) }) diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs index cdd8351499b..570f896ba29 100644 --- a/compiler/rustc_middle/src/ty/abstract_const.rs +++ b/compiler/rustc_middle/src/ty/abstract_const.rs @@ -27,7 +27,7 @@ impl From for NotConstEvaluatable { } } -TrivialTypeTraversalAndLiftImpls! { NotConstEvaluatable } +TrivialTypeTraversalImpls! { NotConstEvaluatable } pub type BoundAbstractConst<'tcx> = Result>>, ErrorGuaranteed>; diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index 76931ceaa69..c3e8991c63a 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -76,7 +76,7 @@ pub enum PointerCoercion { /// At some point, of course, `Box` should move out of the compiler, in which /// case this is analogous to transforming a struct. E.g., `Box<[i32; 4]>` -> /// `Box<[i32]>` is an `Adjust::Unsize` with the target `Box<[i32]>`. -#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)] +#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct Adjustment<'tcx> { pub kind: Adjust<'tcx>, pub target: Ty<'tcx>, @@ -88,7 +88,7 @@ impl<'tcx> Adjustment<'tcx> { } } -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)] +#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub enum Adjust<'tcx> { /// Go from ! to any type. NeverToAny, @@ -110,7 +110,7 @@ pub enum Adjust<'tcx> { /// The target type is `U` in both cases, with the region and mutability /// being those shared by both the receiver and the returned reference. #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)] -#[derive(TypeFoldable, TypeVisitable, Lift)] +#[derive(TypeFoldable, TypeVisitable)] pub struct OverloadedDeref<'tcx> { pub region: ty::Region<'tcx>, pub mutbl: hir::Mutability, @@ -182,7 +182,7 @@ impl From for hir::Mutability { } #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)] -#[derive(TypeFoldable, TypeVisitable, Lift)] +#[derive(TypeFoldable, TypeVisitable)] pub enum AutoBorrow<'tcx> { /// Converts from T to &T. Ref(ty::Region<'tcx>, AutoBorrowMutability), diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index b4c6e0d970a..219927f5ab4 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -478,8 +478,8 @@ impl<'tcx> AdtDef<'tcx> { } Err(err) => { let msg = match err { - ErrorHandled::Reported(_) => "enum discriminant evaluation failed", - ErrorHandled::TooGeneric => "enum discriminant depends on generics", + ErrorHandled::Reported(..) => "enum discriminant evaluation failed", + ErrorHandled::TooGeneric(..) => "enum discriminant depends on generics", }; tcx.sess.delay_span_bug(tcx.def_span(expr_did), msg); None diff --git a/compiler/rustc_middle/src/ty/binding.rs b/compiler/rustc_middle/src/ty/binding.rs index 2fec8ac9095..af594bc5f24 100644 --- a/compiler/rustc_middle/src/ty/binding.rs +++ b/compiler/rustc_middle/src/ty/binding.rs @@ -6,7 +6,7 @@ pub enum BindingMode { BindByValue(Mutability), } -TrivialTypeTraversalAndLiftImpls! { BindingMode } +TrivialTypeTraversalImpls! { BindingMode } impl BindingMode { pub fn convert(BindingAnnotation(by_ref, mutbl): BindingAnnotation) -> BindingMode { diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 629f9f8cd7d..ba871d6478b 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -300,7 +300,7 @@ impl<'tcx> Const<'tcx> { | ConstKind::Infer(_) | ConstKind::Bound(_, _) | ConstKind::Placeholder(_) - | ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric), + | ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric(span.unwrap_or(DUMMY_SP))), } } @@ -309,8 +309,8 @@ impl<'tcx> Const<'tcx> { pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self { match self.eval(tcx, param_env, None) { Ok(val) => Self::new_value(tcx, val, self.ty()), - Err(ErrorHandled::Reported(r)) => Self::new_error(tcx, r.into(), self.ty()), - Err(ErrorHandled::TooGeneric) => self, + Err(ErrorHandled::Reported(r, _span)) => Self::new_error(tcx, r.into(), self.ty()), + Err(ErrorHandled::TooGeneric(_span)) => self, } } diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index e25402fe0c2..749b54ca0be 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -8,7 +8,7 @@ use rustc_hir::def_id::DefId; use rustc_macros::HashStable; /// An unevaluated (potentially generic) constant used in the type-system. -#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)] +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] #[derive(Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct UnevaluatedConst<'tcx> { pub def: DefId, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f7484048757..9ff4b64f48b 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -50,7 +50,7 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; -use rustc_hir::{Constness, HirId, Node, TraitCandidate}; +use rustc_hir::{HirId, Node, TraitCandidate}; use rustc_index::IndexVec; use rustc_macros::HashStable; use rustc_query_system::dep_graph::DepNodeIndex; @@ -82,6 +82,7 @@ use std::ops::{Bound, Deref}; impl<'tcx> Interner for TyCtxt<'tcx> { type AdtDef = ty::AdtDef<'tcx>; type GenericArgsRef = ty::GenericArgsRef<'tcx>; + type GenericArg = ty::GenericArg<'tcx>; type DefId = DefId; type Binder = Binder<'tcx, T>; type Ty = Ty<'tcx>; @@ -1214,6 +1215,25 @@ macro_rules! nop_lift { impl<'a, 'tcx> Lift<'tcx> for $ty { type Lifted = $lifted; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { + // Assert that the set has the right type. + // Given an argument that has an interned type, the return type has the type of + // the corresponding interner set. This won't actually return anything, we're + // just doing this to compute said type! + fn _intern_set_ty_from_interned_ty<'tcx, Inner>( + _x: Interned<'tcx, Inner>, + ) -> InternedSet<'tcx, Inner> { + unreachable!() + } + fn _type_eq(_x: &T, _y: &T) {} + fn _test<'tcx>(x: $lifted, tcx: TyCtxt<'tcx>) { + // If `x` is a newtype around an `Interned`, then `interner` is an + // interner of appropriate type. (Ideally we'd also check that `x` is a + // newtype with just that one field. Not sure how to do that.) + let interner = _intern_set_ty_from_interned_ty(x.0); + // Now check that this is the same type as `interners.$set`. + _type_eq(&interner, &tcx.interners.$set); + } + tcx.interners .$set .contains_pointer_to(&InternedInSet(&*self.0.0)) @@ -1230,6 +1250,11 @@ macro_rules! nop_list_lift { impl<'a, 'tcx> Lift<'tcx> for &'a List<$ty> { type Lifted = &'tcx List<$lifted>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { + // Assert that the set has the right type. + if false { + let _x: &InternedSet<'tcx, List<$lifted>> = &tcx.interners.$set; + } + if self.is_empty() { return Some(List::empty()); } @@ -1251,19 +1276,13 @@ nop_lift! {predicate; Clause<'a> => Clause<'tcx>} nop_list_lift! {type_lists; Ty<'a> => Ty<'tcx>} nop_list_lift! {poly_existential_predicates; PolyExistentialPredicate<'a> => PolyExistentialPredicate<'tcx>} -nop_list_lift! {clauses; Clause<'a> => Clause<'tcx>} -nop_list_lift! {canonical_var_infos; CanonicalVarInfo<'a> => CanonicalVarInfo<'tcx>} -nop_list_lift! {projs; ProjectionKind => ProjectionKind} nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariableKind} // This is the impl for `&'a GenericArgs<'a>`. nop_list_lift! {args; GenericArg<'a> => GenericArg<'tcx>} -CloneLiftImpls! { - Constness, - traits::WellFormedLoc, +TrivialLiftImpls! { ImplPolarity, - crate::mir::ReturnConstraint, } macro_rules! sty_debug_print { diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index bf6f082c21c..f939d466078 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -11,7 +11,7 @@ use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::path::PathBuf; -#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable, Lift)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)] pub struct ExpectedFound { pub expected: T, pub found: T, @@ -28,7 +28,7 @@ impl ExpectedFound { } // Data structures used in type unification -#[derive(Copy, Clone, Debug, TypeVisitable, Lift, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, TypeVisitable, PartialEq, Eq)] #[rustc_pass_by_value] pub enum TypeError<'tcx> { Mismatch, diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index e598ead791e..72390e4bbb0 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -1029,7 +1029,7 @@ impl<'a, 'tcx> ArgFolder<'a, 'tcx> { /// Stores the user-given args to reach some fully qualified path /// (e.g., `::Item` or `::Item`). #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct UserArgs<'tcx> { /// The args for the item as given by the user. pub args: GenericArgsRef<'tcx>, @@ -1056,7 +1056,7 @@ pub struct UserArgs<'tcx> { /// the self type, giving `Foo`. Finally, we unify that with /// the self type here, which contains `?A` to be `&'static u32` #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct UserSelfTy<'tcx> { pub impl_def_id: DefId, pub self_ty: Ty<'tcx>, diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index e5b9203d12a..2b75f6c4e8f 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -18,6 +18,9 @@ use std::fmt; /// Monomorphization happens on-the-fly and no monomorphized MIR is ever created. Instead, this type /// simply couples a potentially generic `InstanceDef` with some args, and codegen and const eval /// will do all required substitution as they run. +/// +/// Note: the `Lift` impl is currently not used by rustc, but is used by +/// rustc_codegen_cranelift when the `jit` feature is enabled. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable, Lift, TypeFoldable, TypeVisitable)] pub struct Instance<'tcx> { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 99b697d0ea5..eb8ea0bc114 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1510,7 +1510,7 @@ impl<'a, 'tcx> IntoIterator for &'a InstantiatedPredicates<'tcx> { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable, Lift)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] #[derive(TypeFoldable, TypeVisitable)] pub struct OpaqueTypeKey<'tcx> { pub def_id: LocalDefId, @@ -1793,7 +1793,7 @@ impl<'tcx> ParamEnv<'tcx> { } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)] -#[derive(HashStable, Lift)] +#[derive(HashStable)] pub struct ParamEnvAnd<'tcx, T> { pub param_env: ParamEnv<'tcx>, pub value: T, @@ -2408,6 +2408,22 @@ impl<'tcx> TyCtxt<'tcx> { } } + pub fn get_attrs_by_path<'attr>( + self, + did: DefId, + attr: &'attr [Symbol], + ) -> impl Iterator + 'attr + where + 'tcx: 'attr, + { + let filter_fn = move |a: &&ast::Attribute| a.path_matches(&attr); + if let Some(did) = did.as_local() { + self.hir().attrs(self.hir().local_def_id_to_hir_id(did)).iter().filter(filter_fn) + } else { + self.item_attrs(did).iter().filter(filter_fn) + } + } + pub fn get_attr(self, did: impl Into, attr: Symbol) -> Option<&'tcx ast::Attribute> { if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) { let did: DefId = did.into(); diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index f24ac79323f..e1d4e43841d 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -136,10 +136,8 @@ define_helper!( /// /// Regions not selected by the region highlight mode are presently /// unaffected. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Default)] pub struct RegionHighlightMode<'tcx> { - tcx: TyCtxt<'tcx>, - /// If enabled, when we see the selected region, use "`'N`" /// instead of the ordinary behavior. highlight_regions: [Option<(ty::Region<'tcx>, usize)>; 3], @@ -155,14 +153,6 @@ pub struct RegionHighlightMode<'tcx> { } impl<'tcx> RegionHighlightMode<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>) -> Self { - Self { - tcx, - highlight_regions: Default::default(), - highlight_bound_region: Default::default(), - } - } - /// If `region` and `number` are both `Some`, invokes /// `highlighting_region`. pub fn maybe_highlighting_region( @@ -188,8 +178,13 @@ impl<'tcx> RegionHighlightMode<'tcx> { } /// Convenience wrapper for `highlighting_region`. - pub fn highlighting_region_vid(&mut self, vid: ty::RegionVid, number: usize) { - self.highlighting_region(ty::Region::new_var(self.tcx, vid), number) + pub fn highlighting_region_vid( + &mut self, + tcx: TyCtxt<'tcx>, + vid: ty::RegionVid, + number: usize, + ) { + self.highlighting_region(ty::Region::new_var(tcx, vid), number) } /// Returns `Some(n)` with the number to use for the given region, if any. @@ -1778,7 +1773,7 @@ impl<'a, 'tcx> FmtPrinter<'a, 'tcx> { printed_type_count: 0, type_length_limit, truncated: false, - region_highlight_mode: RegionHighlightMode::new(tcx), + region_highlight_mode: RegionHighlightMode::default(), ty_infer_name_resolver: None, const_infer_name_resolver: None, })) @@ -2746,20 +2741,14 @@ forward_display_to_print! { // HACK(eddyb) these are exhaustive instead of generic, // because `for<'tcx>` isn't possible yet. - ty::PolyExistentialPredicate<'tcx>, ty::PolyExistentialProjection<'tcx>, ty::PolyExistentialTraitRef<'tcx>, ty::Binder<'tcx, ty::TraitRef<'tcx>>, ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - ty::Binder<'tcx, TraitRefPrintOnlyTraitName<'tcx>>, ty::Binder<'tcx, ty::FnSig<'tcx>>, ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>>, - ty::Binder<'tcx, ty::SubtypePredicate<'tcx>>, ty::Binder<'tcx, ty::ProjectionPredicate<'tcx>>, - ty::Binder<'tcx, ty::OutlivesPredicate, ty::Region<'tcx>>>, - ty::Binder<'tcx, ty::OutlivesPredicate, ty::Region<'tcx>>>, - ty::OutlivesPredicate, ty::Region<'tcx>>, ty::OutlivesPredicate, ty::Region<'tcx>> } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 1b29a83f23e..f4158597d10 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -9,15 +9,13 @@ use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; use rustc_hir::def::Namespace; -use rustc_index::{Idx, IndexVec}; use rustc_target::abi::TyAndLayout; use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, OptWithInfcx}; use std::fmt::{self, Debug}; use std::ops::ControlFlow; -use std::rc::Rc; -use std::sync::Arc; +use super::print::PrettyPrinter; use super::{GenericArg, GenericArgKind, Region}; impl fmt::Debug for ty::TraitDef { @@ -343,14 +341,27 @@ impl<'tcx> DebugWithInfcx> for ty::Const<'tcx> { this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { - // This reflects what `Const` looked liked before `Interned` was - // introduced. We print it like this to avoid having to update expected - // output in a lot of tests. + // If this is a value, we spend some effort to make it look nice. + if let ConstKind::Value(_) = this.data.kind() { + return ty::tls::with(move |tcx| { + // Somehow trying to lift the valtree results in lifetime errors, so we lift the + // entire constant. + let lifted = tcx.lift(*this.data).unwrap(); + let ConstKind::Value(valtree) = lifted.kind() else { + bug!("we checked that this is a valtree") + }; + let cx = FmtPrinter::new(tcx, Namespace::ValueNS); + let cx = + cx.pretty_print_const_valtree(valtree, lifted.ty(), /*print_ty*/ true)?; + f.write_str(&cx.into_buffer()) + }); + } + // Fall back to something verbose. write!( f, - "Const {{ ty: {:?}, kind: {:?} }}", - &this.map(|data| data.ty()), - &this.map(|data| data.kind()) + "{kind:?}: {ty:?}", + ty = &this.map(|data| data.ty()), + kind = &this.map(|data| data.kind()) ) } } @@ -442,22 +453,16 @@ impl<'tcx, T: DebugWithInfcx>> DebugWithInfcx> for ty: // For things for which the type library provides traversal implementations // for all Interners, we only need to provide a Lift implementation: -CloneLiftImpls! { - (), - bool, - usize, - u16, - u32, - u64, - String, - rustc_type_ir::DebruijnIndex, +TrivialLiftImpls! { + (), + bool, + usize, } -// For things about which the type library does not know, or does not -// provide any traversal implementations, we need to provide both a Lift -// implementation and traversal implementations (the latter only for -// TyCtxt<'_> interners). -TrivialTypeTraversalAndLiftImpls! { +// For some things about which the type library does not know, or does not +// provide any traversal implementations, we need to provide a traversal +// implementation (only for TyCtxt<'_> interners). +TrivialTypeTraversalImpls! { ::rustc_target::abi::FieldIdx, ::rustc_target::abi::VariantIdx, crate::middle::region::Scope, @@ -467,14 +472,10 @@ TrivialTypeTraversalAndLiftImpls! { ::rustc_ast::NodeId, ::rustc_span::symbol::Symbol, ::rustc_hir::def::Res, - ::rustc_hir::def_id::DefId, ::rustc_hir::def_id::LocalDefId, ::rustc_hir::HirId, ::rustc_hir::MatchSource, - ::rustc_hir::Mutability, - ::rustc_hir::Unsafety, ::rustc_target::asm::InlineAsmRegOrRegClass, - ::rustc_target::spec::abi::Abi, crate::mir::coverage::CounterId, crate::mir::coverage::ExpressionId, crate::mir::coverage::MappedExpressionIndex, @@ -492,16 +493,12 @@ TrivialTypeTraversalAndLiftImpls! { crate::ty::AssocItem, crate::ty::AssocKind, crate::ty::AliasKind, - crate::ty::AliasRelationDirection, crate::ty::Placeholder, crate::ty::Placeholder, crate::ty::Placeholder, - crate::ty::ClosureKind, crate::ty::FreeRegion, crate::ty::InferTy, crate::ty::IntVarValue, - crate::ty::ParamConst, - crate::ty::ParamTy, crate::ty::adjustment::PointerCoercion, crate::ty::RegionVid, crate::ty::UniverseIndex, @@ -509,33 +506,30 @@ TrivialTypeTraversalAndLiftImpls! { ::rustc_span::Span, ::rustc_span::symbol::Ident, ::rustc_errors::ErrorGuaranteed, + ty::BoundVar, + ty::ValTree<'tcx>, +} +// For some things about which the type library does not know, or does not +// provide any traversal implementations, we need to provide a traversal +// implementation and a lift implementation (the former only for TyCtxt<'_> +// interners). +TrivialTypeTraversalAndLiftImpls! { + ::rustc_hir::def_id::DefId, + ::rustc_hir::Mutability, + ::rustc_hir::Unsafety, + ::rustc_target::spec::abi::Abi, + crate::ty::AliasRelationDirection, + crate::ty::ClosureKind, + crate::ty::ParamConst, + crate::ty::ParamTy, interpret::Scalar, interpret::AllocId, rustc_target::abi::Size, - ty::BoundVar, -} - -TrivialTypeTraversalAndLiftImpls! { - ty::ValTree<'tcx>, } /////////////////////////////////////////////////////////////////////////// // Lift implementations -impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) { - type Lifted = (A::Lifted, B::Lifted); - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - Some((tcx.lift(self.0)?, tcx.lift(self.1)?)) - } -} - -impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>, C: Lift<'tcx>> Lift<'tcx> for (A, B, C) { - type Lifted = (A::Lifted, B::Lifted, C::Lifted); - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - Some((tcx.lift(self.0)?, tcx.lift(self.1)?, tcx.lift(self.2)?)) - } -} - impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option { type Lifted = Option; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { @@ -546,50 +540,6 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option { } } -impl<'tcx, T: Lift<'tcx>, E: Lift<'tcx>> Lift<'tcx> for Result { - type Lifted = Result; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - match self { - Ok(x) => tcx.lift(x).map(Ok), - Err(e) => tcx.lift(e).map(Err), - } - } -} - -impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Box { - type Lifted = Box; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - Some(Box::new(tcx.lift(*self)?)) - } -} - -impl<'tcx, T: Lift<'tcx> + Clone> Lift<'tcx> for Rc { - type Lifted = Rc; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - Some(Rc::new(tcx.lift(self.as_ref().clone())?)) - } -} - -impl<'tcx, T: Lift<'tcx> + Clone> Lift<'tcx> for Arc { - type Lifted = Arc; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - Some(Arc::new(tcx.lift(self.as_ref().clone())?)) - } -} -impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Vec { - type Lifted = Vec; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - self.into_iter().map(|v| tcx.lift(v)).collect() - } -} - -impl<'tcx, I: Idx, T: Lift<'tcx>> Lift<'tcx> for IndexVec { - type Lifted = IndexVec; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - self.into_iter().map(|e| tcx.lift(e)).collect() - } -} - impl<'a, 'tcx> Lift<'tcx> for Term<'a> { type Lifted = ty::Term<'tcx>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { @@ -602,13 +552,6 @@ impl<'a, 'tcx> Lift<'tcx> for Term<'a> { ) } } -impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> { - type Lifted = ty::ParamEnv<'tcx>; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(self.caller_bounds()) - .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal())) - } -} /////////////////////////////////////////////////////////////////////////// // Traversal implementations. diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 2502e303f7a..edab7fe58ba 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -351,7 +351,7 @@ impl<'tcx> ClosureArgs<'tcx> { } /// Similar to `ClosureArgs`; see the above documentation for more. -#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable, Lift)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)] pub struct GeneratorArgs<'tcx> { pub args: GenericArgsRef<'tcx>, } @@ -1305,7 +1305,7 @@ impl<'tcx> AliasTy<'tcx> { } } -#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift)] +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)] pub struct GenSig<'tcx> { pub resume_ty: Ty<'tcx>, pub yield_ty: Ty<'tcx>, diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 7ecc7e6014d..69c4c588c44 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -165,7 +165,7 @@ pub struct TypeckResults<'tcx> { /// reading places that are mentioned in a closure (because of _ patterns). However, /// to ensure the places are initialized, we introduce fake reads. /// Consider these two examples: - /// ``` (discriminant matching with only wildcard arm) + /// ```ignore (discriminant matching with only wildcard arm) /// let x: u8; /// let c = || match x { _ => () }; /// ``` @@ -173,7 +173,7 @@ pub struct TypeckResults<'tcx> { /// want to capture it. However, we do still want an error here, because `x` should have /// to be initialized at the point where c is created. Therefore, we add a "fake read" /// instead. - /// ``` (destructured assignments) + /// ```ignore (destructured assignments) /// let c = || { /// let (t1, t2) = t; /// } @@ -654,7 +654,7 @@ rustc_index::newtype_index! { pub type CanonicalUserTypeAnnotations<'tcx> = IndexVec>; -#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)] +#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub struct CanonicalUserTypeAnnotation<'tcx> { pub user_ty: Box>, pub span: Span, @@ -714,7 +714,7 @@ impl<'tcx> CanonicalUserType<'tcx> { /// from constants that are named via paths, like `Foo::::new` and /// so forth. #[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)] -#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable, Lift)] +#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)] pub enum UserType<'tcx> { Ty(Ty<'tcx>), diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 0ea61ec8d40..71e6e6f3a7a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -566,7 +566,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { pattern } } - Err(ErrorHandled::TooGeneric) => { + 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 }); @@ -640,14 +640,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { .kind } else { // If that fails, convert it to an opaque constant pattern. - match tcx.const_eval_resolve(self.param_env, uneval, None) { + match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) { Ok(val) => self.const_to_pat(mir::ConstantKind::Val(val, ty), id, span, None).kind, - Err(ErrorHandled::TooGeneric) => { + 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 } - Err(ErrorHandled::Reported(_)) => PatKind::Wild, + Err(ErrorHandled::Reported(..)) => PatKind::Wild, } } } diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index b52827a1e88..fb33b3b49d3 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -105,25 +105,12 @@ impl<'tcx> MirLint<'tcx> for ConstProp { trace!("ConstProp starting for {:?}", def_id); - let dummy_body = &Body::new( - body.source, - (*body.basic_blocks).to_owned(), - body.source_scopes.clone(), - body.local_decls.clone(), - Default::default(), - body.arg_count, - Default::default(), - body.span, - body.generator_kind(), - body.tainted_by_errors, - ); - // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold // constants, instead of just checking for const-folding succeeding. // That would require a uniform one-def no-mutation analysis // and RPO (or recursing when needing the value of a local). - let mut optimization_finder = ConstPropagator::new(body, dummy_body, tcx); - optimization_finder.visit_body(body); + let mut linter = ConstPropagator::new(body, tcx); + linter.visit_body(body); trace!("ConstProp done for {:?}", def_id); } @@ -169,11 +156,7 @@ impl<'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'_, 'tcx> { } impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { - fn new( - body: &Body<'tcx>, - dummy_body: &'mir Body<'tcx>, - tcx: TyCtxt<'tcx>, - ) -> ConstPropagator<'mir, 'tcx> { + fn new(body: &'mir Body<'tcx>, tcx: TyCtxt<'tcx>) -> ConstPropagator<'mir, 'tcx> { let def_id = body.source.def_id(); let args = &GenericArgs::identity_for_item(tcx, def_id); let param_env = tcx.param_env_reveal_all_normalized(def_id); @@ -204,7 +187,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ecx.push_stack_frame( Instance::new(def_id, args), - dummy_body, + body, &ret, StackPopCleanup::Root { cleanup: false }, ) diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs index af616c498fd..bb1f16aa8be 100644 --- a/compiler/rustc_mir_transform/src/coverage/debug.rs +++ b/compiler/rustc_mir_transform/src/coverage/debug.rs @@ -44,7 +44,7 @@ //! points, which can be enabled via environment variable: //! //! ```shell -//! RUSTC_LOG=rustc_mir_transform::transform::coverage=debug +//! RUSTC_LOG=rustc_mir_transform::coverage=debug //! ``` //! //! Other module paths with coverage-related debug logs may also be of interest, particularly for @@ -52,7 +52,7 @@ //! code generation pass). For example: //! //! ```shell -//! RUSTC_LOG=rustc_mir_transform::transform::coverage,rustc_codegen_ssa::coverageinfo,rustc_codegen_llvm::coverageinfo=debug +//! RUSTC_LOG=rustc_mir_transform::coverage,rustc_codegen_llvm::coverageinfo=debug //! ``` //! //! Coverage Debug Options @@ -108,24 +108,23 @@ //! recursively, generating labels with nested operations, enclosed in parentheses //! (for example: `bcb2 + (bcb0 - bcb1)`). -use super::counters::{BcbCounter, CoverageCounters}; -use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; -use super::spans::CoverageSpan; +use std::iter; +use std::ops::Deref; +use std::sync::OnceLock; use itertools::Itertools; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_middle::mir::coverage::*; use rustc_middle::mir::create_dump_file; use rustc_middle::mir::generic_graphviz::GraphvizWriter; use rustc_middle::mir::spanview::{self, SpanViewable}; - -use rustc_data_structures::fx::FxHashMap; -use rustc_middle::mir::coverage::*; use rustc_middle::mir::{self, BasicBlock}; use rustc_middle::ty::TyCtxt; use rustc_span::Span; -use std::iter; -use std::ops::Deref; -use std::sync::OnceLock; +use super::counters::{BcbCounter, CoverageCounters}; +use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph}; +use super::spans::CoverageSpan; pub const NESTED_INDENT: &str = " "; @@ -259,36 +258,42 @@ impl Default for ExpressionFormat { /// `DebugCounters` supports a recursive rendering of `Expression` counters, so they can be /// presented as nested expressions such as `(bcb3 - (bcb0 + bcb1))`. pub(super) struct DebugCounters { - some_counters: Option>, + state: Option, +} + +#[derive(Default)] +struct DebugCountersState { + counters: FxHashMap, } impl DebugCounters { pub fn new() -> Self { - Self { some_counters: None } + Self { state: None } } pub fn enable(&mut self) { debug_assert!(!self.is_enabled()); - self.some_counters.replace(FxHashMap::default()); + self.state = Some(DebugCountersState::default()); } pub fn is_enabled(&self) -> bool { - self.some_counters.is_some() + self.state.is_some() } pub fn add_counter(&mut self, counter_kind: &BcbCounter, some_block_label: Option) { - if let Some(counters) = &mut self.some_counters { - let id = counter_kind.as_operand(); - counters - .try_insert(id, DebugCounter::new(counter_kind.clone(), some_block_label)) - .expect("attempt to add the same counter_kind to DebugCounters more than once"); - } + let Some(state) = &mut self.state else { return }; + + let id = counter_kind.as_operand(); + state + .counters + .try_insert(id, DebugCounter::new(counter_kind.clone(), some_block_label)) + .expect("attempt to add the same counter_kind to DebugCounters more than once"); } pub fn some_block_label(&self, operand: Operand) -> Option<&String> { - self.some_counters.as_ref().and_then(|counters| { - counters.get(&operand).and_then(|debug_counter| debug_counter.some_block_label.as_ref()) - }) + let Some(state) = &self.state else { return None }; + + state.counters.get(&operand)?.some_block_label.as_ref() } pub fn format_counter(&self, counter_kind: &BcbCounter) -> String { @@ -308,7 +313,7 @@ impl DebugCounters { if counter_format.operation { return format!( "{}{} {} {}", - if counter_format.id || self.some_counters.is_none() { + if counter_format.id || !self.is_enabled() { format!("#{} = ", id.index()) } else { String::new() @@ -324,10 +329,9 @@ impl DebugCounters { } let id = counter_kind.as_operand(); - if self.some_counters.is_some() && (counter_format.block || !counter_format.id) { - let counters = self.some_counters.as_ref().unwrap(); + if let Some(state) = &self.state && (counter_format.block || !counter_format.id) { if let Some(DebugCounter { some_block_label: Some(block_label), .. }) = - counters.get(&id) + state.counters.get(&id) { return if counter_format.id { format!("{}#{:?}", block_label, id) @@ -343,8 +347,10 @@ impl DebugCounters { if matches!(operand, Operand::Zero) { return String::from("0"); } - if let Some(counters) = &self.some_counters { - if let Some(DebugCounter { counter_kind, some_block_label }) = counters.get(&operand) { + if let Some(state) = &self.state { + if let Some(DebugCounter { counter_kind, some_block_label }) = + state.counters.get(&operand) + { if let BcbCounter::Expression { .. } = counter_kind { if let Some(label) = some_block_label && debug_options().counter_format.block { return format!( @@ -378,30 +384,29 @@ impl DebugCounter { /// If enabled, this data structure captures additional debugging information used when generating /// a Graphviz (.dot file) representation of the `CoverageGraph`, for debugging purposes. pub(super) struct GraphvizData { - some_bcb_to_coverage_spans_with_counters: - Option>>, - some_bcb_to_dependency_counters: Option>>, - some_edge_to_counter: Option>, + state: Option, +} + +#[derive(Default)] +struct GraphvizDataState { + bcb_to_coverage_spans_with_counters: + FxHashMap>, + bcb_to_dependency_counters: FxHashMap>, + edge_to_counter: FxHashMap<(BasicCoverageBlock, BasicBlock), BcbCounter>, } impl GraphvizData { pub fn new() -> Self { - Self { - some_bcb_to_coverage_spans_with_counters: None, - some_bcb_to_dependency_counters: None, - some_edge_to_counter: None, - } + Self { state: None } } pub fn enable(&mut self) { debug_assert!(!self.is_enabled()); - self.some_bcb_to_coverage_spans_with_counters = Some(FxHashMap::default()); - self.some_bcb_to_dependency_counters = Some(FxHashMap::default()); - self.some_edge_to_counter = Some(FxHashMap::default()); + self.state = Some(GraphvizDataState::default()); } pub fn is_enabled(&self) -> bool { - self.some_bcb_to_coverage_spans_with_counters.is_some() + self.state.is_some() } pub fn add_bcb_coverage_span_with_counter( @@ -410,27 +415,22 @@ impl GraphvizData { coverage_span: &CoverageSpan, counter_kind: &BcbCounter, ) { - if let Some(bcb_to_coverage_spans_with_counters) = - self.some_bcb_to_coverage_spans_with_counters.as_mut() - { - bcb_to_coverage_spans_with_counters - .entry(bcb) - .or_insert_with(Vec::new) - .push((coverage_span.clone(), counter_kind.clone())); - } + let Some(state) = &mut self.state else { return }; + + state + .bcb_to_coverage_spans_with_counters + .entry(bcb) + .or_insert_with(Vec::new) + .push((coverage_span.clone(), counter_kind.clone())); } pub fn get_bcb_coverage_spans_with_counters( &self, bcb: BasicCoverageBlock, ) -> Option<&[(CoverageSpan, BcbCounter)]> { - if let Some(bcb_to_coverage_spans_with_counters) = - self.some_bcb_to_coverage_spans_with_counters.as_ref() - { - bcb_to_coverage_spans_with_counters.get(&bcb).map(Deref::deref) - } else { - None - } + let Some(state) = &self.state else { return None }; + + state.bcb_to_coverage_spans_with_counters.get(&bcb).map(Deref::deref) } pub fn add_bcb_dependency_counter( @@ -438,20 +438,19 @@ impl GraphvizData { bcb: BasicCoverageBlock, counter_kind: &BcbCounter, ) { - if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_mut() { - bcb_to_dependency_counters - .entry(bcb) - .or_insert_with(Vec::new) - .push(counter_kind.clone()); - } + let Some(state) = &mut self.state else { return }; + + state + .bcb_to_dependency_counters + .entry(bcb) + .or_insert_with(Vec::new) + .push(counter_kind.clone()); } pub fn get_bcb_dependency_counters(&self, bcb: BasicCoverageBlock) -> Option<&[BcbCounter]> { - if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_ref() { - bcb_to_dependency_counters.get(&bcb).map(Deref::deref) - } else { - None - } + let Some(state) = &self.state else { return None }; + + state.bcb_to_dependency_counters.get(&bcb).map(Deref::deref) } pub fn set_edge_counter( @@ -460,11 +459,12 @@ impl GraphvizData { to_bb: BasicBlock, counter_kind: &BcbCounter, ) { - if let Some(edge_to_counter) = self.some_edge_to_counter.as_mut() { - edge_to_counter - .try_insert((from_bcb, to_bb), counter_kind.clone()) - .expect("invalid attempt to insert more than one edge counter for the same edge"); - } + let Some(state) = &mut self.state else { return }; + + state + .edge_to_counter + .try_insert((from_bcb, to_bb), counter_kind.clone()) + .expect("invalid attempt to insert more than one edge counter for the same edge"); } pub fn get_edge_counter( @@ -472,11 +472,9 @@ impl GraphvizData { from_bcb: BasicCoverageBlock, to_bb: BasicBlock, ) -> Option<&BcbCounter> { - if let Some(edge_to_counter) = self.some_edge_to_counter.as_ref() { - edge_to_counter.get(&(from_bcb, to_bb)) - } else { - None - } + let Some(state) = &self.state else { return None }; + + state.edge_to_counter.get(&(from_bcb, to_bb)) } } @@ -485,41 +483,42 @@ impl GraphvizData { /// _not_ used are retained in the `unused_expressions` Vec, to be included in debug output (logs /// and/or a `CoverageGraph` graphviz output). pub(super) struct UsedExpressions { - some_used_expression_operands: Option>>, - some_unused_expressions: - Option, BasicCoverageBlock)>>, + state: Option, +} + +#[derive(Default)] +struct UsedExpressionsState { + used_expression_operands: FxHashSet, + unused_expressions: Vec<(BcbCounter, Option, BasicCoverageBlock)>, } impl UsedExpressions { pub fn new() -> Self { - Self { some_used_expression_operands: None, some_unused_expressions: None } + Self { state: None } } pub fn enable(&mut self) { debug_assert!(!self.is_enabled()); - self.some_used_expression_operands = Some(FxHashMap::default()); - self.some_unused_expressions = Some(Vec::new()); + self.state = Some(UsedExpressionsState::default()) } pub fn is_enabled(&self) -> bool { - self.some_used_expression_operands.is_some() + self.state.is_some() } pub fn add_expression_operands(&mut self, expression: &BcbCounter) { - if let Some(used_expression_operands) = self.some_used_expression_operands.as_mut() { - if let BcbCounter::Expression { id, lhs, rhs, .. } = *expression { - used_expression_operands.entry(lhs).or_insert_with(Vec::new).push(id); - used_expression_operands.entry(rhs).or_insert_with(Vec::new).push(id); - } + let Some(state) = &mut self.state else { return }; + + if let BcbCounter::Expression { lhs, rhs, .. } = *expression { + state.used_expression_operands.insert(lhs); + state.used_expression_operands.insert(rhs); } } pub fn expression_is_used(&self, expression: &BcbCounter) -> bool { - if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() { - used_expression_operands.contains_key(&expression.as_operand()) - } else { - false - } + let Some(state) = &self.state else { return false }; + + state.used_expression_operands.contains(&expression.as_operand()) } pub fn add_unused_expression_if_not_found( @@ -528,14 +527,10 @@ impl UsedExpressions { edge_from_bcb: Option, target_bcb: BasicCoverageBlock, ) { - if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() { - if !used_expression_operands.contains_key(&expression.as_operand()) { - self.some_unused_expressions.as_mut().unwrap().push(( - expression.clone(), - edge_from_bcb, - target_bcb, - )); - } + let Some(state) = &mut self.state else { return }; + + if !state.used_expression_operands.contains(&expression.as_operand()) { + state.unused_expressions.push((expression.clone(), edge_from_bcb, target_bcb)); } } @@ -544,11 +539,9 @@ impl UsedExpressions { pub fn get_unused_expressions( &self, ) -> Vec<(BcbCounter, Option, BasicCoverageBlock)> { - if let Some(unused_expressions) = self.some_unused_expressions.as_ref() { - unused_expressions.clone() - } else { - Vec::new() - } + let Some(state) = &self.state else { return Vec::new() }; + + state.unused_expressions.clone() } /// If enabled, validate that every BCB or edge counter not directly associated with a coverage @@ -562,51 +555,53 @@ impl UsedExpressions { BcbCounter, )], ) { - if self.is_enabled() { - let mut not_validated = bcb_counters_without_direct_coverage_spans - .iter() - .map(|(_, _, counter_kind)| counter_kind) - .collect::>(); - let mut validating_count = 0; - while not_validated.len() != validating_count { - let to_validate = not_validated.split_off(0); - validating_count = to_validate.len(); - for counter_kind in to_validate { - if self.expression_is_used(counter_kind) { - self.add_expression_operands(counter_kind); - } else { - not_validated.push(counter_kind); - } + if !self.is_enabled() { + return; + } + + let mut not_validated = bcb_counters_without_direct_coverage_spans + .iter() + .map(|(_, _, counter_kind)| counter_kind) + .collect::>(); + let mut validating_count = 0; + while not_validated.len() != validating_count { + let to_validate = not_validated.split_off(0); + validating_count = to_validate.len(); + for counter_kind in to_validate { + if self.expression_is_used(counter_kind) { + self.add_expression_operands(counter_kind); + } else { + not_validated.push(counter_kind); } } } } pub fn alert_on_unused_expressions(&self, debug_counters: &DebugCounters) { - if let Some(unused_expressions) = self.some_unused_expressions.as_ref() { - for (counter_kind, edge_from_bcb, target_bcb) in unused_expressions { - let unused_counter_message = if let Some(from_bcb) = edge_from_bcb.as_ref() { - format!( - "non-coverage edge counter found without a dependent expression, in \ - {:?}->{:?}; counter={}", - from_bcb, - target_bcb, - debug_counters.format_counter(&counter_kind), - ) - } else { - format!( - "non-coverage counter found without a dependent expression, in {:?}; \ - counter={}", - target_bcb, - debug_counters.format_counter(&counter_kind), - ) - }; + let Some(state) = &self.state else { return }; - if debug_options().allow_unused_expressions { - debug!("WARNING: {}", unused_counter_message); - } else { - bug!("{}", unused_counter_message); - } + for (counter_kind, edge_from_bcb, target_bcb) in &state.unused_expressions { + let unused_counter_message = if let Some(from_bcb) = edge_from_bcb.as_ref() { + format!( + "non-coverage edge counter found without a dependent expression, in \ + {:?}->{:?}; counter={}", + from_bcb, + target_bcb, + debug_counters.format_counter(&counter_kind), + ) + } else { + format!( + "non-coverage counter found without a dependent expression, in {:?}; \ + counter={}", + target_bcb, + debug_counters.format_counter(&counter_kind), + ) + }; + + if debug_options().allow_unused_expressions { + debug!("WARNING: {}", unused_counter_message); + } else { + bug!("{}", unused_counter_message); } } } diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 60461691e7f..b6b0463614d 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -199,12 +199,8 @@ impl CoverageGraph { } #[inline(always)] - pub fn rank_partial_cmp( - &self, - a: BasicCoverageBlock, - b: BasicCoverageBlock, - ) -> Option { - self.dominators.as_ref().unwrap().rank_partial_cmp(a, b) + pub fn cmp_in_dominator_order(&self, a: BasicCoverageBlock, b: BasicCoverageBlock) -> Ordering { + self.dominators.as_ref().unwrap().cmp_in_dominator_order(a, b) } } diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 717763a94a0..32e8ca25d31 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -12,7 +12,6 @@ use rustc_span::source_map::original_sp; use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol}; use std::cell::OnceCell; -use std::cmp::Ordering; #[derive(Debug, Copy, Clone)] pub(super) enum CoverageStatement { @@ -333,30 +332,21 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> { initial_spans.push(CoverageSpan::for_fn_sig(self.fn_sig_span)); - initial_spans.sort_unstable_by(|a, b| { - if a.span.lo() == b.span.lo() { - if a.span.hi() == b.span.hi() { - if a.is_in_same_bcb(b) { - Some(Ordering::Equal) - } else { - // Sort equal spans by dominator relationship (so dominators always come - // before the dominated equal spans). When later comparing two spans in - // order, the first will either dominate the second, or they will have no - // dominator relationship. - self.basic_coverage_blocks.rank_partial_cmp(a.bcb, b.bcb) - } - } else { - // Sort hi() in reverse order so shorter spans are attempted after longer spans. - // This guarantees that, if a `prev` span overlaps, and is not equal to, a - // `curr` span, the prev span either extends further left of the curr span, or - // they start at the same position and the prev span extends further right of - // the end of the curr span. - b.span.hi().partial_cmp(&a.span.hi()) - } - } else { - a.span.lo().partial_cmp(&b.span.lo()) - } - .unwrap() + 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 diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index f5cfc4153b8..92abd0c3b6e 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -752,8 +752,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { let param_env = ty::ParamEnv::reveal_all(); let val = match literal.eval(self.tcx, param_env, None) { Ok(v) => v, - Err(ErrorHandled::Reported(_)) => return, - Err(ErrorHandled::TooGeneric) => span_bug!( + Err(ErrorHandled::Reported(..)) => return, + Err(ErrorHandled::TooGeneric(..)) => span_bug!( self.body.source_info(location).span, "collection encountered polymorphic constant: {:?}", literal diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index a6c7eb8d912..90ac436a91f 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -210,7 +210,17 @@ pub struct ParseError { pub label: string::String, pub span: InnerSpan, pub secondary_label: Option<(string::String, InnerSpan)>, - pub should_be_replaced_with_positional_argument: bool, + pub suggestion: Suggestion, +} + +pub enum Suggestion { + None, + /// Replace inline argument with positional argument: + /// `format!("{foo.bar}")` -> `format!("{}", foo.bar)` + UsePositional, + /// Remove `r#` from identifier: + /// `format!("{r#foo}")` -> `format!("{foo}")` + RemoveRawIdent(InnerSpan), } /// The parser structure for interpreting the input format string. This is @@ -365,7 +375,7 @@ impl<'a> Parser<'a> { label: label.into(), span, secondary_label: None, - should_be_replaced_with_positional_argument: false, + suggestion: Suggestion::None, }); } @@ -389,7 +399,7 @@ impl<'a> Parser<'a> { label: label.into(), span, secondary_label: None, - should_be_replaced_with_positional_argument: false, + suggestion: Suggestion::None, }); } @@ -493,7 +503,7 @@ impl<'a> Parser<'a> { label, span: pos.to(pos), secondary_label, - should_be_replaced_with_positional_argument: false, + suggestion: Suggestion::None, }); None @@ -573,7 +583,37 @@ impl<'a> Parser<'a> { Some(ArgumentIs(i)) } else { match self.cur.peek() { - Some(&(_, c)) if rustc_lexer::is_id_start(c) => Some(ArgumentNamed(self.word())), + Some(&(lo, c)) if rustc_lexer::is_id_start(c) => { + let word = self.word(); + + // Recover from `r#ident` in format strings. + // FIXME: use a let chain + if word == "r" { + if let Some((pos, '#')) = self.cur.peek() { + if self.input[pos + 1..] + .chars() + .next() + .is_some_and(rustc_lexer::is_id_start) + { + self.cur.next(); + let word = self.word(); + let prefix_span = self.span(lo, lo + 2); + let full_span = self.span(lo, lo + 2 + word.len()); + self.errors.insert(0, ParseError { + description: "raw identifiers are not supported".to_owned(), + note: Some("identifiers in format strings can be keywords and don't need to be prefixed with `r#`".to_string()), + label: "raw identifier used here".to_owned(), + span: full_span, + secondary_label: None, + suggestion: Suggestion::RemoveRawIdent(prefix_span), + }); + return Some(ArgumentNamed(word)); + } + } + } + + Some(ArgumentNamed(word)) + } // This is an `ArgumentNext`. // Record the fact and do the resolution after parsing the @@ -841,7 +881,7 @@ impl<'a> Parser<'a> { label: "expected `?` to occur after `:`".to_owned(), span: pos.to(pos), secondary_label: None, - should_be_replaced_with_positional_argument: false, + suggestion: Suggestion::None, }, ); } @@ -867,7 +907,7 @@ impl<'a> Parser<'a> { label: "not supported".to_string(), span: InnerSpan::new(arg.position_span.start, field.position_span.end), secondary_label: None, - should_be_replaced_with_positional_argument: true, + suggestion: Suggestion::UsePositional, }, ); } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 56f4b387df8..4f8ce99417a 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -153,6 +153,9 @@ passes_deprecated_annotation_has_no_effect = passes_deprecated_attribute = deprecated attribute must be paired with either stable or unstable attribute +passes_diagnostic_diagnostic_on_unimplemented_only_for_traits = + `#[diagnostic::on_unimplemented]` can only be applied to trait definitions + passes_diagnostic_item_first_defined = the diagnostic item is first defined here diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 879d1dd680c..2d94354e3e1 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -16,6 +16,7 @@ use rustc_hir::{ self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID, }; use rustc_hir::{MethodKind, Target, Unsafety}; +use rustc_macros::LintDiagnostic; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; use rustc_middle::query::Providers; @@ -24,7 +25,7 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, - UNUSED_ATTRIBUTES, + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, }; use rustc_session::parse::feature_err; use rustc_span::symbol::{kw, sym, Symbol}; @@ -36,6 +37,10 @@ use rustc_trait_selection::traits::ObligationCtxt; use std::cell::Cell; use std::collections::hash_map::Entry; +#[derive(LintDiagnostic)] +#[diag(passes_diagnostic_diagnostic_on_unimplemented_only_for_traits)] +pub struct DiagnosticOnUnimplementedOnlyForTraits; + pub(crate) fn target_from_impl_item<'tcx>( tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>, @@ -104,6 +109,9 @@ impl CheckAttrVisitor<'_> { let mut seen = FxHashMap::default(); let attrs = self.tcx.hir().attrs(hir_id); for attr in attrs { + if attr.path_matches(&[sym::diagnostic, sym::on_unimplemented]) { + self.check_diagnostic_on_unimplemented(attr.span, hir_id, target); + } match attr.name_or_empty() { sym::do_not_recommend => self.check_do_not_recommend(attr.span, target), sym::inline => self.check_inline(hir_id, attr, span, target), @@ -139,6 +147,9 @@ impl CheckAttrVisitor<'_> { self.check_rustc_std_internal_symbol(&attr, span, target) } sym::naked => self.check_naked(hir_id, attr, span, target), + sym::rustc_never_returns_null_ptr => { + self.check_applied_to_fn_or_method(hir_id, attr, span, target) + } sym::rustc_legacy_const_generics => { self.check_rustc_legacy_const_generics(hir_id, &attr, span, target, item) } @@ -284,6 +295,18 @@ impl CheckAttrVisitor<'_> { } } + /// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition + fn check_diagnostic_on_unimplemented(&self, attr_span: Span, hir_id: HirId, target: Target) { + if !matches!(target, Target::Trait) { + self.tcx.emit_spanned_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + hir_id, + attr_span, + DiagnosticOnUnimplementedOnlyForTraits, + ); + } + } + /// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid. fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool { match target { diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 4ba0cb31d0b..213e5c8ba68 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -43,9 +43,11 @@ use rustc_data_structures::fingerprint::PackedFingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::Lock; +use rustc_data_structures::unhash::UnhashMap; use rustc_index::{Idx, IndexVec}; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; +use std::iter; use std::marker::PhantomData; // The maximum value of `SerializedDepNodeIndex` leaves the upper two bits @@ -81,8 +83,9 @@ pub struct SerializedDepGraph { /// A flattened list of all edge targets in the graph, stored in the same /// varint encoding that we use on disk. Edge sources are implicit in edge_list_indices. edge_list_data: Vec, - /// Reciprocal map to `nodes`. - index: FxHashMap, SerializedDepNodeIndex>, + /// Stores a map from fingerprints to nodes per dep node kind. + /// This is the reciprocal of `nodes`. + index: Vec>, } impl Default for SerializedDepGraph { @@ -137,7 +140,7 @@ impl SerializedDepGraph { #[inline] pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option { - self.index.get(dep_node).cloned() + self.index.get(dep_node.kind.to_u16() as usize)?.get(&dep_node.hash).cloned() } #[inline] @@ -147,7 +150,7 @@ impl SerializedDepGraph { #[inline] pub fn node_count(&self) -> usize { - self.index.len() + self.nodes.len() } } @@ -220,7 +223,8 @@ impl<'a, K: DepKind + Decodable>> Decodable> for _index in 0..node_count { // Decode the header for this edge; the header packs together as many of the fixed-size // fields as possible to limit the number of times we update decoder state. - let node_header = SerializedNodeHeader { bytes: d.read_array(), _marker: PhantomData }; + let node_header = + SerializedNodeHeader:: { bytes: d.read_array(), _marker: PhantomData }; let _i: SerializedDepNodeIndex = nodes.push(node_header.node()); debug_assert_eq!(_i.index(), _index); @@ -251,8 +255,14 @@ impl<'a, K: DepKind + Decodable>> Decodable> // end of the array. This padding ensure it doesn't. edge_list_data.extend(&[0u8; DEP_NODE_PAD]); - let index: FxHashMap<_, _> = - nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect(); + // Read the number of each dep kind and use it to create an hash map with a suitable size. + let mut index: Vec<_> = (0..(K::MAX as usize + 1)) + .map(|_| UnhashMap::with_capacity_and_hasher(d.read_u32() as usize, Default::default())) + .collect(); + + for (idx, node) in nodes.iter_enumerated() { + index[node.kind.to_u16() as usize].insert(node.hash, idx); + } SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data, index } } @@ -419,6 +429,9 @@ struct EncoderState { total_node_count: usize, total_edge_count: usize, stats: Option>>, + + /// Stores the number of times we've encoded each dep kind. + kind_stats: Vec, } impl EncoderState { @@ -428,6 +441,7 @@ impl EncoderState { total_edge_count: 0, total_node_count: 0, stats: record_stats.then(FxHashMap::default), + kind_stats: iter::repeat(0).take(K::MAX as usize + 1).collect(), } } @@ -438,6 +452,7 @@ impl EncoderState { ) -> DepNodeIndex { let index = DepNodeIndex::new(self.total_node_count); self.total_node_count += 1; + self.kind_stats[node.node.kind.to_u16() as usize] += 1; let edge_count = node.edges.len(); self.total_edge_count += edge_count; @@ -463,11 +478,16 @@ impl EncoderState { } fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult { - let Self { mut encoder, total_node_count, total_edge_count, stats: _ } = self; + let Self { mut encoder, total_node_count, total_edge_count, stats: _, kind_stats } = self; let node_count = total_node_count.try_into().unwrap(); let edge_count = total_edge_count.try_into().unwrap(); + // Encode the number of each dep kind encountered + for count in kind_stats.iter() { + count.encode(&mut encoder); + } + debug!(?node_count, ?edge_count); debug!("position: {:?}", encoder.position()); IntEncodedWithFixedSize(node_count).encode(&mut encoder); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 82060716575..90ae08ce37c 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -26,7 +26,7 @@ use rustc_middle::middle::stability; use rustc_middle::ty::RegisteredTools; use rustc_middle::ty::{TyCtxt, Visibility}; use rustc_session::lint::builtin::{ - LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNKNOWN_DIAGNOSTIC_ATTRIBUTES, + LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, }; use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES}; use rustc_session::lint::BuiltinLintDiagnostics; @@ -610,9 +610,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if res == Res::NonMacroAttr(NonMacroAttrKind::Tool) && path.segments.len() >= 2 && path.segments[0].ident.name == sym::diagnostic + && path.segments[1].ident.name != sym::on_unimplemented { self.tcx.sess.parse_sess.buffer_lint( - UNKNOWN_DIAGNOSTIC_ATTRIBUTES, + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, path.segments[1].span(), node_id, "unknown diagnostic attribute", diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index ba82ee95caa..956ae149e55 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -898,6 +898,9 @@ impl OutFileName { #[derive(Clone, Hash, Debug, HashStable_Generic)] pub struct OutputFilenames { pub out_directory: PathBuf, + /// Crate name. Never contains '-'. + crate_stem: String, + /// Typically based on `.rs` input file name. Any '-' is preserved. filestem: String, pub single_output_file: Option, pub temps_directory: Option, @@ -911,6 +914,7 @@ pub const DWARF_OBJECT_EXT: &str = "dwo"; impl OutputFilenames { pub fn new( out_directory: PathBuf, + out_crate_name: String, out_filestem: String, single_output_file: Option, temps_directory: Option, @@ -922,6 +926,7 @@ impl OutputFilenames { single_output_file, temps_directory, outputs, + crate_stem: format!("{out_crate_name}{extra}"), filestem: format!("{out_filestem}{extra}"), } } @@ -938,7 +943,12 @@ impl OutputFilenames { /// should be placed on disk. pub fn output_path(&self, flavor: OutputType) -> PathBuf { let extension = flavor.extension(); - self.with_directory_and_extension(&self.out_directory, extension) + match flavor { + OutputType::Metadata => { + self.out_directory.join(format!("lib{}.{}", self.crate_stem, extension)) + } + _ => self.with_directory_and_extension(&self.out_directory, extension), + } } /// Gets the path where a compilation artifact of the given type for the diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index c0884fb21cd..7a57b0621cd 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -119,26 +119,11 @@ pub fn validate_crate_name(sess: &Session, s: Symbol, sp: Option) { } } -pub fn filename_for_metadata( - sess: &Session, - crate_name: Symbol, - outputs: &OutputFilenames, -) -> OutFileName { - // If the command-line specified the path, use that directly. - if let Some(Some(out_filename)) = sess.opts.output_types.get(&OutputType::Metadata) { - return out_filename.clone(); - } - - let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename); - - let out_filename = outputs.single_output_file.clone().unwrap_or_else(|| { - OutFileName::Real(outputs.out_directory.join(&format!("lib{libname}.rmeta"))) - }); - +pub fn filename_for_metadata(sess: &Session, outputs: &OutputFilenames) -> OutFileName { + let out_filename = outputs.path(OutputType::Metadata); if let OutFileName::Real(ref path) = out_filename { check_file_is_writeable(path, sess); } - out_filename } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 448314cd9e1..382754be2ca 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -592,6 +592,7 @@ symbols! { cttz, cttz_nonzero, custom_attribute, + custom_code_classes_in_docs, custom_derive, custom_inner_attributes, custom_mir, @@ -1178,7 +1179,6 @@ symbols! { ptr_cast_const, ptr_cast_mut, ptr_const_is_null, - ptr_from_mut, ptr_from_ref, ptr_guaranteed_cmp, ptr_is_null, @@ -1337,6 +1337,7 @@ symbols! { rustc_main, rustc_mir, rustc_must_implement_one_of, + rustc_never_returns_null_ptr, rustc_nonnull_optimization_guaranteed, rustc_nounwind, rustc_object_lifetime_default, diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 1a4a46ceb40..5efd171b9dd 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -2,6 +2,7 @@ use crate::abi::{self, Abi, Align, FieldsShape, Size}; use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout}; use crate::spec::{self, HasTargetSpec}; use rustc_span::Symbol; +use std::fmt; use std::str::FromStr; mod aarch64; @@ -45,17 +46,17 @@ pub enum PassMode { /// /// The argument has a layout abi of `ScalarPair`. Pair(ArgAttributes, ArgAttributes), - /// Pass the argument after casting it, to either a single uniform or a - /// pair of registers. The bool indicates if a `Reg::i32()` dummy argument - /// is emitted before the real argument. - Cast(Box, bool), + /// Pass the argument after casting it. See the `CastTarget` docs for details. The bool + /// indicates if a `Reg::i32()` dummy argument is emitted before the real argument. + Cast { pad_i32: bool, cast: Box }, /// Pass the argument indirectly via a hidden pointer. - /// The `extra_attrs` value, if any, is for the extra data (vtable or length) - /// which indicates that it refers to an unsized rvalue. - /// `on_stack` defines that the value should be passed at a fixed - /// stack offset in accordance to the ABI rather than passed using a - /// pointer. This corresponds to the `byval` LLVM argument attribute. - Indirect { attrs: ArgAttributes, extra_attrs: Option, on_stack: bool }, + /// The `meta_attrs` value, if any, is for the metadata (vtable or length) of an unsized + /// argument. (This is the only mode that supports unsized arguments.) + /// `on_stack` defines that the value should be passed at a fixed stack offset in accordance to + /// the ABI rather than passed using a pointer. This corresponds to the `byval` LLVM argument + /// attribute (using the Rust type of this argument). `on_stack` cannot be true for unsized + /// arguments, i.e., when `meta_attrs` is `Some`. + Indirect { attrs: ArgAttributes, meta_attrs: Option, on_stack: bool }, } impl PassMode { @@ -64,17 +65,20 @@ impl PassMode { /// so that needs to be compared as well! pub fn eq_abi(&self, other: &Self) -> bool { match (self, other) { - (PassMode::Ignore, PassMode::Ignore) => true, // can still be reached for the return type + (PassMode::Ignore, PassMode::Ignore) => true, (PassMode::Direct(a1), PassMode::Direct(a2)) => a1.eq_abi(a2), (PassMode::Pair(a1, b1), PassMode::Pair(a2, b2)) => a1.eq_abi(a2) && b1.eq_abi(b2), - (PassMode::Cast(c1, pad1), PassMode::Cast(c2, pad2)) => c1.eq_abi(c2) && pad1 == pad2, ( - PassMode::Indirect { attrs: a1, extra_attrs: None, on_stack: s1 }, - PassMode::Indirect { attrs: a2, extra_attrs: None, on_stack: s2 }, + PassMode::Cast { cast: c1, pad_i32: pad1 }, + PassMode::Cast { cast: c2, pad_i32: pad2 }, + ) => c1.eq_abi(c2) && pad1 == pad2, + ( + PassMode::Indirect { attrs: a1, meta_attrs: None, on_stack: s1 }, + PassMode::Indirect { attrs: a2, meta_attrs: None, on_stack: s2 }, ) => a1.eq_abi(a2) && s1 == s2, ( - PassMode::Indirect { attrs: a1, extra_attrs: Some(e1), on_stack: s1 }, - PassMode::Indirect { attrs: a2, extra_attrs: Some(e2), on_stack: s2 }, + PassMode::Indirect { attrs: a1, meta_attrs: Some(e1), on_stack: s1 }, + PassMode::Indirect { attrs: a2, meta_attrs: Some(e2), on_stack: s2 }, ) => a1.eq_abi(a2) && e1.eq_abi(e2) && s1 == s2, _ => false, } @@ -255,6 +259,13 @@ impl Uniform { } } +/// Describes the type used for `PassMode::Cast`. +/// +/// Passing arguments in this mode works as follows: the registers in the `prefix` (the ones that +/// are `Some`) get laid out one after the other (using `repr(C)` layout rules). Then the +/// `rest.unit` register type gets repeated often enough to cover `rest.size`. This describes the +/// actual type used for the call; the Rust type of the argument is then transmuted to this ABI type +/// (and all data in the padding between the registers is dropped). #[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] pub struct CastTarget { pub prefix: [Option; 8], @@ -515,12 +526,20 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { /// Information about how to pass an argument to, /// or return a value from, a function, under some ABI. -#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] +#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic)] pub struct ArgAbi<'a, Ty> { pub layout: TyAndLayout<'a, Ty>, pub mode: PassMode, } +// Needs to be a custom impl because of the bounds on the `TyAndLayout` debug impl. +impl<'a, Ty: fmt::Display> fmt::Debug for ArgAbi<'a, Ty> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let ArgAbi { layout, mode } = self; + f.debug_struct("ArgAbi").field("layout", layout).field("mode", mode).finish() + } +} + impl<'a, Ty> ArgAbi<'a, Ty> { /// This defines the "default ABI" for that type, that is then later adjusted in `fn_abi_adjust_for_abi`. pub fn new( @@ -556,15 +575,15 @@ impl<'a, Ty> ArgAbi<'a, Ty> { attrs.pointee_size = layout.size; attrs.pointee_align = Some(layout.align.abi); - let extra_attrs = layout.is_unsized().then_some(ArgAttributes::new()); + let meta_attrs = layout.is_unsized().then_some(ArgAttributes::new()); - PassMode::Indirect { attrs, extra_attrs, on_stack: false } + PassMode::Indirect { attrs, meta_attrs, on_stack: false } } pub fn make_indirect(&mut self) { match self.mode { PassMode::Direct(_) | PassMode::Pair(_, _) => {} - PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: false } => return, + PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: false } => return, _ => panic!("Tried to make {:?} indirect", self.mode), } @@ -574,7 +593,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { pub fn make_indirect_byval(&mut self, byval_align: Option) { self.make_indirect(); match self.mode { - PassMode::Indirect { ref mut attrs, extra_attrs: _, ref mut on_stack } => { + PassMode::Indirect { ref mut attrs, meta_attrs: _, ref mut on_stack } => { *on_stack = true; // Some platforms, like 32-bit x86, change the alignment of the type when passing @@ -607,11 +626,11 @@ impl<'a, Ty> ArgAbi<'a, Ty> { } pub fn cast_to>(&mut self, target: T) { - self.mode = PassMode::Cast(Box::new(target.into()), false); + self.mode = PassMode::Cast { cast: Box::new(target.into()), pad_i32: false }; } pub fn cast_to_and_pad_i32>(&mut self, target: T, pad_i32: bool) { - self.mode = PassMode::Cast(Box::new(target.into()), pad_i32); + self.mode = PassMode::Cast { cast: Box::new(target.into()), pad_i32 }; } pub fn is_indirect(&self) -> bool { @@ -619,11 +638,11 @@ impl<'a, Ty> ArgAbi<'a, Ty> { } pub fn is_sized_indirect(&self) -> bool { - matches!(self.mode, PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ }) + matches!(self.mode, PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ }) } pub fn is_unsized_indirect(&self) -> bool { - matches!(self.mode, PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ }) + matches!(self.mode, PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ }) } pub fn is_ignore(&self) -> bool { @@ -694,7 +713,7 @@ impl RiscvInterruptKind { /// /// I will do my best to describe this structure, but these /// comments are reverse-engineered and may be inaccurate. -NDM -#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] +#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic)] pub struct FnAbi<'a, Ty> { /// The LLVM types of each argument. pub args: Box<[ArgAbi<'a, Ty>]>, @@ -715,6 +734,21 @@ pub struct FnAbi<'a, Ty> { pub can_unwind: bool, } +// Needs to be a custom impl because of the bounds on the `TyAndLayout` debug impl. +impl<'a, Ty: fmt::Display> fmt::Debug for FnAbi<'a, Ty> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let FnAbi { args, ret, c_variadic, fixed_count, conv, can_unwind } = self; + f.debug_struct("FnAbi") + .field("args", args) + .field("ret", ret) + .field("c_variadic", c_variadic) + .field("fixed_count", fixed_count) + .field("conv", conv) + .field("can_unwind", can_unwind) + .finish() + } +} + /// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI. #[derive(Copy, Clone, Debug, HashStable_Generic)] pub enum AdjustForForeignAbiError { diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs index b738c3133d9..afa1b70efc2 100644 --- a/compiler/rustc_target/src/abi/call/x86.rs +++ b/compiler/rustc_target/src/abi/call/x86.rs @@ -142,13 +142,13 @@ where for arg in fn_abi.args.iter_mut() { let attrs = match arg.mode { PassMode::Ignore - | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => { + | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => { continue; } PassMode::Direct(ref mut attrs) => attrs, PassMode::Pair(..) - | PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } - | PassMode::Cast(..) => { + | PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } + | PassMode::Cast { .. } => { unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode) } }; diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index a335585dbf3..636adcf6b17 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -3,6 +3,7 @@ pub use Primitive::*; use crate::json::{Json, ToJson}; +use std::fmt; use std::ops::Deref; use rustc_macros::HashStable_Generic; @@ -24,12 +25,22 @@ impl ToJson for Endian { /// to that obtained from `layout_of(ty)`, as we need to produce /// layouts for which Rust types do not exist, such as enum variants /// or synthetic fields of enums (i.e., discriminants) and fat pointers. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable_Generic)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)] pub struct TyAndLayout<'a, Ty> { pub ty: Ty, pub layout: Layout<'a>, } +impl<'a, Ty: fmt::Display> fmt::Debug for TyAndLayout<'a, Ty> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Print the type in a readable way, not its debug representation. + f.debug_struct("TyAndLayout") + .field("ty", &format_args!("{}", self.ty)) + .field("layout", &self.layout) + .finish() + } +} + impl<'a, Ty> Deref for TyAndLayout<'a, Ty> { type Target = &'a LayoutS; fn deref(&self) -> &&'a LayoutS { diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs index e2df7e0bdcc..b29ab14e7f2 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs @@ -1,5 +1,5 @@ use super::apple_base::{opts, Arch}; -use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, Target, TargetOptions}; +use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet, Target, TargetOptions}; pub fn target() -> Target { let llvm_target = "arm64-apple-ios14.0-macabi"; @@ -7,6 +7,7 @@ pub fn target() -> Target { let arch = Arch::Arm64_macabi; let mut base = opts("ios", arch); base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-target", llvm_target]); + base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD; Target { llvm_target: llvm_target.into(), diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs index 956a5cb5c2f..a99cccd42c4 100644 --- a/compiler/rustc_target/src/spec/abi.rs +++ b/compiler/rustc_target/src/spec/abi.rs @@ -68,7 +68,7 @@ pub enum Abi { impl Abi { pub fn supports_varargs(self) -> bool { // * C and Cdecl obviously support varargs. - // * C can be based on SysV64 or Win64, so they must support varargs. + // * C can be based on Aapcs, SysV64 or Win64, so they must support varargs. // * EfiApi is based on Win64 or C, so it also supports it. // // * Stdcall does not, because it would be impossible for the callee to clean @@ -79,6 +79,7 @@ impl Abi { match self { Self::C { .. } | Self::Cdecl { .. } + | Self::Aapcs { .. } | Self::Win64 { .. } | Self::SysV64 { .. } | Self::EfiApi => true, diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs index 50f359c357b..fd1926f2945 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs @@ -1,5 +1,5 @@ use super::apple_base::{opts, Arch}; -use crate::spec::{Cc, LinkerFlavor, Lld, StackProbeType, Target, TargetOptions}; +use crate::spec::{Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, TargetOptions}; pub fn target() -> Target { let llvm_target = "x86_64-apple-ios14.0-macabi"; @@ -7,6 +7,7 @@ pub fn target() -> Target { let arch = Arch::X86_64_macabi; let mut base = opts("ios", arch); base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-target", llvm_target]); + base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD; Target { llvm_target: llvm_target.into(), diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 2db24c43734..20253b32add 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -27,6 +27,8 @@ trait_selection_inherent_projection_normalization_overflow = overflow evaluating trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-clause in `#[rustc_on_unimplemented]` .label = invalid on-clause here +trait_selection_malformed_on_unimplemented_attr = malformed `on_unimplemented` attribute + trait_selection_negative_positive_conflict = found both positive and negative implementation of trait `{$trait_desc}`{$self_desc -> [none] {""} *[default] {" "}for type `{$self_desc}` diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs index 307c0516f70..7941f64873b 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs @@ -28,8 +28,8 @@ use std::ops::ControlFlow; use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment}; use super::inspect::ProofTreeBuilder; -use super::search_graph; use super::SolverMode; +use super::{search_graph, GoalEvaluationKind}; use super::{search_graph::SearchGraph, Goal}; pub use select::InferCtxtSelectExt; @@ -85,7 +85,7 @@ pub struct EvalCtxt<'a, 'tcx> { // evaluation code. tainted: Result<(), NoSolution>, - inspect: ProofTreeBuilder<'tcx>, + pub(super) inspect: ProofTreeBuilder<'tcx>, } #[derive(Debug, Clone)] @@ -164,7 +164,7 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> { Option>, ) { EvalCtxt::enter_root(self, generate_proof_tree, |ecx| { - ecx.evaluate_goal(IsNormalizesToHack::No, goal) + ecx.evaluate_goal(GoalEvaluationKind::Root, goal) }) } } @@ -340,11 +340,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { /// been constrained and the certainty of the result. fn evaluate_goal( &mut self, - is_normalizes_to_hack: IsNormalizesToHack, + goal_evaluation_kind: GoalEvaluationKind, goal: Goal<'tcx, ty::Predicate<'tcx>>, ) -> Result<(bool, Certainty, Vec>>), NoSolution> { let (orig_values, canonical_goal) = self.canonicalize_goal(goal); - let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, is_normalizes_to_hack); + let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, goal_evaluation_kind); let encountered_overflow = self.search_graph.encountered_overflow(); let canonical_response = EvalCtxt::evaluate_canonical_goal( self.tcx(), @@ -389,7 +389,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // solver cycle. if cfg!(debug_assertions) && has_changed - && is_normalizes_to_hack == IsNormalizesToHack::No + && !matches!( + goal_evaluation_kind, + GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::Yes } + ) && !self.search_graph.in_cycle() { // The nested evaluation has to happen with the original state @@ -561,8 +564,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { }, ); - let (_, certainty, instantiate_goals) = - self.evaluate_goal(IsNormalizesToHack::Yes, unconstrained_goal)?; + let (_, certainty, instantiate_goals) = self.evaluate_goal( + GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::Yes }, + unconstrained_goal, + )?; self.add_goals(instantiate_goals); // Finally, equate the goal's RHS with the unconstrained var. @@ -596,8 +601,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } for goal in goals.goals.drain(..) { - let (has_changed, certainty, instantiate_goals) = - self.evaluate_goal(IsNormalizesToHack::No, goal)?; + let (has_changed, certainty, instantiate_goals) = self.evaluate_goal( + GoalEvaluationKind::Nested { is_normalizes_to_hack: IsNormalizesToHack::No }, + goal, + )?; self.add_goals(instantiate_goals); if has_changed { unchanged_certainty = None; @@ -949,8 +956,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { use rustc_middle::mir::interpret::ErrorHandled; match self.infcx.try_const_eval_resolve(param_env, unevaluated, ty, None) { Ok(ct) => Some(ct), - Err(ErrorHandled::Reported(e)) => Some(ty::Const::new_error(self.tcx(), e.into(), ty)), - Err(ErrorHandled::TooGeneric) => None, + Err(ErrorHandled::Reported(e, _)) => { + Some(ty::Const::new_error(self.tcx(), e.into(), ty)) + } + Err(ErrorHandled::TooGeneric(_)) => None, } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs index f88cfbac3f3..6087b916790 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs @@ -24,13 +24,13 @@ where search_graph: outer_ecx.search_graph, nested_goals: outer_ecx.nested_goals.clone(), tainted: outer_ecx.tainted, - inspect: outer_ecx.inspect.new_goal_candidate(), + inspect: outer_ecx.inspect.new_probe(), }; let r = nested_ecx.infcx.probe(|_| f(&mut nested_ecx)); if !outer_ecx.inspect.is_noop() { let probe_kind = probe_kind(&r); nested_ecx.inspect.probe_kind(probe_kind); - outer_ecx.inspect.goal_candidate(nested_ecx.inspect); + outer_ecx.inspect.finish_probe(nested_ecx.inspect); } r } diff --git a/compiler/rustc_trait_selection/src/solve/inspect.rs b/compiler/rustc_trait_selection/src/solve/inspect.rs index 46025da7683..749bba33c9b 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect.rs @@ -7,13 +7,13 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::DumpSolverProofTree; use super::eval_ctxt::UseGlobalCache; -use super::GenerateProofTree; +use super::{GenerateProofTree, GoalEvaluationKind}; #[derive(Eq, PartialEq, Debug)] pub struct WipGoalEvaluation<'tcx> { pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>, + pub kind: WipGoalEvaluationKind, pub evaluation: Option>, - pub is_normalizes_to_hack: IsNormalizesToHack, pub returned_goals: Vec>>, } @@ -21,8 +21,13 @@ impl<'tcx> WipGoalEvaluation<'tcx> { pub fn finalize(self) -> inspect::GoalEvaluation<'tcx> { inspect::GoalEvaluation { uncanonicalized_goal: self.uncanonicalized_goal, + kind: match self.kind { + WipGoalEvaluationKind::Root => inspect::GoalEvaluationKind::Root, + WipGoalEvaluationKind::Nested { is_normalizes_to_hack } => { + inspect::GoalEvaluationKind::Nested { is_normalizes_to_hack } + } + }, evaluation: self.evaluation.unwrap().finalize(), - is_normalizes_to_hack: self.is_normalizes_to_hack, returned_goals: self.returned_goals, } } @@ -30,6 +35,12 @@ impl<'tcx> WipGoalEvaluation<'tcx> { #[derive(Eq, PartialEq, Debug)] pub enum WipGoalEvaluationKind { + Root, + Nested { is_normalizes_to_hack: IsNormalizesToHack }, +} + +#[derive(Eq, PartialEq, Debug)] +pub enum WipCanonicalGoalEvaluationKind { Overflow, CacheHit(CacheHit), } @@ -37,7 +48,7 @@ pub enum WipGoalEvaluationKind { #[derive(Eq, PartialEq, Debug)] pub struct WipCanonicalGoalEvaluation<'tcx> { pub goal: CanonicalInput<'tcx>, - pub kind: Option, + pub kind: Option, pub revisions: Vec>, pub result: Option>, } @@ -45,11 +56,13 @@ pub struct WipCanonicalGoalEvaluation<'tcx> { impl<'tcx> WipCanonicalGoalEvaluation<'tcx> { pub fn finalize(self) -> inspect::CanonicalGoalEvaluation<'tcx> { let kind = match self.kind { - Some(WipGoalEvaluationKind::Overflow) => inspect::GoalEvaluationKind::Overflow, - Some(WipGoalEvaluationKind::CacheHit(hit)) => { - inspect::GoalEvaluationKind::CacheHit(hit) + Some(WipCanonicalGoalEvaluationKind::Overflow) => { + inspect::CanonicalGoalEvaluationKind::Overflow } - None => inspect::GoalEvaluationKind::Uncached { + Some(WipCanonicalGoalEvaluationKind::CacheHit(hit)) => { + inspect::CanonicalGoalEvaluationKind::CacheHit(hit) + } + None => inspect::CanonicalGoalEvaluationKind::Uncached { revisions: self .revisions .into_iter() @@ -87,7 +100,7 @@ impl<'tcx> WipAddedGoalsEvaluation<'tcx> { pub struct WipGoalEvaluationStep<'tcx> { pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>, - pub evaluation: WipGoalCandidate<'tcx>, + pub evaluation: WipProbe<'tcx>, } impl<'tcx> WipGoalEvaluationStep<'tcx> { @@ -102,26 +115,37 @@ impl<'tcx> WipGoalEvaluationStep<'tcx> { } #[derive(Eq, PartialEq, Debug)] -pub struct WipGoalCandidate<'tcx> { - pub added_goals_evaluations: Vec>, - pub candidates: Vec>, +pub struct WipProbe<'tcx> { + pub steps: Vec>, pub kind: Option>, } -impl<'tcx> WipGoalCandidate<'tcx> { - pub fn finalize(self) -> inspect::GoalCandidate<'tcx> { - inspect::GoalCandidate { - added_goals_evaluations: self - .added_goals_evaluations - .into_iter() - .map(WipAddedGoalsEvaluation::finalize) - .collect(), - candidates: self.candidates.into_iter().map(WipGoalCandidate::finalize).collect(), +impl<'tcx> WipProbe<'tcx> { + pub fn finalize(self) -> inspect::Probe<'tcx> { + inspect::Probe { + steps: self.steps.into_iter().map(WipProbeStep::finalize).collect(), kind: self.kind.unwrap(), } } } +#[derive(Eq, PartialEq, Debug)] +pub enum WipProbeStep<'tcx> { + AddGoal(Goal<'tcx, ty::Predicate<'tcx>>), + EvaluateGoals(WipAddedGoalsEvaluation<'tcx>), + NestedProbe(WipProbe<'tcx>), +} + +impl<'tcx> WipProbeStep<'tcx> { + pub fn finalize(self) -> inspect::ProbeStep<'tcx> { + match self { + WipProbeStep::AddGoal(goal) => inspect::ProbeStep::AddGoal(goal), + WipProbeStep::EvaluateGoals(eval) => inspect::ProbeStep::EvaluateGoals(eval.finalize()), + WipProbeStep::NestedProbe(probe) => inspect::ProbeStep::NestedProbe(probe.finalize()), + } + } +} + #[derive(Debug)] pub enum DebugSolver<'tcx> { Root, @@ -129,7 +153,7 @@ pub enum DebugSolver<'tcx> { CanonicalGoalEvaluation(WipCanonicalGoalEvaluation<'tcx>), AddedGoalsEvaluation(WipAddedGoalsEvaluation<'tcx>), GoalEvaluationStep(WipGoalEvaluationStep<'tcx>), - GoalCandidate(WipGoalCandidate<'tcx>), + Probe(WipProbe<'tcx>), } impl<'tcx> From> for DebugSolver<'tcx> { @@ -156,9 +180,9 @@ impl<'tcx> From> for DebugSolver<'tcx> { } } -impl<'tcx> From> for DebugSolver<'tcx> { - fn from(g: WipGoalCandidate<'tcx>) -> DebugSolver<'tcx> { - DebugSolver::GoalCandidate(g) +impl<'tcx> From> for DebugSolver<'tcx> { + fn from(p: WipProbe<'tcx>) -> DebugSolver<'tcx> { + DebugSolver::Probe(p) } } @@ -249,15 +273,20 @@ impl<'tcx> ProofTreeBuilder<'tcx> { self.state.is_none() } - pub fn new_goal_evaluation( + pub(super) fn new_goal_evaluation( &mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>, - is_normalizes_to_hack: IsNormalizesToHack, + kind: GoalEvaluationKind, ) -> ProofTreeBuilder<'tcx> { self.nested(|| WipGoalEvaluation { uncanonicalized_goal: goal, + kind: match kind { + GoalEvaluationKind::Root => WipGoalEvaluationKind::Root, + GoalEvaluationKind::Nested { is_normalizes_to_hack } => { + WipGoalEvaluationKind::Nested { is_normalizes_to_hack } + } + }, evaluation: None, - is_normalizes_to_hack, returned_goals: vec![], }) } @@ -286,7 +315,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } - pub fn goal_evaluation_kind(&mut self, kind: WipGoalEvaluationKind) { + pub fn goal_evaluation_kind(&mut self, kind: WipCanonicalGoalEvaluationKind) { if let Some(this) = self.as_mut() { match this { DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => { @@ -329,11 +358,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { ) -> ProofTreeBuilder<'tcx> { self.nested(|| WipGoalEvaluationStep { instantiated_goal, - evaluation: WipGoalCandidate { - added_goals_evaluations: vec![], - candidates: vec![], - kind: None, - }, + evaluation: WipProbe { steps: vec![], kind: None }, }) } pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<'tcx>) { @@ -350,18 +375,14 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } - pub fn new_goal_candidate(&mut self) -> ProofTreeBuilder<'tcx> { - self.nested(|| WipGoalCandidate { - added_goals_evaluations: vec![], - candidates: vec![], - kind: None, - }) + pub fn new_probe(&mut self) -> ProofTreeBuilder<'tcx> { + self.nested(|| WipProbe { steps: vec![], kind: None }) } pub fn probe_kind(&mut self, probe_kind: ProbeKind<'tcx>) { if let Some(this) = self.as_mut() { match this { - DebugSolver::GoalCandidate(this) => { + DebugSolver::Probe(this) => { assert_eq!(this.kind.replace(probe_kind), None) } _ => unreachable!(), @@ -369,17 +390,32 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } - pub fn goal_candidate(&mut self, candidate: ProofTreeBuilder<'tcx>) { + pub fn add_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) { if let Some(this) = self.as_mut() { - match (this, candidate.state.unwrap().tree) { + match this { + DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { + evaluation: WipProbe { steps, .. }, + .. + }) + | DebugSolver::Probe(WipProbe { steps, .. }) => { + steps.push(WipProbeStep::AddGoal(goal)) + } + _ => unreachable!(), + } + } + } + + pub fn finish_probe(&mut self, probe: ProofTreeBuilder<'tcx>) { + if let Some(this) = self.as_mut() { + match (this, probe.state.unwrap().tree) { ( - DebugSolver::GoalCandidate(WipGoalCandidate { candidates, .. }) + DebugSolver::Probe(WipProbe { steps, .. }) | DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { - evaluation: WipGoalCandidate { candidates, .. }, + evaluation: WipProbe { steps, .. }, .. }), - DebugSolver::GoalCandidate(candidate), - ) => candidates.push(candidate), + DebugSolver::Probe(probe), + ) => steps.push(WipProbeStep::NestedProbe(probe)), _ => unreachable!(), } } @@ -416,14 +452,12 @@ impl<'tcx> ProofTreeBuilder<'tcx> { match (this, added_goals_evaluation.state.unwrap().tree) { ( DebugSolver::GoalEvaluationStep(WipGoalEvaluationStep { - evaluation: WipGoalCandidate { added_goals_evaluations, .. }, + evaluation: WipProbe { steps, .. }, .. }) - | DebugSolver::GoalCandidate(WipGoalCandidate { - added_goals_evaluations, .. - }), + | DebugSolver::Probe(WipProbe { steps, .. }), DebugSolver::AddedGoalsEvaluation(added_goals_evaluation), - ) => added_goals_evaluations.push(added_goals_evaluation), + ) => steps.push(WipProbeStep::EvaluateGoals(added_goals_evaluation)), _ => unreachable!(), } } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index c492408bc76..bd612ce4778 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -19,7 +19,8 @@ use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_infer::traits::query::NoSolution; use rustc_middle::infer::canonical::CanonicalVarInfos; use rustc_middle::traits::solve::{ - CanonicalResponse, Certainty, ExternalConstraintsData, Goal, QueryResult, Response, + CanonicalResponse, Certainty, ExternalConstraintsData, Goal, IsNormalizesToHack, QueryResult, + Response, }; use rustc_middle::ty::{self, Ty, TyCtxt, UniverseIndex}; use rustc_middle::ty::{ @@ -59,6 +60,12 @@ enum SolverMode { Coherence, } +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum GoalEvaluationKind { + Root, + Nested { is_normalizes_to_hack: IsNormalizesToHack }, +} + trait CanonicalResponseExt { fn has_no_inference_or_external_constraints(&self) -> bool; @@ -228,6 +235,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { #[instrument(level = "debug", skip(self))] fn add_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) { + self.inspect.add_goal(goal); self.nested_goals.goals.push(goal); } diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index c816b51f67a..16de518e8e0 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -187,7 +187,7 @@ impl<'tcx> SearchGraph<'tcx> { last.encountered_overflow = true; } - inspect.goal_evaluation_kind(inspect::WipGoalEvaluationKind::Overflow); + inspect.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::Overflow); return Self::response_no_constraints(tcx, input, Certainty::OVERFLOW); }; @@ -203,7 +203,7 @@ impl<'tcx> SearchGraph<'tcx> { available_depth, ) { - inspect.goal_evaluation_kind(inspect::WipGoalEvaluationKind::CacheHit( + inspect.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::CacheHit( CacheHit::Global, )); self.on_cache_hit(reached_depth, encountered_overflow); @@ -240,7 +240,7 @@ impl<'tcx> SearchGraph<'tcx> { // Finally we can return either the provisional response for that goal if we have a // coinductive cycle or an ambiguous result if the cycle is inductive. Entry::Occupied(entry_index) => { - inspect.goal_evaluation_kind(inspect::WipGoalEvaluationKind::CacheHit( + inspect.goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::CacheHit( CacheHit::Provisional, )); diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index ba5000da6cd..8096d7969f3 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -793,7 +793,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { span: tcx.def_span(unevaluated.def), unevaluated: unevaluated, }); - Err(ErrorHandled::Reported(reported.into())) + Err(ErrorHandled::Reported(reported.into(), tcx.def_span(unevaluated.def))) } Err(err) => Err(err), } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 3d0d3812d0c..62ab1e1049b 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -73,13 +73,13 @@ pub fn is_const_evaluatable<'tcx>( ty::ConstKind::Unevaluated(uv) => { let concrete = infcx.const_eval_resolve(param_env, uv, Some(span)); match concrete { - Err(ErrorHandled::TooGeneric) => { + Err(ErrorHandled::TooGeneric(_)) => { Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug( span, "Missing value for constant, but no error reported?", ))) } - Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e.into())), + Err(ErrorHandled::Reported(e, _)) => Err(NotConstEvaluatable::Error(e.into())), Ok(_) => Ok(()), } } @@ -132,7 +132,7 @@ pub fn is_const_evaluatable<'tcx>( .emit() } - Err(ErrorHandled::TooGeneric) => { + Err(ErrorHandled::TooGeneric(_)) => { let err = if uv.has_non_region_infer() { NotConstEvaluatable::MentionsInfer } else if uv.has_non_region_param() { @@ -147,7 +147,7 @@ pub fn is_const_evaluatable<'tcx>( Err(err) } - Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e.into())), + Err(ErrorHandled::Reported(e, _)) => Err(NotConstEvaluatable::Error(e.into())), Ok(_) => Ok(()), } } 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 fe71a9f07df..4086db2ab55 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 @@ -9,6 +9,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt}; use rustc_parse_format::{ParseMode, Parser, Piece, Position}; +use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use std::iter; @@ -336,6 +337,10 @@ pub enum AppendConstMessage { Custom(Symbol), } +#[derive(LintDiagnostic)] +#[diag(trait_selection_malformed_on_unimplemented_attr)] +pub struct NoValueInOnUnimplementedLint; + impl<'tcx> OnUnimplementedDirective { fn parse( tcx: TyCtxt<'tcx>, @@ -343,7 +348,8 @@ impl<'tcx> OnUnimplementedDirective { items: &[NestedMetaItem], span: Span, is_root: bool, - ) -> Result { + is_diagnostic_namespace_variant: bool, + ) -> Result, ErrorGuaranteed> { let mut errored = None; let mut item_iter = items.iter(); @@ -391,7 +397,10 @@ impl<'tcx> OnUnimplementedDirective { note = parse_value(note_)?; continue; } - } else if item.has_name(sym::parent_label) && parent_label.is_none() { + } else if item.has_name(sym::parent_label) + && parent_label.is_none() + && !is_diagnostic_namespace_variant + { if let Some(parent_label_) = item.value_str() { parent_label = parse_value(parent_label_)?; continue; @@ -401,15 +410,30 @@ impl<'tcx> OnUnimplementedDirective { && message.is_none() && label.is_none() && note.is_none() + && !is_diagnostic_namespace_variant + // FIXME(diagnostic_namespace): disallow filters for now { if let Some(items) = item.meta_item_list() { - match Self::parse(tcx, item_def_id, &items, item.span(), false) { - Ok(subcommand) => subcommands.push(subcommand), + match Self::parse( + tcx, + item_def_id, + &items, + item.span(), + false, + is_diagnostic_namespace_variant, + ) { + Ok(Some(subcommand)) => subcommands.push(subcommand), + Ok(None) => bug!( + "This cannot happen for now as we only reach that if `is_diagnostic_namespace_variant` is false" + ), Err(reported) => errored = Some(reported), }; continue; } - } else if item.has_name(sym::append_const_msg) && append_const_msg.is_none() { + } else if item.has_name(sym::append_const_msg) + && append_const_msg.is_none() + && !is_diagnostic_namespace_variant + { if let Some(msg) = item.value_str() { append_const_msg = Some(AppendConstMessage::Custom(msg)); continue; @@ -419,14 +443,23 @@ impl<'tcx> OnUnimplementedDirective { } } - // nothing found - tcx.sess.emit_err(NoValueInOnUnimplemented { span: item.span() }); + if is_diagnostic_namespace_variant { + tcx.emit_spanned_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), + vec![item.span()], + NoValueInOnUnimplementedLint, + ); + } else { + // nothing found + tcx.sess.emit_err(NoValueInOnUnimplemented { span: item.span() }); + } } if let Some(reported) = errored { - Err(reported) + if is_diagnostic_namespace_variant { Ok(None) } else { Err(reported) } } else { - Ok(OnUnimplementedDirective { + Ok(Some(OnUnimplementedDirective { condition, subcommands, message, @@ -434,32 +467,58 @@ impl<'tcx> OnUnimplementedDirective { note, parent_label, append_const_msg, - }) + })) } } pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result, ErrorGuaranteed> { - let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) else { + 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); }; let result = if let Some(items) = attr.meta_item_list() { - Self::parse(tcx, item_def_id, &items, attr.span, true).map(Some) + Self::parse(tcx, item_def_id, &items, attr.span, true, is_diagnostic_namespace_variant) } else if let Some(value) = attr.value_str() { - Ok(Some(OnUnimplementedDirective { - condition: None, - message: None, - subcommands: vec![], - label: Some(OnUnimplementedFormatString::try_parse( - tcx, - item_def_id, - value, + if !is_diagnostic_namespace_variant { + Ok(Some(OnUnimplementedDirective { + condition: None, + message: None, + subcommands: vec![], + label: Some(OnUnimplementedFormatString::try_parse( + tcx, + item_def_id, + value, + attr.span, + )?), + note: None, + parent_label: None, + append_const_msg: None, + })) + } else { + tcx.emit_spanned_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), attr.span, - )?), - note: None, - parent_label: None, - append_const_msg: None, - })) + NoValueInOnUnimplementedLint, + ); + Ok(None) + } + } else if is_diagnostic_namespace_variant { + tcx.emit_spanned_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), + attr.span, + NoValueInOnUnimplementedLint, + ); + Ok(None) } else { let reported = tcx.sess.delay_span_bug(DUMMY_SP, "of_item: neither meta_item_list nor value_str"); diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index f1779451bc5..da357dac415 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -560,30 +560,31 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { let stalled_on = &mut pending_obligation.stalled_on; - let mut evaluate = - |c: Const<'tcx>| { - if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() { - match self.selcx.infcx.try_const_eval_resolve( - obligation.param_env, - unevaluated, - c.ty(), - Some(obligation.cause.span), - ) { - Ok(val) => Ok(val), - Err(e) => match e { - ErrorHandled::TooGeneric => { + let mut evaluate = |c: Const<'tcx>| { + if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() { + match self.selcx.infcx.try_const_eval_resolve( + obligation.param_env, + unevaluated, + c.ty(), + Some(obligation.cause.span), + ) { + Ok(val) => Ok(val), + Err(e) => { + match e { + ErrorHandled::TooGeneric(..) => { stalled_on.extend(unevaluated.args.iter().filter_map( TyOrConstInferVar::maybe_from_generic_arg, )); - Err(ErrorHandled::TooGeneric) } - _ => Err(e), - }, + _ => {} + } + Err(e) } - } else { - Ok(c) } - }; + } else { + Ok(c) + } + }; match (evaluate(c1), evaluate(c2)) { (Ok(c1), Ok(c2)) => { @@ -603,13 +604,14 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ), } } - (Err(ErrorHandled::Reported(reported)), _) - | (_, Err(ErrorHandled::Reported(reported))) => ProcessResult::Error( + (Err(ErrorHandled::Reported(reported, _)), _) + | (_, Err(ErrorHandled::Reported(reported, _))) => ProcessResult::Error( CodeSelectionError(SelectionError::NotConstEvaluatable( NotConstEvaluatable::Error(reported.into()), )), ), - (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { + (Err(ErrorHandled::TooGeneric(_)), _) + | (_, Err(ErrorHandled::TooGeneric(_))) => { if c1.has_non_region_infer() || c2.has_non_region_infer() { ProcessResult::Unchanged } else { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index 979498fb6e6..e415d70479e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -13,7 +13,7 @@ use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::source_map::DUMMY_SP; use smallvec::{smallvec, SmallVec}; -#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)] +#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct ImpliedOutlivesBounds<'tcx> { pub ty: Ty<'tcx>, } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs index 59f4a22ac75..f2c1243f931 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs @@ -6,7 +6,7 @@ use crate::traits::ObligationCtxt; use rustc_middle::traits::query::{DropckOutlivesResult, NoSolution}; use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt}; -#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)] +#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct DropckOutlives<'tcx> { dropped_ty: Ty<'tcx>, } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 0d84fee8309..24d31633850 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -989,9 +989,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Err(_) => Ok(EvaluatedToErr), } } - (Err(ErrorHandled::Reported(_)), _) - | (_, Err(ErrorHandled::Reported(_))) => Ok(EvaluatedToErr), - (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { + (Err(ErrorHandled::Reported(..)), _) + | (_, Err(ErrorHandled::Reported(..))) => Ok(EvaluatedToErr), + (Err(ErrorHandled::TooGeneric(..)), _) + | (_, Err(ErrorHandled::TooGeneric(..))) => { if c1.has_non_region_infer() || c2.has_non_region_infer() { Ok(EvaluatedToAmbig) } else { diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 904f1b38740..a03b82305f0 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -36,6 +36,9 @@ fn layout_of<'tcx>( let (param_env, ty) = query.into_parts(); debug!(?ty); + // Optimization: We convert to RevealAll and convert opaque types in the where bounds + // to their hidden types. This reduces overall uncached invocations of `layout_of` and + // is thus a small performance improvement. let param_env = param_env.with_reveal_all_normalized(tcx); let unnormalized_ty = ty; diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index e348591ebba..5df068de1f8 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -41,7 +41,12 @@ pub trait HashStableContext {} pub trait Interner: Sized { type AdtDef: Clone + Debug + Hash + Ord; - type GenericArgsRef: Clone + DebugWithInfcx + Hash + Ord; + type GenericArgsRef: Clone + + DebugWithInfcx + + Hash + + Ord + + IntoIterator; + type GenericArg: Clone + DebugWithInfcx + Hash + Ord; type DefId: Clone + Debug + Hash + Ord; type Binder; type Ty: Clone + DebugWithInfcx + Hash + Ord; diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index 72bd50ace6d..b574cdcc879 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -517,7 +517,21 @@ impl DebugWithInfcx for TyKind { Int(i) => write!(f, "{i:?}"), Uint(u) => write!(f, "{u:?}"), Float(float) => write!(f, "{float:?}"), - Adt(d, s) => f.debug_tuple_field2_finish("Adt", d, &this.wrap(s)), + Adt(d, s) => { + write!(f, "{d:?}")?; + let mut s = s.clone().into_iter(); + let first = s.next(); + match first { + Some(first) => write!(f, "<{:?}", first)?, + None => return Ok(()), + }; + + for arg in s { + write!(f, ", {:?}", arg)?; + } + + write!(f, ">") + } Foreign(d) => f.debug_tuple_field1_finish("Foreign", d), Str => write!(f, "str"), Array(t, c) => write!(f, "[{:?}; {:?}]", &this.wrap(t), &this.wrap(c)), diff --git a/config.example.toml b/config.example.toml index 2e0558c3f1b..f3c2366d674 100644 --- a/config.example.toml +++ b/config.example.toml @@ -458,7 +458,6 @@ changelog-seen = 2 # Sets the number of codegen units to build the standard library with, # regardless of what the codegen-unit setting for the rest of the compiler is. # NOTE: building with anything other than 1 is known to occasionally have bugs. -# See https://github.com/rust-lang/rust/issues/83600. #codegen-units-std = codegen-units # Whether or not debug assertions are enabled for the compiler and standard library. diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 5965ec2affa..4ef8af9b034 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1015,8 +1015,8 @@ impl VecDeque { /// Shortens the deque, keeping the first `len` elements and dropping /// the rest. /// - /// If `len` is greater than the deque's current length, this has no - /// effect. + /// If `len` is greater or equal to the deque's current length, this has + /// no effect. /// /// # Examples /// diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index fb8d00e8d87..1e2c35bf735 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -177,8 +177,8 @@ //! These are all flags altering the behavior of the formatter. //! //! * `+` - This is intended for numeric types and indicates that the sign -//! should always be printed. Positive signs are never printed by -//! default, and the negative sign is only printed by default for signed values. +//! should always be printed. By default only the negative sign of signed values +//! is printed, and the sign of positive or unsigned values is omitted. //! This flag indicates that the correct sign (`+` or `-`) should always be printed. //! * `-` - Currently not used //! * `#` - This flag indicates that the "alternate" form of printing should diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index e43b6ac4039..f435f503fc1 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -144,7 +144,6 @@ #![feature(ptr_metadata)] #![feature(ptr_sub_ptr)] #![feature(receiver_trait)] -#![feature(saturating_int_impl)] #![feature(set_ptr_value)] #![feature(sized_type_properties)] #![feature(slice_from_ptr_range)] diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index 3f19561e1ac..0f767df6063 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -88,15 +88,19 @@ macro_rules! vec { /// /// A common use for `format!` is concatenation and interpolation of strings. /// The same convention is used with [`print!`] and [`write!`] macros, -/// depending on the intended destination of the string. +/// depending on the intended destination of the string; all these macros internally use [`format_args!`]. /// /// To convert a single value to a string, use the [`to_string`] method. This /// will use the [`Display`] formatting trait. /// +/// To concatenate literals into a `&'static str`, use the [`concat!`] macro. +/// /// [`print!`]: ../std/macro.print.html /// [`write!`]: core::write +/// [`format_args!`]: core::format_args /// [`to_string`]: crate::string::ToString /// [`Display`]: core::fmt::Display +/// [`concat!`]: core::concat /// /// # Panics /// @@ -107,11 +111,11 @@ macro_rules! vec { /// # Examples /// /// ``` -/// format!("test"); -/// format!("hello {}", "world!"); -/// format!("x = {}, y = {y}", 10, y = 30); +/// format!("test"); // => "test" +/// format!("hello {}", "world!"); // => "hello world!" +/// format!("x = {}, y = {val}", 10, val = 30); // => "x = 10, y = 30" /// let (x, y) = (1, 2); -/// format!("{x} + {y} = 3"); +/// format!("{x} + {y} = 3"); // => "1 + 2 = 3" /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index c485680f92e..0fb06b16655 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1304,6 +1304,7 @@ impl Rc { /// assert_eq!(unsafe { &*x_ptr }, "hello"); /// ``` #[stable(feature = "rc_raw", since = "1.17.0")] + #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] pub fn into_raw(this: Self) -> *const T { let ptr = Self::as_ptr(&this); mem::forget(this); @@ -1327,6 +1328,7 @@ impl Rc { /// assert_eq!(unsafe { &*x_ptr }, "hello"); /// ``` #[stable(feature = "weak_into_raw", since = "1.45.0")] + #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] pub fn as_ptr(this: &Self) -> *const T { let ptr: *mut RcBox = NonNull::as_ptr(this.ptr); diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index d3b7558440c..c53e9a5dd7a 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1454,6 +1454,7 @@ impl Arc { /// ``` #[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)] pub fn into_raw(this: Self) -> *const T { let ptr = Self::as_ptr(&this); mem::forget(this); @@ -1478,6 +1479,7 @@ impl Arc { /// ``` #[must_use] #[stable(feature = "rc_as_ptr", since = "1.45.0")] + #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] pub fn as_ptr(this: &Self) -> *const T { let ptr: *mut ArcInner = NonNull::as_ptr(this.ptr); diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index ae7bac0c85f..02331db3341 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1110,8 +1110,8 @@ impl Vec { /// Shortens the vector, keeping the first `len` elements and dropping /// the rest. /// - /// If `len` is greater than the vector's current length, this has no - /// effect. + /// If `len` is greater or equal to the vector's current length, this has + /// no effect. /// /// The [`drain`] method can emulate `truncate`, but causes the excess /// elements to be returned instead of dropped. @@ -1258,6 +1258,7 @@ impl Vec { /// [`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)] #[inline] pub fn as_ptr(&self) -> *const T { // We shadow the slice method of the same name to avoid going through @@ -1317,6 +1318,7 @@ impl Vec { /// [`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)] #[inline] pub fn as_mut_ptr(&mut self) -> *mut T { // We shadow the slice method of the same name to avoid going through diff --git a/library/core/primitive_docs/box_into_raw.md b/library/core/primitive_docs/box_into_raw.md deleted file mode 100644 index 9dd0344c7c7..00000000000 --- a/library/core/primitive_docs/box_into_raw.md +++ /dev/null @@ -1 +0,0 @@ -../std/boxed/struct.Box.html#method.into_raw diff --git a/library/core/primitive_docs/fs_file.md b/library/core/primitive_docs/fs_file.md deleted file mode 100644 index 4023e340a51..00000000000 --- a/library/core/primitive_docs/fs_file.md +++ /dev/null @@ -1 +0,0 @@ -../std/fs/struct.File.html diff --git a/library/core/primitive_docs/io_bufread.md b/library/core/primitive_docs/io_bufread.md deleted file mode 100644 index 7beda2cd390..00000000000 --- a/library/core/primitive_docs/io_bufread.md +++ /dev/null @@ -1 +0,0 @@ -../std/io/trait.BufRead.html diff --git a/library/core/primitive_docs/io_read.md b/library/core/primitive_docs/io_read.md deleted file mode 100644 index b7ecf5e273c..00000000000 --- a/library/core/primitive_docs/io_read.md +++ /dev/null @@ -1 +0,0 @@ -../std/io/trait.Read.html diff --git a/library/core/primitive_docs/io_seek.md b/library/core/primitive_docs/io_seek.md deleted file mode 100644 index db0274d291c..00000000000 --- a/library/core/primitive_docs/io_seek.md +++ /dev/null @@ -1 +0,0 @@ -../std/io/trait.Seek.html diff --git a/library/core/primitive_docs/io_write.md b/library/core/primitive_docs/io_write.md deleted file mode 100644 index 92a3b88a79c..00000000000 --- a/library/core/primitive_docs/io_write.md +++ /dev/null @@ -1 +0,0 @@ -../std/io/trait.Write.html diff --git a/library/core/primitive_docs/net_tosocketaddrs.md b/library/core/primitive_docs/net_tosocketaddrs.md deleted file mode 100644 index 4daa10ddbe2..00000000000 --- a/library/core/primitive_docs/net_tosocketaddrs.md +++ /dev/null @@ -1 +0,0 @@ -../std/net/trait.ToSocketAddrs.html diff --git a/library/core/primitive_docs/process_exit.md b/library/core/primitive_docs/process_exit.md deleted file mode 100644 index cae34d12d52..00000000000 --- a/library/core/primitive_docs/process_exit.md +++ /dev/null @@ -1 +0,0 @@ -../std/process/fn.exit.html diff --git a/library/core/primitive_docs/string_string.md b/library/core/primitive_docs/string_string.md deleted file mode 100644 index 303dc07b185..00000000000 --- a/library/core/primitive_docs/string_string.md +++ /dev/null @@ -1 +0,0 @@ -../std/string/struct.String.html diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs index 5378b210e67..cc872a5343d 100644 --- a/library/core/src/ascii/ascii_char.rs +++ b/library/core/src/ascii/ascii_char.rs @@ -3,7 +3,7 @@ //! suggestions from rustc if you get anything slightly wrong in here, and overall //! helps with clarity as we're also referring to `char` intentionally in here. -use crate::fmt; +use crate::fmt::{self, Write}; use crate::mem::transmute; /// One of the 128 Unicode characters from U+0000 through U+007F, @@ -54,7 +54,7 @@ use crate::mem::transmute; /// [chart]: https://www.unicode.org/charts/PDF/U0000.pdf /// [NIST FIPS 1-2]: https://nvlpubs.nist.gov/nistpubs/Legacy/FIPS/fipspub1-2-1977.pdf /// [NamesList]: https://www.unicode.org/Public/15.0.0/ucd/NamesList.txt -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[unstable(feature = "ascii_char", issue = "110998")] #[repr(u8)] pub enum AsciiChar { @@ -563,3 +563,40 @@ impl fmt::Display for AsciiChar { ::fmt(self.as_str(), f) } } + +#[unstable(feature = "ascii_char", issue = "110998")] +impl fmt::Debug for AsciiChar { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + #[inline] + fn backslash(a: AsciiChar) -> ([AsciiChar; 4], u8) { + ([AsciiChar::ReverseSolidus, a, AsciiChar::Null, AsciiChar::Null], 2) + } + + let (buf, len) = match self { + AsciiChar::Null => backslash(AsciiChar::Digit0), + AsciiChar::CharacterTabulation => backslash(AsciiChar::SmallT), + AsciiChar::CarriageReturn => backslash(AsciiChar::SmallR), + AsciiChar::LineFeed => backslash(AsciiChar::SmallN), + AsciiChar::ReverseSolidus => backslash(AsciiChar::ReverseSolidus), + AsciiChar::Apostrophe => backslash(AsciiChar::Apostrophe), + _ => { + let byte = self.to_u8(); + if !byte.is_ascii_control() { + ([*self, AsciiChar::Null, AsciiChar::Null, AsciiChar::Null], 1) + } else { + const HEX_DIGITS: [AsciiChar; 16] = *b"0123456789abcdef".as_ascii().unwrap(); + + let hi = HEX_DIGITS[usize::from(byte >> 4)]; + let lo = HEX_DIGITS[usize::from(byte & 0xf)]; + ([AsciiChar::ReverseSolidus, AsciiChar::SmallX, hi, lo], 4) + } + } + }; + + f.write_char('\'')?; + for byte in &buf[..len as usize] { + f.write_str(byte.as_str())?; + } + f.write_char('\'') + } +} diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index e6c793a6516..3b4d99221f2 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -556,6 +556,7 @@ impl Cell { #[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)] pub const fn as_ptr(&self) -> *mut T { self.value.get() } @@ -1111,6 +1112,7 @@ impl RefCell { /// ``` #[inline] #[stable(feature = "cell_as_ptr", since = "1.12.0")] + #[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] pub fn as_ptr(&self) -> *mut T { self.value.get() } @@ -2105,6 +2107,7 @@ impl UnsafeCell { #[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)] pub const fn get(&self) -> *mut T { // We can just cast the pointer from `UnsafeCell` to `T` because of // #[repr(transparent)]. This exploits std's special status, there is @@ -2248,6 +2251,7 @@ impl SyncUnsafeCell { /// 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)] pub const fn get(&self) -> *mut T { self.value.get() } diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 6d5133646b5..33226b07e04 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -63,6 +63,11 @@ use self::Ordering::*; /// (transitive) impls are not forced to exist, but these requirements apply /// whenever they do exist. /// +/// Violating these requirements is a logic error. The behavior resulting from a logic error is not +/// specified, but users of the trait must ensure that such logic errors do *not* result in +/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these +/// methods. +/// /// ## Derivable /// /// This trait can be used with `#[derive]`. When `derive`d on structs, two @@ -250,6 +255,11 @@ pub macro PartialEq($item:item) { /// This property cannot be checked by the compiler, and therefore `Eq` implies /// [`PartialEq`], and has no extra methods. /// +/// Violating this property is a logic error. The behavior resulting from a logic error is not +/// specified, but users of the trait must ensure that such logic errors do *not* result in +/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these +/// methods. +/// /// ## Derivable /// /// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has @@ -659,6 +669,11 @@ impl Clone for Reverse { /// It's easy to accidentally make `cmp` and `partial_cmp` disagree by /// deriving some of the traits and manually implementing others. /// +/// Violating these requirements is a logic error. The behavior resulting from a logic error is not +/// specified, but users of the trait must ensure that such logic errors do *not* result in +/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these +/// methods. +/// /// ## Corollaries /// /// From the above and the requirements of `PartialOrd`, it follows that `<` defines a strict total order. @@ -892,6 +907,11 @@ pub macro Ord($item:item) { /// transitively: if `T: PartialOrd` and `U: PartialOrd` then `U: PartialOrd` and `T: /// PartialOrd`. /// +/// Violating these requirements is a logic error. The behavior resulting from a logic error is not +/// specified, but users of the trait must ensure that such logic errors do *not* result in +/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these +/// methods. +/// /// ## Corollaries /// /// The following corollaries follow from the above requirements: @@ -1269,6 +1289,91 @@ pub fn max_by_key K, K: Ord>(v1: T, v2: T, mut f: F) -> T { max_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2))) } +/// Compares and sorts two values, returning minimum and maximum. +/// +/// Returns `[v1, v2]` if the comparison determines them to be equal. +/// +/// # Examples +/// +/// ``` +/// #![feature(cmp_minmax)] +/// use std::cmp; +/// +/// assert_eq!(cmp::minmax(1, 2), [1, 2]); +/// assert_eq!(cmp::minmax(2, 2), [2, 2]); +/// +/// // You can destructure the result using array patterns +/// let [min, max] = cmp::minmax(42, 17); +/// assert_eq!(min, 17); +/// assert_eq!(max, 42); +/// ``` +#[inline] +#[must_use] +#[unstable(feature = "cmp_minmax", issue = "115939")] +pub fn minmax(v1: T, v2: T) -> [T; 2] +where + T: Ord, +{ + if v1 <= v2 { [v1, v2] } else { [v2, v1] } +} + +/// Returns minimum and maximum values with respect to the specified comparison function. +/// +/// Returns `[v1, v2]` if the comparison determines them to be equal. +/// +/// # Examples +/// +/// ``` +/// #![feature(cmp_minmax)] +/// use std::cmp; +/// +/// assert_eq!(cmp::minmax_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), [1, -2]); +/// assert_eq!(cmp::minmax_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), [-2, 2]); +/// +/// // You can destructure the result using array patterns +/// let [min, max] = cmp::minmax_by(-42, 17, |x: &i32, y: &i32| x.abs().cmp(&y.abs())); +/// assert_eq!(min, 17); +/// assert_eq!(max, -42); +/// ``` +#[inline] +#[must_use] +#[unstable(feature = "cmp_minmax", issue = "115939")] +pub fn minmax_by(v1: T, v2: T, compare: F) -> [T; 2] +where + F: FnOnce(&T, &T) -> Ordering, +{ + if compare(&v1, &v2).is_le() { [v1, v2] } else { [v2, v1] } +} + +/// Returns minimum and maximum values with respect to the specified key function. +/// +/// Returns `[v1, v2]` if the comparison determines them to be equal. +/// +/// # Examples +/// +/// ``` +/// #![feature(cmp_minmax)] +/// use std::cmp; +/// +/// assert_eq!(cmp::minmax_by_key(-2, 1, |x: &i32| x.abs()), [1, -2]); +/// assert_eq!(cmp::minmax_by_key(-2, 2, |x: &i32| x.abs()), [-2, 2]); +/// +/// // You can destructure the result using array patterns +/// let [min, max] = cmp::minmax_by_key(-42, 17, |x: &i32| x.abs()); +/// assert_eq!(min, 17); +/// assert_eq!(max, -42); +/// ``` +#[inline] +#[must_use] +#[unstable(feature = "cmp_minmax", issue = "115939")] +pub fn minmax_by_key(v1: T, v2: T, mut f: F) -> [T; 2] +where + F: FnMut(&T) -> K, + K: Ord, +{ + minmax_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2))) +} + // Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types mod impls { use crate::cmp::Ordering::{self, Equal, Greater, Less}; diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 163a65c909e..7e4077db935 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -511,6 +511,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)] pub const fn as_ptr(&self) -> *const c_char { self.inner.as_ptr() } diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs index d2c9f980042..9227248041e 100644 --- a/library/core/src/fmt/builders.rs +++ b/library/core/src/fmt/builders.rs @@ -40,6 +40,14 @@ impl fmt::Write for PadAdapter<'_, '_> { Ok(()) } + + fn write_char(&mut self, c: char) -> fmt::Result { + if self.state.on_newline { + self.buf.write_str(" ")?; + } + self.state.on_newline = c == '\n'; + self.buf.write_char(c) + } } /// A struct to help with [`fmt::Debug`](Debug) implementations. diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 9ce6093f1d1..8204b3855bd 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -188,8 +188,28 @@ pub trait Write { /// assert_eq!(&buf, "world"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - fn write_fmt(mut self: &mut Self, args: Arguments<'_>) -> Result { - write(&mut self, args) + fn write_fmt(&mut self, args: Arguments<'_>) -> Result { + // We use a specialization for `Sized` types to avoid an indirection + // through `&mut self` + trait SpecWriteFmt { + fn spec_write_fmt(self, args: Arguments<'_>) -> Result; + } + + impl SpecWriteFmt for &mut W { + #[inline] + default fn spec_write_fmt(mut self, args: Arguments<'_>) -> Result { + write(&mut self, args) + } + } + + impl SpecWriteFmt for &mut W { + #[inline] + fn spec_write_fmt(self, args: Arguments<'_>) -> Result { + write(self, args) + } + } + + self.spec_write_fmt(args) } } diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index 794a57f0922..35b757dc1ee 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -153,6 +153,11 @@ mod sip; /// Thankfully, you won't need to worry about upholding this property when /// deriving both [`Eq`] and `Hash` with `#[derive(PartialEq, Eq, Hash)]`. /// +/// Violating this property is a logic error. The behavior resulting from a logic error is not +/// specified, but users of the trait must ensure that such logic errors do *not* result in +/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these +/// methods. +/// /// ## Prefix collisions /// /// Implementations of `hash` should ensure that the data they diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 75c104ce2fa..4bf3da07354 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -175,34 +175,27 @@ pub fn spin_loop() { unsafe { crate::arch::x86_64::_mm_pause() }; } - // RISC-V platform spin loop hint implementation + #[cfg(target_arch = "riscv32")] { - // RISC-V RV32 and RV64 share the same PAUSE instruction, but they are located in different - // modules in `core::arch`. - // In this case, here we call `pause` function in each core arch module. - #[cfg(target_arch = "riscv32")] - { - crate::arch::riscv32::pause(); - } - #[cfg(target_arch = "riscv64")] - { - crate::arch::riscv64::pause(); - } + crate::arch::riscv32::pause(); } - #[cfg(any(target_arch = "aarch64", all(target_arch = "arm", target_feature = "v6")))] + #[cfg(target_arch = "riscv64")] { - #[cfg(target_arch = "aarch64")] - { - // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets. - unsafe { crate::arch::aarch64::__isb(crate::arch::aarch64::SY) }; - } - #[cfg(target_arch = "arm")] - { - // SAFETY: the `cfg` attr ensures that we only execute this on arm targets - // with support for the v6 feature. - unsafe { crate::arch::arm::__yield() }; - } + crate::arch::riscv64::pause(); + } + + #[cfg(target_arch = "aarch64")] + { + // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets. + unsafe { crate::arch::aarch64::__isb(crate::arch::aarch64::SY) }; + } + + #[cfg(all(target_arch = "arm", target_feature = "v6"))] + { + // SAFETY: the `cfg` attr ensures that we only execute this on arm targets + // with support for the v6 feature. + unsafe { crate::arch::arm::__yield() }; } } diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 44feb0a5638..0e03d0c2d4e 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -1,6 +1,7 @@ use crate::ascii::Char as AsciiChar; use crate::convert::TryFrom; use crate::mem; +use crate::net::{Ipv4Addr, Ipv6Addr}; use crate::num::NonZeroUsize; use crate::ops::{self, Try}; @@ -15,7 +16,7 @@ macro_rules! unsafe_impl_trusted_step { unsafe impl TrustedStep for $type {} )*}; } -unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize]; +unsafe_impl_trusted_step![AsciiChar char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize Ipv4Addr Ipv6Addr]; /// Objects that have a notion of *successor* and *predecessor* operations. /// @@ -527,6 +528,70 @@ impl Step for AsciiChar { } } +#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] +impl Step for Ipv4Addr { + #[inline] + fn steps_between(&start: &Ipv4Addr, &end: &Ipv4Addr) -> Option { + u32::steps_between(&start.to_bits(), &end.to_bits()) + } + + #[inline] + fn forward_checked(start: Ipv4Addr, count: usize) -> Option { + u32::forward_checked(start.to_bits(), count).map(Ipv4Addr::from_bits) + } + + #[inline] + fn backward_checked(start: Ipv4Addr, count: usize) -> Option { + u32::backward_checked(start.to_bits(), count).map(Ipv4Addr::from_bits) + } + + #[inline] + unsafe fn forward_unchecked(start: Ipv4Addr, count: usize) -> Ipv4Addr { + // SAFETY: Since u32 and Ipv4Addr are losslessly convertible, + // this is as safe as the u32 version. + Ipv4Addr::from_bits(unsafe { u32::forward_unchecked(start.to_bits(), count) }) + } + + #[inline] + unsafe fn backward_unchecked(start: Ipv4Addr, count: usize) -> Ipv4Addr { + // SAFETY: Since u32 and Ipv4Addr are losslessly convertible, + // this is as safe as the u32 version. + Ipv4Addr::from_bits(unsafe { u32::backward_unchecked(start.to_bits(), count) }) + } +} + +#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] +impl Step for Ipv6Addr { + #[inline] + fn steps_between(&start: &Ipv6Addr, &end: &Ipv6Addr) -> Option { + u128::steps_between(&start.to_bits(), &end.to_bits()) + } + + #[inline] + fn forward_checked(start: Ipv6Addr, count: usize) -> Option { + u128::forward_checked(start.to_bits(), count).map(Ipv6Addr::from_bits) + } + + #[inline] + fn backward_checked(start: Ipv6Addr, count: usize) -> Option { + u128::backward_checked(start.to_bits(), count).map(Ipv6Addr::from_bits) + } + + #[inline] + unsafe fn forward_unchecked(start: Ipv6Addr, count: usize) -> Ipv6Addr { + // SAFETY: Since u128 and Ipv6Addr are losslessly convertible, + // this is as safe as the u128 version. + Ipv6Addr::from_bits(unsafe { u128::forward_unchecked(start.to_bits(), count) }) + } + + #[inline] + unsafe fn backward_unchecked(start: Ipv6Addr, count: usize) -> Ipv6Addr { + // SAFETY: Since u128 and Ipv6Addr are losslessly convertible, + // this is as safe as the u128 version. + Ipv6Addr::from_bits(unsafe { u128::backward_unchecked(start.to_bits(), count) }) + } +} + macro_rules! range_exact_iter_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] @@ -765,6 +830,15 @@ impl Iterator for ops::Range { } } + #[inline] + fn count(self) -> usize { + if self.start < self.end { + Step::steps_between(&self.start, &self.end).expect("count overflowed usize") + } else { + 0 + } + } + #[inline] fn nth(&mut self, n: usize) -> Option { self.spec_nth(n) @@ -1162,6 +1236,17 @@ impl Iterator for ops::RangeInclusive { } } + #[inline] + fn count(self) -> usize { + if self.is_empty() { + return 0; + } + + Step::steps_between(&self.start, &self.end) + .and_then(|steps| steps.checked_add(1)) + .expect("count overflowed usize") + } + #[inline] fn nth(&mut self, n: usize) -> Option { if self.is_empty() { diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 7c08d1703cc..b5458e667ed 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -166,7 +166,6 @@ #![feature(const_slice_split_at_mut)] #![feature(const_str_from_utf8_unchecked_mut)] #![feature(const_swap)] -#![feature(const_transmute_copy)] #![feature(const_try)] #![feature(const_type_id)] #![feature(const_type_name)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 46628bcea00..646100fe27b 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1044,7 +1044,7 @@ pub(crate) mod builtin { /// expression of type `&'static str` which represents all of the literals /// concatenated left-to-right. /// - /// Integer and floating point literals are stringified in order to be + /// Integer and floating point literals are [stringified](core::stringify) in order to be /// concatenated. /// /// # Examples diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index bc701d97bbb..d7abc9a0e23 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1051,7 +1051,7 @@ pub const fn copy(x: &T) -> T { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_transmute_copy", issue = "83165")] +#[rustc_const_stable(feature = "const_transmute_copy", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn transmute_copy(src: &Src) -> Dst { assert!( size_of::() >= size_of::(), diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 95dcaf5dd73..4232319fecb 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -44,11 +44,10 @@ mod uint_macros; // import uint_impl! mod error; mod int_log10; mod nonzero; -#[unstable(feature = "saturating_int_impl", issue = "87920")] mod saturating; mod wrapping; -#[unstable(feature = "saturating_int_impl", issue = "87920")] +#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] 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 e9f794e7d62..5757e7498ad 100644 --- a/library/core/src/num/saturating.rs +++ b/library/core/src/num/saturating.rs @@ -4,7 +4,7 @@ use crate::fmt; use crate::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign}; use crate::ops::{BitXor, BitXorAssign, Div, DivAssign}; use crate::ops::{Mul, MulAssign, Neg, Not, Rem, RemAssign}; -use crate::ops::{Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign}; +use crate::ops::{Sub, SubAssign}; /// Provides intentionally-saturating arithmetic on `T`. /// @@ -24,7 +24,6 @@ use crate::ops::{Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign}; /// # Examples /// /// ``` -/// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// /// let max = Saturating(u32::MAX); @@ -32,181 +31,186 @@ use crate::ops::{Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign}; /// /// assert_eq!(u32::MAX, (max + one).0); /// ``` -#[unstable(feature = "saturating_int_impl", issue = "87920")] +#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)] #[repr(transparent)] #[rustc_diagnostic_item = "Saturating"] -pub struct Saturating(#[unstable(feature = "saturating_int_impl", issue = "87920")] pub T); +pub struct Saturating( + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] pub T, +); -#[unstable(feature = "saturating_int_impl", issue = "87920")] +#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl fmt::Debug for Saturating { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -#[unstable(feature = "saturating_int_impl", issue = "87920")] +#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl fmt::Display for Saturating { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -#[unstable(feature = "saturating_int_impl", issue = "87920")] +#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl fmt::Binary for Saturating { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -#[unstable(feature = "saturating_int_impl", issue = "87920")] +#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl fmt::Octal for Saturating { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -#[unstable(feature = "saturating_int_impl", issue = "87920")] +#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl fmt::LowerHex for Saturating { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -#[unstable(feature = "saturating_int_impl", issue = "87920")] +#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl fmt::UpperHex for Saturating { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -#[allow(unused_macros)] -macro_rules! sh_impl_signed { - ($t:ident, $f:ident) => { - // FIXME what is the correct implementation here? see discussion https://github.com/rust-lang/rust/pull/87921#discussion_r695870065 - // - // #[unstable(feature = "saturating_int_impl", issue = "87920")] - // impl Shl<$f> for Saturating<$t> { - // type Output = Saturating<$t>; - // - // #[inline] - // fn shl(self, other: $f) -> Saturating<$t> { - // if other < 0 { - // Saturating(self.0.shr((-other & self::shift_max::$t as $f) as u32)) - // } else { - // Saturating(self.0.shl((other & self::shift_max::$t as $f) as u32)) - // } - // } - // } - // forward_ref_binop! { impl Shl, shl for Saturating<$t>, $f, - // #[unstable(feature = "saturating_int_impl", issue = "87920")] } - // - // #[unstable(feature = "saturating_int_impl", issue = "87920")] - // impl ShlAssign<$f> for Saturating<$t> { - // #[inline] - // fn shl_assign(&mut self, other: $f) { - // *self = *self << other; - // } - // } - // forward_ref_op_assign! { impl ShlAssign, shl_assign for Saturating<$t>, $f } - #[unstable(feature = "saturating_int_impl", issue = "87920")] - impl Shr<$f> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn shr(self, other: $f) -> Saturating<$t> { - if other < 0 { - Saturating(self.0.shl((-other & self::shift_max::$t as $f) as u32)) - } else { - Saturating(self.0.shr((other & self::shift_max::$t as $f) as u32)) - } - } - } - forward_ref_binop! { impl Shr, shr for Saturating<$t>, $f, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } - - #[unstable(feature = "saturating_int_impl", issue = "87920")] - impl ShrAssign<$f> for Saturating<$t> { - #[inline] - fn shr_assign(&mut self, other: $f) { - *self = *self >> other; - } - } - forward_ref_op_assign! { impl ShrAssign, shr_assign for Saturating<$t>, $f } - }; -} - -macro_rules! sh_impl_unsigned { - ($t:ident, $f:ident) => { - #[unstable(feature = "saturating_int_impl", issue = "87920")] - impl Shl<$f> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn shl(self, other: $f) -> Saturating<$t> { - Saturating(self.0.wrapping_shl(other as u32)) - } - } - forward_ref_binop! { impl Shl, shl for Saturating<$t>, $f, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } - - #[unstable(feature = "saturating_int_impl", issue = "87920")] - impl ShlAssign<$f> for Saturating<$t> { - #[inline] - fn shl_assign(&mut self, other: $f) { - *self = *self << other; - } - } - forward_ref_op_assign! { impl ShlAssign, shl_assign for Saturating<$t>, $f } - - #[unstable(feature = "saturating_int_impl", issue = "87920")] - impl Shr<$f> for Saturating<$t> { - type Output = Saturating<$t>; - - #[inline] - fn shr(self, other: $f) -> Saturating<$t> { - Saturating(self.0.wrapping_shr(other as u32)) - } - } - forward_ref_binop! { impl Shr, shr for Saturating<$t>, $f, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } - - #[unstable(feature = "saturating_int_impl", issue = "87920")] - impl ShrAssign<$f> for Saturating<$t> { - #[inline] - fn shr_assign(&mut self, other: $f) { - *self = *self >> other; - } - } - forward_ref_op_assign! { impl ShrAssign, shr_assign for Saturating<$t>, $f } - }; -} - -// FIXME (#23545): uncomment the remaining impls -macro_rules! sh_impl_all { - ($($t:ident)*) => ($( - //sh_impl_unsigned! { $t, u8 } - //sh_impl_unsigned! { $t, u16 } - //sh_impl_unsigned! { $t, u32 } - //sh_impl_unsigned! { $t, u64 } - //sh_impl_unsigned! { $t, u128 } - sh_impl_unsigned! { $t, usize } - - //sh_impl_signed! { $t, i8 } - //sh_impl_signed! { $t, i16 } - //sh_impl_signed! { $t, i32 } - //sh_impl_signed! { $t, i64 } - //sh_impl_signed! { $t, i128 } - //sh_impl_signed! { $t, isize } - )*) -} - -sh_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } +// FIXME the correct implementation is not clear. Waiting for a real world use case at https://github.com/rust-lang/libs-team/issues/230 +// +// #[allow(unused_macros)] +// macro_rules! sh_impl_signed { +// ($t:ident, $f:ident) => { +// // FIXME what is the correct implementation here? see discussion https://github.com/rust-lang/rust/pull/87921#discussion_r695870065 +// // +// // #[unstable(feature = "saturating_int_impl", issue = "87920")] +// // impl Shl<$f> for Saturating<$t> { +// // type Output = Saturating<$t>; +// // +// // #[inline] +// // fn shl(self, other: $f) -> Saturating<$t> { +// // if other < 0 { +// // Saturating(self.0.shr((-other & self::shift_max::$t as $f) as u32)) +// // } else { +// // Saturating(self.0.shl((other & self::shift_max::$t as $f) as u32)) +// // } +// // } +// // } +// // forward_ref_binop! { impl Shl, shl for Saturating<$t>, $f, +// // #[unstable(feature = "saturating_int_impl", issue = "87920")] } +// // +// // #[unstable(feature = "saturating_int_impl", issue = "87920")] +// // impl ShlAssign<$f> for Saturating<$t> { +// // #[inline] +// // fn shl_assign(&mut self, other: $f) { +// // *self = *self << other; +// // } +// // } +// // forward_ref_op_assign! { impl ShlAssign, shl_assign for Saturating<$t>, $f } +// +// #[unstable(feature = "saturating_int_impl", issue = "87920")] +// impl Shr<$f> for Saturating<$t> { +// type Output = Saturating<$t>; +// +// #[inline] +// fn shr(self, other: $f) -> Saturating<$t> { +// if other < 0 { +// Saturating(self.0.shl((-other & self::shift_max::$t as $f) as u32)) +// } else { +// Saturating(self.0.shr((other & self::shift_max::$t as $f) as u32)) +// } +// } +// } +// forward_ref_binop! { impl Shr, shr for Saturating<$t>, $f, +// #[unstable(feature = "saturating_int_impl", issue = "87920")] } +// +// #[unstable(feature = "saturating_int_impl", issue = "87920")] +// impl ShrAssign<$f> for Saturating<$t> { +// #[inline] +// fn shr_assign(&mut self, other: $f) { +// *self = *self >> other; +// } +// } +// forward_ref_op_assign! { impl ShrAssign, shr_assign for Saturating<$t>, $f } +// }; +// } +// +// macro_rules! sh_impl_unsigned { +// ($t:ident, $f:ident) => { +// #[unstable(feature = "saturating_int_impl", issue = "87920")] +// impl Shl<$f> for Saturating<$t> { +// type Output = Saturating<$t>; +// +// #[inline] +// fn shl(self, other: $f) -> Saturating<$t> { +// Saturating(self.0.wrapping_shl(other as u32)) +// } +// } +// forward_ref_binop! { impl Shl, shl for Saturating<$t>, $f, +// #[unstable(feature = "saturating_int_impl", issue = "87920")] } +// +// #[unstable(feature = "saturating_int_impl", issue = "87920")] +// impl ShlAssign<$f> for Saturating<$t> { +// #[inline] +// fn shl_assign(&mut self, other: $f) { +// *self = *self << other; +// } +// } +// forward_ref_op_assign! { impl ShlAssign, shl_assign for Saturating<$t>, $f } +// +// #[unstable(feature = "saturating_int_impl", issue = "87920")] +// impl Shr<$f> for Saturating<$t> { +// type Output = Saturating<$t>; +// +// #[inline] +// fn shr(self, other: $f) -> Saturating<$t> { +// Saturating(self.0.wrapping_shr(other as u32)) +// } +// } +// forward_ref_binop! { impl Shr, shr for Saturating<$t>, $f, +// #[unstable(feature = "saturating_int_impl", issue = "87920")] } +// +// #[unstable(feature = "saturating_int_impl", issue = "87920")] +// impl ShrAssign<$f> for Saturating<$t> { +// #[inline] +// fn shr_assign(&mut self, other: $f) { +// *self = *self >> other; +// } +// } +// forward_ref_op_assign! { impl ShrAssign, shr_assign for Saturating<$t>, $f } +// }; +// } +// +// // FIXME (#23545): uncomment the remaining impls +// macro_rules! sh_impl_all { +// ($($t:ident)*) => ($( +// //sh_impl_unsigned! { $t, u8 } +// //sh_impl_unsigned! { $t, u16 } +// //sh_impl_unsigned! { $t, u32 } +// //sh_impl_unsigned! { $t, u64 } +// //sh_impl_unsigned! { $t, u128 } +// sh_impl_unsigned! { $t, usize } +// +// //sh_impl_signed! { $t, i8 } +// //sh_impl_signed! { $t, i16 } +// //sh_impl_signed! { $t, i32 } +// //sh_impl_signed! { $t, i64 } +// //sh_impl_signed! { $t, i128 } +// //sh_impl_signed! { $t, isize } +// )*) +// } +// +// sh_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } // FIXME(30524): impl Op for Saturating, impl OpAssign for Saturating macro_rules! saturating_impl { ($($t:ty)*) => ($( - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl Add for Saturating<$t> { type Output = Saturating<$t>; @@ -216,9 +220,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl Add, add for Saturating<$t>, Saturating<$t>, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl AddAssign for Saturating<$t> { #[inline] fn add_assign(&mut self, other: Saturating<$t>) { @@ -227,7 +231,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl AddAssign, add_assign for Saturating<$t>, Saturating<$t> } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] + #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")] impl AddAssign<$t> for Saturating<$t> { #[inline] fn add_assign(&mut self, other: $t) { @@ -236,7 +240,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl AddAssign, add_assign for Saturating<$t>, $t } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl Sub for Saturating<$t> { type Output = Saturating<$t>; @@ -246,9 +250,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl Sub, sub for Saturating<$t>, Saturating<$t>, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl SubAssign for Saturating<$t> { #[inline] fn sub_assign(&mut self, other: Saturating<$t>) { @@ -257,7 +261,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl SubAssign, sub_assign for Saturating<$t>, Saturating<$t> } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] + #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")] impl SubAssign<$t> for Saturating<$t> { #[inline] fn sub_assign(&mut self, other: $t) { @@ -266,7 +270,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl SubAssign, sub_assign for Saturating<$t>, $t } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl Mul for Saturating<$t> { type Output = Saturating<$t>; @@ -276,9 +280,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl Mul, mul for Saturating<$t>, Saturating<$t>, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl MulAssign for Saturating<$t> { #[inline] fn mul_assign(&mut self, other: Saturating<$t>) { @@ -287,7 +291,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl MulAssign, mul_assign for Saturating<$t>, Saturating<$t> } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] + #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")] impl MulAssign<$t> for Saturating<$t> { #[inline] fn mul_assign(&mut self, other: $t) { @@ -301,7 +305,6 @@ macro_rules! saturating_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert_eq!(Saturating(2", stringify!($t), "), Saturating(5", stringify!($t), ") / Saturating(2));")] @@ -310,12 +313,11 @@ macro_rules! saturating_impl { /// ``` /// /// ```should_panic - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("let _ = Saturating(0", stringify!($t), ") / Saturating(0);")] /// ``` - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl Div for Saturating<$t> { type Output = Saturating<$t>; @@ -325,10 +327,10 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl Div, div for Saturating<$t>, Saturating<$t>, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl DivAssign for Saturating<$t> { #[inline] fn div_assign(&mut self, other: Saturating<$t>) { @@ -337,7 +339,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl DivAssign, div_assign for Saturating<$t>, Saturating<$t> } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] + #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")] impl DivAssign<$t> for Saturating<$t> { #[inline] fn div_assign(&mut self, other: $t) { @@ -346,7 +348,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl DivAssign, div_assign for Saturating<$t>, $t } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl Rem for Saturating<$t> { type Output = Saturating<$t>; @@ -356,9 +358,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl Rem, rem for Saturating<$t>, Saturating<$t>, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl RemAssign for Saturating<$t> { #[inline] fn rem_assign(&mut self, other: Saturating<$t>) { @@ -367,7 +369,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl RemAssign, rem_assign for Saturating<$t>, Saturating<$t> } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] + #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")] impl RemAssign<$t> for Saturating<$t> { #[inline] fn rem_assign(&mut self, other: $t) { @@ -376,7 +378,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl RemAssign, rem_assign for Saturating<$t>, $t } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl Not for Saturating<$t> { type Output = Saturating<$t>; @@ -386,9 +388,9 @@ macro_rules! saturating_impl { } } forward_ref_unop! { impl Not, not for Saturating<$t>, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl BitXor for Saturating<$t> { type Output = Saturating<$t>; @@ -398,9 +400,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl BitXor, bitxor for Saturating<$t>, Saturating<$t>, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl BitXorAssign for Saturating<$t> { #[inline] fn bitxor_assign(&mut self, other: Saturating<$t>) { @@ -409,7 +411,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Saturating<$t>, Saturating<$t> } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] + #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")] impl BitXorAssign<$t> for Saturating<$t> { #[inline] fn bitxor_assign(&mut self, other: $t) { @@ -418,7 +420,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Saturating<$t>, $t } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl BitOr for Saturating<$t> { type Output = Saturating<$t>; @@ -428,9 +430,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl BitOr, bitor for Saturating<$t>, Saturating<$t>, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl BitOrAssign for Saturating<$t> { #[inline] fn bitor_assign(&mut self, other: Saturating<$t>) { @@ -439,7 +441,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Saturating<$t>, Saturating<$t> } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] + #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")] impl BitOrAssign<$t> for Saturating<$t> { #[inline] fn bitor_assign(&mut self, other: $t) { @@ -448,7 +450,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Saturating<$t>, $t } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl BitAnd for Saturating<$t> { type Output = Saturating<$t>; @@ -458,9 +460,9 @@ macro_rules! saturating_impl { } } forward_ref_binop! { impl BitAnd, bitand for Saturating<$t>, Saturating<$t>, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl BitAndAssign for Saturating<$t> { #[inline] fn bitand_assign(&mut self, other: Saturating<$t>) { @@ -469,7 +471,7 @@ macro_rules! saturating_impl { } forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Saturating<$t>, Saturating<$t> } - #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] + #[stable(feature = "saturating_int_assign_impl", since = "CURRENT_RUSTC_VERSION")] impl BitAndAssign<$t> for Saturating<$t> { #[inline] fn bitand_assign(&mut self, other: $t) { @@ -493,12 +495,11 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert_eq!(>::MIN, Saturating(", stringify!($t), "::MIN));")] /// ``` - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] pub const MIN: Self = Self(<$t>::MIN); /// Returns the largest value that can be represented by this integer type. @@ -508,12 +509,11 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert_eq!(>::MAX, Saturating(", stringify!($t), "::MAX));")] /// ``` - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] pub const MAX: Self = Self(<$t>::MAX); /// Returns the size of this integer type in bits. @@ -523,12 +523,11 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert_eq!(>::BITS, ", stringify!($t), "::BITS);")] /// ``` - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] pub const BITS: u32 = <$t>::BITS; /// Returns the number of ones in the binary representation of `self`. @@ -538,7 +537,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("let n = Saturating(0b01001100", stringify!($t), ");")] @@ -550,7 +548,8 @@ macro_rules! saturating_int_impl { #[doc(alias = "popcnt")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] pub const fn count_ones(self) -> u32 { self.0.count_ones() } @@ -562,7 +561,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert_eq!(Saturating(!0", stringify!($t), ").count_zeros(), 0);")] @@ -570,7 +568,8 @@ macro_rules! saturating_int_impl { #[inline] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] pub const fn count_zeros(self) -> u32 { self.0.count_zeros() } @@ -582,7 +581,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("let n = Saturating(0b0101000", stringify!($t), ");")] @@ -592,7 +590,8 @@ macro_rules! saturating_int_impl { #[inline] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] pub const fn trailing_zeros(self) -> u32 { self.0.trailing_zeros() } @@ -609,7 +608,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// /// let n: Saturating = Saturating(0x0123456789ABCDEF); @@ -620,7 +618,8 @@ macro_rules! saturating_int_impl { #[inline] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] pub const fn rotate_left(self, n: u32) -> Self { Saturating(self.0.rotate_left(n)) } @@ -637,7 +636,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// /// let n: Saturating = Saturating(0x0123456789ABCDEF); @@ -648,7 +646,8 @@ macro_rules! saturating_int_impl { #[inline] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] pub const fn rotate_right(self, n: u32) -> Self { Saturating(self.0.rotate_right(n)) } @@ -660,7 +659,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// /// let n: Saturating = Saturating(0b0000000_01010101); @@ -674,7 +672,8 @@ macro_rules! saturating_int_impl { #[inline] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] pub const fn swap_bytes(self) -> Self { Saturating(self.0.swap_bytes()) } @@ -689,7 +688,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// /// let n = Saturating(0b0000000_01010101i16); @@ -701,8 +699,8 @@ macro_rules! saturating_int_impl { /// assert_eq!(m, Saturating(-22016)); /// ``` #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] - #[rustc_const_unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn reverse_bits(self) -> Self { @@ -719,7 +717,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("let n = Saturating(0x1A", stringify!($t), ");")] @@ -732,7 +729,8 @@ macro_rules! saturating_int_impl { /// ``` #[inline] #[must_use] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] pub const fn from_be(x: Self) -> Self { Saturating(<$t>::from_be(x.0)) } @@ -747,7 +745,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("let n = Saturating(0x1A", stringify!($t), ");")] @@ -760,7 +757,8 @@ macro_rules! saturating_int_impl { /// ``` #[inline] #[must_use] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] pub const fn from_le(x: Self) -> Self { Saturating(<$t>::from_le(x.0)) } @@ -775,7 +773,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("let n = Saturating(0x1A", stringify!($t), ");")] @@ -787,7 +784,8 @@ macro_rules! saturating_int_impl { /// } /// ``` #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn to_be(self) -> Self { @@ -804,7 +802,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("let n = Saturating(0x1A", stringify!($t), ");")] @@ -816,7 +813,8 @@ macro_rules! saturating_int_impl { /// } /// ``` #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn to_le(self) -> Self { @@ -830,7 +828,6 @@ macro_rules! saturating_int_impl { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert_eq!(Saturating(3", stringify!($t), ").pow(4), Saturating(81));")] @@ -839,17 +836,17 @@ macro_rules! saturating_int_impl { /// Results that are too large are saturated: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// /// assert_eq!(Saturating(3i8).pow(5), Saturating(127)); /// assert_eq!(Saturating(3i8).pow(6), Saturating(127)); /// ``` #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - pub fn pow(self, exp: u32) -> Self { + pub const fn pow(self, exp: u32) -> Self { Saturating(self.0.saturating_pow(exp)) } } @@ -868,7 +865,6 @@ macro_rules! saturating_int_impl_signed { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("let n = Saturating(", stringify!($t), "::MAX >> 2);")] @@ -876,7 +872,8 @@ macro_rules! saturating_int_impl_signed { /// assert_eq!(n.leading_zeros(), 3); /// ``` #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn leading_zeros(self) -> u32 { @@ -891,7 +888,6 @@ macro_rules! saturating_int_impl_signed { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert_eq!(Saturating(100", stringify!($t), ").abs(), Saturating(100));")] @@ -901,10 +897,11 @@ macro_rules! saturating_int_impl_signed { #[doc = concat!("assert_eq!(Saturating(", stringify!($t), "::MIN).abs(), Saturating(", stringify!($t), "::MAX));")] /// ``` #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - pub fn abs(self) -> Saturating<$t> { + pub const fn abs(self) -> Saturating<$t> { Saturating(self.0.saturating_abs()) } @@ -919,7 +916,6 @@ macro_rules! saturating_int_impl_signed { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert_eq!(Saturating(10", stringify!($t), ").signum(), Saturating(1));")] @@ -927,10 +923,11 @@ macro_rules! saturating_int_impl_signed { #[doc = concat!("assert_eq!(Saturating(-10", stringify!($t), ").signum(), Saturating(-1));")] /// ``` #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - pub fn signum(self) -> Saturating<$t> { + pub const fn signum(self) -> Saturating<$t> { Saturating(self.0.signum()) } @@ -942,7 +939,6 @@ macro_rules! saturating_int_impl_signed { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert!(Saturating(10", stringify!($t), ").is_positive());")] @@ -950,7 +946,8 @@ macro_rules! saturating_int_impl_signed { /// ``` #[must_use] #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] pub const fn is_positive(self) -> bool { self.0.is_positive() } @@ -963,7 +960,6 @@ macro_rules! saturating_int_impl_signed { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert!(Saturating(-10", stringify!($t), ").is_negative());")] @@ -971,13 +967,14 @@ macro_rules! saturating_int_impl_signed { /// ``` #[must_use] #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] pub const fn is_negative(self) -> bool { self.0.is_negative() } } - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] impl Neg for Saturating<$t> { type Output = Self; #[inline] @@ -986,7 +983,7 @@ macro_rules! saturating_int_impl_signed { } } forward_ref_unop! { impl Neg, neg for Saturating<$t>, - #[unstable(feature = "saturating_int_impl", issue = "87920")] } + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] } )*) } @@ -1002,7 +999,6 @@ macro_rules! saturating_int_impl_unsigned { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("let n = Saturating(", stringify!($t), "::MAX >> 2);")] @@ -1010,7 +1006,8 @@ macro_rules! saturating_int_impl_unsigned { /// assert_eq!(n.leading_zeros(), 2); /// ``` #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] + #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn leading_zeros(self) -> u32 { @@ -1024,7 +1021,6 @@ macro_rules! saturating_int_impl_unsigned { /// Basic usage: /// /// ``` - /// #![feature(saturating_int_impl)] /// use std::num::Saturating; /// #[doc = concat!("assert!(Saturating(16", stringify!($t), ").is_power_of_two());")] @@ -1032,8 +1028,9 @@ macro_rules! saturating_int_impl_unsigned { /// ``` #[must_use] #[inline] - #[unstable(feature = "saturating_int_impl", issue = "87920")] - pub fn is_power_of_two(self) -> bool { + #[rustc_const_stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] + pub const fn is_power_of_two(self) -> bool { self.0.is_power_of_two() } diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 08c35b6dac3..911761c6edd 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -14,6 +14,11 @@ /// For similar reasons, **this trait should never fail**. Failure during /// dereferencing can be extremely confusing when `Deref` is invoked implicitly. /// +/// Violating these requirements is a logic error. The behavior resulting from a logic error is not +/// specified, but users of the trait must ensure that such logic errors do *not* result in +/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of this +/// method. +/// /// # More on `Deref` coercion /// /// If `T` implements `Deref`, and `x` is a value of type `T`, then: @@ -114,6 +119,11 @@ impl Deref for &mut T { /// dereferencing can be extremely confusing when `DerefMut` is invoked /// implicitly. /// +/// Violating these requirements is a logic error. The behavior resulting from a logic error is not +/// specified, but users of the trait must ensure that such logic errors do *not* result in +/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of this +/// method. +/// /// # More on `Deref` coercion /// /// If `T` implements `DerefMut`, and `x` is a value of type `T`, diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 80289ca08c3..fd5fe5a04f4 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1,6 +1,3 @@ -// `library/{std,core}/src/primitive_docs.rs` should have the same contents. -// These are different files so that relative links work properly without -// having to have `CARGO_PKG_NAME` set, but conceptually they should always be the same. #[rustc_doc_primitive = "bool"] #[doc(alias = "true")] #[doc(alias = "false")] @@ -106,7 +103,7 @@ mod prim_bool {} /// behaviour of the `!` type - expressions with type `!` will coerce into any other type. /// /// [`u32`]: prim@u32 -#[doc = concat!("[`exit`]: ", include_str!("../primitive_docs/process_exit.md"))] +/// [`exit`]: ../std/process/fn.exit.html /// /// # `!` and generics /// @@ -191,7 +188,7 @@ mod prim_bool {} /// because `!` coerces to `Result` automatically. /// /// [`String::from_str`]: str::FromStr::from_str -#[doc = concat!("[`String`]: ", include_str!("../primitive_docs/string_string.md"))] +/// [`String`]: ../std/string/struct.String.html /// [`FromStr`]: str::FromStr /// /// # `!` and traits @@ -267,7 +264,7 @@ mod prim_bool {} /// `impl` for this which simply panics, but the same is true for any type (we could `impl /// Default` for (eg.) [`File`] by just making [`default()`] panic.) /// -#[doc = concat!("[`File`]: ", include_str!("../primitive_docs/fs_file.md"))] +/// [`File`]: ../std/fs/struct.File.html /// [`Debug`]: fmt::Debug /// [`default()`]: Default::default /// @@ -355,7 +352,7 @@ mod prim_never {} /// assert_eq!(5, s.len() * std::mem::size_of::()); /// ``` /// -#[doc = concat!("[`String`]: ", include_str!("../primitive_docs/string_string.md"))] +/// [`String`]: ../std/string/struct.String.html /// /// As always, remember that a human intuition for 'character' might not map to /// Unicode's definitions. For example, despite looking similar, the 'é' @@ -572,7 +569,7 @@ impl Copy for () { /// [`null_mut`]: ptr::null_mut /// [`is_null`]: pointer::is_null /// [`offset`]: pointer::offset -#[doc = concat!("[`into_raw`]: ", include_str!("../primitive_docs/box_into_raw.md"))] +/// [`into_raw`]: ../std/boxed/struct.Box.html#method.into_raw /// [`write`]: ptr::write #[stable(feature = "rust1", since = "1.0.0")] mod prim_pointer {} @@ -612,7 +609,7 @@ mod prim_pointer {} /// statically generated up to size 32. /// /// Arrays of sizes from 1 to 12 (inclusive) implement [`From`], where `Tuple` -/// is a homogenous [prim@tuple] of appropriate length. +/// is a homogeneous [prim@tuple] of appropriate length. /// /// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on /// an array. Indeed, this provides most of the API for working with arrays. @@ -676,7 +673,7 @@ mod prim_pointer {} /// move_away(roa); /// ``` /// -/// Arrays can be created from homogenous tuples of appropriate length: +/// Arrays can be created from homogeneous tuples of appropriate length: /// /// ``` /// let tuple: (u32, u32, u32) = (1, 2, 3); @@ -1065,7 +1062,7 @@ mod prim_str {} /// assert_eq!(y, 5); /// ``` /// -/// Homogenous tuples can be created from arrays of appropriate length: +/// Homogeneous tuples can be created from arrays of appropriate length: /// /// ``` /// let array: [u32; 3] = [1, 2, 3]; @@ -1361,7 +1358,7 @@ mod prim_usize {} /// /// [`std::fmt`]: fmt /// [`Hash`]: hash::Hash -#[doc = concat!("[`ToSocketAddrs`]: ", include_str!("../primitive_docs/net_tosocketaddrs.md"))] +/// [`ToSocketAddrs`]: ../std/net/trait.ToSocketAddrs.html /// /// `&mut T` references get all of the above except `ToSocketAddrs`, plus the following, if `T` /// implements that trait: @@ -1381,10 +1378,10 @@ mod prim_usize {} /// /// [`FusedIterator`]: iter::FusedIterator /// [`TrustedLen`]: iter::TrustedLen -#[doc = concat!("[`Seek`]: ", include_str!("../primitive_docs/io_seek.md"))] -#[doc = concat!("[`BufRead`]: ", include_str!("../primitive_docs/io_bufread.md"))] -#[doc = concat!("[`Read`]: ", include_str!("../primitive_docs/io_read.md"))] -#[doc = concat!("[`io::Write`]: ", include_str!("../primitive_docs/io_write.md"))] +/// [`Seek`]: ../std/io/trait.Seek.html +/// [`BufRead`]: ../std/io/trait.BufRead.html +/// [`Read`]: ../std/io/trait.Read.html +/// [`io::Write`]: ../std/io/trait.Write.html /// /// Note that due to method call deref coercion, simply calling a trait method will act like they /// work on references as well as they do on owned values! The implementations described here are diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 41e67fd8435..d1286a1dea7 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -698,6 +698,7 @@ where #[inline(always)] #[must_use] #[unstable(feature = "ptr_from_ref", issue = "106116")] +#[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] #[rustc_diagnostic_item = "ptr_from_ref"] pub const fn from_ref(r: &T) -> *const T { r @@ -710,7 +711,7 @@ pub const fn from_ref(r: &T) -> *const T { #[inline(always)] #[must_use] #[unstable(feature = "ptr_from_ref", issue = "106116")] -#[rustc_diagnostic_item = "ptr_from_mut"] +#[cfg_attr(not(bootstrap), rustc_never_returns_null_ptr)] pub const fn from_mut(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 6b3c4343ed3..d5bd54fd59a 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -338,6 +338,7 @@ impl NonNull { /// ``` #[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)] #[must_use] #[inline(always)] pub const fn as_ptr(self) -> *mut T { @@ -597,6 +598,7 @@ impl 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)] pub const fn as_mut_ptr(self) -> *mut T { self.as_non_null_ptr().as_ptr() } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index d95662afddd..0d635aced85 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -730,6 +730,7 @@ impl [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)] #[inline(always)] #[must_use] pub const fn as_ptr(&self) -> *const T { @@ -760,6 +761,7 @@ impl [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)] #[inline(always)] #[must_use] pub const fn as_mut_ptr(&mut self) -> *mut T { diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index d5b0ab92c09..eb0c424e2d2 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -386,6 +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)] #[must_use] #[inline(always)] pub const fn as_ptr(&self) -> *const u8 { @@ -401,6 +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)] #[must_use] #[inline(always)] pub fn as_mut_ptr(&mut self) -> *mut u8 { diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 22a1c09782c..cf1fbe2d389 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1018,6 +1018,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)] pub const fn as_ptr(&self) -> *mut bool { self.v.get().cast() } @@ -1953,6 +1954,7 @@ impl AtomicPtr { #[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)] pub const fn as_ptr(&self) -> *mut *mut T { self.p.get() } @@ -2891,6 +2893,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)] pub const fn as_ptr(&self) -> *mut $int_type { self.v.get() } diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index 7782ace69c1..ff292ff2dcb 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -1,4 +1,4 @@ -// See src/libstd/primitive_docs.rs for documentation. +// See core/src/primitive_docs.rs for documentation. use crate::cmp::Ordering::{self, *}; use crate::marker::ConstParamTy; diff --git a/library/std/primitive_docs/box_into_raw.md b/library/std/primitive_docs/box_into_raw.md deleted file mode 100644 index 307b9c85bd6..00000000000 --- a/library/std/primitive_docs/box_into_raw.md +++ /dev/null @@ -1 +0,0 @@ -Box::into_raw diff --git a/library/std/primitive_docs/fs_file.md b/library/std/primitive_docs/fs_file.md deleted file mode 100644 index 13e4540835e..00000000000 --- a/library/std/primitive_docs/fs_file.md +++ /dev/null @@ -1 +0,0 @@ -fs::File diff --git a/library/std/primitive_docs/io_bufread.md b/library/std/primitive_docs/io_bufread.md deleted file mode 100644 index bb688e3a5cc..00000000000 --- a/library/std/primitive_docs/io_bufread.md +++ /dev/null @@ -1 +0,0 @@ -io::BufRead diff --git a/library/std/primitive_docs/io_read.md b/library/std/primitive_docs/io_read.md deleted file mode 100644 index 5118d7c4888..00000000000 --- a/library/std/primitive_docs/io_read.md +++ /dev/null @@ -1 +0,0 @@ -io::Read diff --git a/library/std/primitive_docs/io_seek.md b/library/std/primitive_docs/io_seek.md deleted file mode 100644 index 122e6df77b6..00000000000 --- a/library/std/primitive_docs/io_seek.md +++ /dev/null @@ -1 +0,0 @@ -io::Seek diff --git a/library/std/primitive_docs/io_write.md b/library/std/primitive_docs/io_write.md deleted file mode 100644 index 15dfc907a65..00000000000 --- a/library/std/primitive_docs/io_write.md +++ /dev/null @@ -1 +0,0 @@ -io::Write diff --git a/library/std/primitive_docs/net_tosocketaddrs.md b/library/std/primitive_docs/net_tosocketaddrs.md deleted file mode 100644 index a01f318e887..00000000000 --- a/library/std/primitive_docs/net_tosocketaddrs.md +++ /dev/null @@ -1 +0,0 @@ -net::ToSocketAddrs diff --git a/library/std/primitive_docs/process_exit.md b/library/std/primitive_docs/process_exit.md deleted file mode 100644 index 565a71375cd..00000000000 --- a/library/std/primitive_docs/process_exit.md +++ /dev/null @@ -1 +0,0 @@ -process::exit diff --git a/library/std/primitive_docs/string_string.md b/library/std/primitive_docs/string_string.md deleted file mode 100644 index ce7815ff91b..00000000000 --- a/library/std/primitive_docs/string_string.md +++ /dev/null @@ -1 +0,0 @@ -string::String diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 1955ef815ff..55c112c7b80 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -152,6 +152,31 @@ //! contains further primitive shared memory types, including [`atomic`] and //! [`mpsc`], which contains the channel types for message passing. //! +//! # Use before and after `main()` +//! +//! Many parts of the standard library are expected to work before and after `main()`; +//! but this is not guaranteed or ensured by tests. It is recommended that you write your own tests +//! and run them on each platform you wish to support. +//! This means that use of `std` before/after main, especially of features that interact with the +//! OS or global state, is exempted from stability and portability guarantees and instead only +//! provided on a best-effort basis. Nevertheless bug reports are appreciated. +//! +//! On the other hand `core` and `alloc` are most likely to work in such environments with +//! the caveat that any hookable behavior such as panics, oom handling or allocators will also +//! depend on the compatibility of the hooks. +//! +//! Some features may also behave differently outside main, e.g. stdio could become unbuffered, +//! some panics might turn into aborts, backtraces might not get symbolicated or similar. +//! +//! Non-exhaustive list of known limitations: +//! +//! - after-main use of thread-locals, which also affects additional features: +//! - [`thread::current()`] +//! - [`thread::scope()`] +//! - [`sync::mpsc`] +//! - before-main stdio file descriptors are not guaranteed to be open on unix platforms +//! +//! //! [I/O]: io //! [`MIN`]: i32::MIN //! [`MAX`]: i32::MAX @@ -187,7 +212,6 @@ //! [rust-discord]: https://discord.gg/rust-lang //! [array]: prim@array //! [slice]: prim@slice - // To run std tests without x.py without ending up with two copies of std, Miri needs to be // able to "empty" this crate. See . // rustc itself never sets the feature, so this line has no effect there. @@ -351,7 +375,6 @@ #![feature(get_many_mut)] #![feature(lazy_cell)] #![feature(log_syntax)] -#![feature(saturating_int_impl)] #![feature(stdsimd)] #![feature(test)] #![feature(trace_macros)] @@ -650,7 +673,7 @@ pub use core::primitive; // Include a number of private modules that exist solely to provide // the rustdoc documentation for primitive types. Using `include!` // because rustdoc only looks for these modules at the crate level. -include!("primitive_docs.rs"); +include!("../../core/src/primitive_docs.rs"); // Include a number of private modules that exist solely to provide // the rustdoc documentation for the existing keywords. Using `include!` diff --git a/library/std/src/num.rs b/library/std/src/num.rs index 46064bd2837..9e021b23fec 100644 --- a/library/std/src/num.rs +++ b/library/std/src/num.rs @@ -12,7 +12,7 @@ mod tests; #[cfg(test)] mod benches; -#[unstable(feature = "saturating_int_impl", issue = "87920")] +#[stable(feature = "saturating_int_impl", since = "CURRENT_RUSTC_VERSION")] pub use core::num::Saturating; #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::Wrapping; diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index b6dc1a062ed..0eb4e88cfad 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -155,7 +155,7 @@ pub trait FileExt { /// flag fail to respect the offset parameter, always appending to the end /// of the file instead. /// - /// It is possible to inadvertantly set this flag, like in the example below. + /// It is possible to inadvertently set this flag, like in the example below. /// Therefore, it is important to be vigilant while changing options to mitigate /// unexpected behaviour. /// diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs deleted file mode 100644 index 80289ca08c3..00000000000 --- a/library/std/src/primitive_docs.rs +++ /dev/null @@ -1,1593 +0,0 @@ -// `library/{std,core}/src/primitive_docs.rs` should have the same contents. -// These are different files so that relative links work properly without -// having to have `CARGO_PKG_NAME` set, but conceptually they should always be the same. -#[rustc_doc_primitive = "bool"] -#[doc(alias = "true")] -#[doc(alias = "false")] -/// The boolean type. -/// -/// The `bool` represents a value, which could only be either [`true`] or [`false`]. If you cast -/// a `bool` into an integer, [`true`] will be 1 and [`false`] will be 0. -/// -/// # Basic usage -/// -/// `bool` implements various traits, such as [`BitAnd`], [`BitOr`], [`Not`], etc., -/// which allow us to perform boolean operations using `&`, `|` and `!`. -/// -/// [`if`] requires a `bool` value as its conditional. [`assert!`], which is an -/// important macro in testing, checks whether an expression is [`true`] and panics -/// if it isn't. -/// -/// ``` -/// let bool_val = true & false | false; -/// assert!(!bool_val); -/// ``` -/// -/// [`true`]: ../std/keyword.true.html -/// [`false`]: ../std/keyword.false.html -/// [`BitAnd`]: ops::BitAnd -/// [`BitOr`]: ops::BitOr -/// [`Not`]: ops::Not -/// [`if`]: ../std/keyword.if.html -/// -/// # Examples -/// -/// A trivial example of the usage of `bool`: -/// -/// ``` -/// let praise_the_borrow_checker = true; -/// -/// // using the `if` conditional -/// if praise_the_borrow_checker { -/// println!("oh, yeah!"); -/// } else { -/// println!("what?!!"); -/// } -/// -/// // ... or, a match pattern -/// match praise_the_borrow_checker { -/// true => println!("keep praising!"), -/// false => println!("you should praise!"), -/// } -/// ``` -/// -/// Also, since `bool` implements the [`Copy`] trait, we don't -/// have to worry about the move semantics (just like the integer and float primitives). -/// -/// Now an example of `bool` cast to integer type: -/// -/// ``` -/// assert_eq!(true as i32, 1); -/// assert_eq!(false as i32, 0); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_bool {} - -#[rustc_doc_primitive = "never"] -#[doc(alias = "!")] -// -/// The `!` type, also called "never". -/// -/// `!` represents the type of computations which never resolve to any value at all. For example, -/// the [`exit`] function `fn exit(code: i32) -> !` exits the process without ever returning, and -/// so returns `!`. -/// -/// `break`, `continue` and `return` expressions also have type `!`. For example we are allowed to -/// write: -/// -/// ``` -/// #![feature(never_type)] -/// # fn foo() -> u32 { -/// let x: ! = { -/// return 123 -/// }; -/// # } -/// ``` -/// -/// Although the `let` is pointless here, it illustrates the meaning of `!`. Since `x` is never -/// assigned a value (because `return` returns from the entire function), `x` can be given type -/// `!`. We could also replace `return 123` with a `panic!` or a never-ending `loop` and this code -/// would still be valid. -/// -/// A more realistic usage of `!` is in this code: -/// -/// ``` -/// # fn get_a_number() -> Option { None } -/// # loop { -/// let num: u32 = match get_a_number() { -/// Some(num) => num, -/// None => break, -/// }; -/// # } -/// ``` -/// -/// Both match arms must produce values of type [`u32`], but since `break` never produces a value -/// at all we know it can never produce a value which isn't a [`u32`]. This illustrates another -/// behaviour of the `!` type - expressions with type `!` will coerce into any other type. -/// -/// [`u32`]: prim@u32 -#[doc = concat!("[`exit`]: ", include_str!("../primitive_docs/process_exit.md"))] -/// -/// # `!` and generics -/// -/// ## Infallible errors -/// -/// The main place you'll see `!` used explicitly is in generic code. Consider the [`FromStr`] -/// trait: -/// -/// ``` -/// trait FromStr: Sized { -/// type Err; -/// fn from_str(s: &str) -> Result; -/// } -/// ``` -/// -/// When implementing this trait for [`String`] we need to pick a type for [`Err`]. And since -/// converting a string into a string will never result in an error, the appropriate type is `!`. -/// (Currently the type actually used is an enum with no variants, though this is only because `!` -/// was added to Rust at a later date and it may change in the future.) With an [`Err`] type of -/// `!`, if we have to call [`String::from_str`] for some reason the result will be a -/// [`Result`] which we can unpack like this: -/// -/// ``` -/// #![feature(exhaustive_patterns)] -/// use std::str::FromStr; -/// let Ok(s) = String::from_str("hello"); -/// ``` -/// -/// Since the [`Err`] variant contains a `!`, it can never occur. If the `exhaustive_patterns` -/// feature is present this means we can exhaustively match on [`Result`] by just taking the -/// [`Ok`] variant. This illustrates another behaviour of `!` - it can be used to "delete" certain -/// enum variants from generic types like `Result`. -/// -/// ## Infinite loops -/// -/// While [`Result`] is very useful for removing errors, `!` can also be used to remove -/// successes as well. If we think of [`Result`] as "if this function returns, it has not -/// errored," we get a very intuitive idea of [`Result`] as well: if the function returns, it -/// *has* errored. -/// -/// For example, consider the case of a simple web server, which can be simplified to: -/// -/// ```ignore (hypothetical-example) -/// loop { -/// let (client, request) = get_request().expect("disconnected"); -/// let response = request.process(); -/// response.send(client); -/// } -/// ``` -/// -/// Currently, this isn't ideal, because we simply panic whenever we fail to get a new connection. -/// Instead, we'd like to keep track of this error, like this: -/// -/// ```ignore (hypothetical-example) -/// loop { -/// match get_request() { -/// Err(err) => break err, -/// Ok((client, request)) => { -/// let response = request.process(); -/// response.send(client); -/// }, -/// } -/// } -/// ``` -/// -/// Now, when the server disconnects, we exit the loop with an error instead of panicking. While it -/// might be intuitive to simply return the error, we might want to wrap it in a [`Result`] -/// instead: -/// -/// ```ignore (hypothetical-example) -/// fn server_loop() -> Result { -/// loop { -/// let (client, request) = get_request()?; -/// let response = request.process(); -/// response.send(client); -/// } -/// } -/// ``` -/// -/// Now, we can use `?` instead of `match`, and the return type makes a lot more sense: if the loop -/// ever stops, it means that an error occurred. We don't even have to wrap the loop in an `Ok` -/// because `!` coerces to `Result` automatically. -/// -/// [`String::from_str`]: str::FromStr::from_str -#[doc = concat!("[`String`]: ", include_str!("../primitive_docs/string_string.md"))] -/// [`FromStr`]: str::FromStr -/// -/// # `!` and traits -/// -/// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl` -/// which doesn't `panic!`. The reason is that functions returning an `impl Trait` where `!` -/// does not have an `impl` of `Trait` cannot diverge as their only possible code path. In other -/// words, they can't return `!` from every code path. As an example, this code doesn't compile: -/// -/// ```compile_fail -/// use std::ops::Add; -/// -/// fn foo() -> impl Add { -/// unimplemented!() -/// } -/// ``` -/// -/// But this code does: -/// -/// ``` -/// use std::ops::Add; -/// -/// fn foo() -> impl Add { -/// if true { -/// unimplemented!() -/// } else { -/// 0 -/// } -/// } -/// ``` -/// -/// The reason is that, in the first example, there are many possible types that `!` could coerce -/// to, because many types implement `Add`. However, in the second example, -/// the `else` branch returns a `0`, which the compiler infers from the return type to be of type -/// `u32`. Since `u32` is a concrete type, `!` can and will be coerced to it. See issue [#36375] -/// for more information on this quirk of `!`. -/// -/// [#36375]: https://github.com/rust-lang/rust/issues/36375 -/// -/// As it turns out, though, most traits can have an `impl` for `!`. Take [`Debug`] -/// for example: -/// -/// ``` -/// #![feature(never_type)] -/// # use std::fmt; -/// # trait Debug { -/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result; -/// # } -/// impl Debug for ! { -/// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { -/// *self -/// } -/// } -/// ``` -/// -/// Once again we're using `!`'s ability to coerce into any other type, in this case -/// [`fmt::Result`]. Since this method takes a `&!` as an argument we know that it can never be -/// called (because there is no value of type `!` for it to be called with). Writing `*self` -/// essentially tells the compiler "We know that this code can never be run, so just treat the -/// entire function body as having type [`fmt::Result`]". This pattern can be used a lot when -/// implementing traits for `!`. Generally, any trait which only has methods which take a `self` -/// parameter should have such an impl. -/// -/// On the other hand, one trait which would not be appropriate to implement is [`Default`]: -/// -/// ``` -/// trait Default { -/// fn default() -> Self; -/// } -/// ``` -/// -/// Since `!` has no values, it has no default value either. It's true that we could write an -/// `impl` for this which simply panics, but the same is true for any type (we could `impl -/// Default` for (eg.) [`File`] by just making [`default()`] panic.) -/// -#[doc = concat!("[`File`]: ", include_str!("../primitive_docs/fs_file.md"))] -/// [`Debug`]: fmt::Debug -/// [`default()`]: Default::default -/// -#[unstable(feature = "never_type", issue = "35121")] -mod prim_never {} - -#[rustc_doc_primitive = "char"] -#[allow(rustdoc::invalid_rust_codeblocks)] -/// A character type. -/// -/// The `char` type represents a single character. More specifically, since -/// 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode -/// scalar value]'. -/// -/// This documentation describes a number of methods and trait implementations on the -/// `char` type. For technical reasons, there is additional, separate -/// documentation in [the `std::char` module](char/index.html) as well. -/// -/// # Validity -/// -/// A `char` is a '[Unicode scalar value]', which is any '[Unicode code point]' -/// other than a [surrogate code point]. This has a fixed numerical definition: -/// code points are in the range 0 to 0x10FFFF, inclusive. -/// Surrogate code points, used by UTF-16, are in the range 0xD800 to 0xDFFF. -/// -/// No `char` may be constructed, whether as a literal or at runtime, that is not a -/// Unicode scalar value: -/// -/// ```compile_fail -/// // Each of these is a compiler error -/// ['\u{D800}', '\u{DFFF}', '\u{110000}']; -/// ``` -/// -/// ```should_panic -/// // Panics; from_u32 returns None. -/// char::from_u32(0xDE01).unwrap(); -/// ``` -/// -/// ```no_run -/// // Undefined behaviour -/// let _ = unsafe { char::from_u32_unchecked(0x110000) }; -/// ``` -/// -/// USVs are also the exact set of values that may be encoded in UTF-8. Because -/// `char` values are USVs and `str` values are valid UTF-8, it is safe to store -/// any `char` in a `str` or read any character from a `str` as a `char`. -/// -/// The gap in valid `char` values is understood by the compiler, so in the -/// below example the two ranges are understood to cover the whole range of -/// possible `char` values and there is no error for a [non-exhaustive match]. -/// -/// ``` -/// let c: char = 'a'; -/// match c { -/// '\0' ..= '\u{D7FF}' => false, -/// '\u{E000}' ..= '\u{10FFFF}' => true, -/// }; -/// ``` -/// -/// All USVs are valid `char` values, but not all of them represent a real -/// character. Many USVs are not currently assigned to a character, but may be -/// in the future ("reserved"); some will never be a character -/// ("noncharacters"); and some may be given different meanings by different -/// users ("private use"). -/// -/// [Unicode code point]: https://www.unicode.org/glossary/#code_point -/// [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value -/// [non-exhaustive match]: ../book/ch06-02-match.html#matches-are-exhaustive -/// [surrogate code point]: https://www.unicode.org/glossary/#surrogate_code_point -/// -/// # Representation -/// -/// `char` is always four bytes in size. This is a different representation than -/// a given character would have as part of a [`String`]. For example: -/// -/// ``` -/// let v = vec!['h', 'e', 'l', 'l', 'o']; -/// -/// // five elements times four bytes for each element -/// assert_eq!(20, v.len() * std::mem::size_of::()); -/// -/// let s = String::from("hello"); -/// -/// // five elements times one byte per element -/// assert_eq!(5, s.len() * std::mem::size_of::()); -/// ``` -/// -#[doc = concat!("[`String`]: ", include_str!("../primitive_docs/string_string.md"))] -/// -/// As always, remember that a human intuition for 'character' might not map to -/// Unicode's definitions. For example, despite looking similar, the 'é' -/// character is one Unicode code point while 'é' is two Unicode code points: -/// -/// ``` -/// let mut chars = "é".chars(); -/// // U+00e9: 'latin small letter e with acute' -/// assert_eq!(Some('\u{00e9}'), chars.next()); -/// assert_eq!(None, chars.next()); -/// -/// let mut chars = "é".chars(); -/// // U+0065: 'latin small letter e' -/// assert_eq!(Some('\u{0065}'), chars.next()); -/// // U+0301: 'combining acute accent' -/// assert_eq!(Some('\u{0301}'), chars.next()); -/// assert_eq!(None, chars.next()); -/// ``` -/// -/// This means that the contents of the first string above _will_ fit into a -/// `char` while the contents of the second string _will not_. Trying to create -/// a `char` literal with the contents of the second string gives an error: -/// -/// ```text -/// error: character literal may only contain one codepoint: 'é' -/// let c = 'é'; -/// ^^^ -/// ``` -/// -/// Another implication of the 4-byte fixed size of a `char` is that -/// per-`char` processing can end up using a lot more memory: -/// -/// ``` -/// let s = String::from("love: ❤️"); -/// let v: Vec = s.chars().collect(); -/// -/// assert_eq!(12, std::mem::size_of_val(&s[..])); -/// assert_eq!(32, std::mem::size_of_val(&v[..])); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_char {} - -#[rustc_doc_primitive = "unit"] -#[doc(alias = "(")] -#[doc(alias = ")")] -#[doc(alias = "()")] -// -/// The `()` type, also called "unit". -/// -/// The `()` type has exactly one value `()`, and is used when there -/// is no other meaningful value that could be returned. `()` is most -/// commonly seen implicitly: functions without a `-> ...` implicitly -/// have return type `()`, that is, these are equivalent: -/// -/// ```rust -/// fn long() -> () {} -/// -/// fn short() {} -/// ``` -/// -/// The semicolon `;` can be used to discard the result of an -/// expression at the end of a block, making the expression (and thus -/// the block) evaluate to `()`. For example, -/// -/// ```rust -/// fn returns_i64() -> i64 { -/// 1i64 -/// } -/// fn returns_unit() { -/// 1i64; -/// } -/// -/// let is_i64 = { -/// returns_i64() -/// }; -/// let is_unit = { -/// returns_i64(); -/// }; -/// ``` -/// -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_unit {} - -// Required to make auto trait impls render. -// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls -#[doc(hidden)] -impl () {} - -// Fake impl that's only really used for docs. -#[cfg(doc)] -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for () { - fn clone(&self) -> Self { - loop {} - } -} - -// Fake impl that's only really used for docs. -#[cfg(doc)] -#[stable(feature = "rust1", since = "1.0.0")] -impl Copy for () { - // empty -} - -#[rustc_doc_primitive = "pointer"] -#[doc(alias = "ptr")] -#[doc(alias = "*")] -#[doc(alias = "*const")] -#[doc(alias = "*mut")] -// -/// Raw, unsafe pointers, `*const T`, and `*mut T`. -/// -/// *[See also the `std::ptr` module](ptr).* -/// -/// Working with raw pointers in Rust is uncommon, typically limited to a few patterns. -/// Raw pointers can be unaligned or [`null`]. However, when a raw pointer is -/// dereferenced (using the `*` operator), it must be non-null and aligned. -/// -/// Storing through a raw pointer using `*ptr = data` calls `drop` on the old value, so -/// [`write`] must be used if the type has drop glue and memory is not already -/// initialized - otherwise `drop` would be called on the uninitialized memory. -/// -/// Use the [`null`] and [`null_mut`] functions to create null pointers, and the -/// [`is_null`] method of the `*const T` and `*mut T` types to check for null. -/// The `*const T` and `*mut T` types also define the [`offset`] method, for -/// pointer math. -/// -/// # Common ways to create raw pointers -/// -/// ## 1. Coerce a reference (`&T`) or mutable reference (`&mut T`). -/// -/// ``` -/// let my_num: i32 = 10; -/// let my_num_ptr: *const i32 = &my_num; -/// let mut my_speed: i32 = 88; -/// let my_speed_ptr: *mut i32 = &mut my_speed; -/// ``` -/// -/// To get a pointer to a boxed value, dereference the box: -/// -/// ``` -/// let my_num: Box = Box::new(10); -/// let my_num_ptr: *const i32 = &*my_num; -/// let mut my_speed: Box = Box::new(88); -/// let my_speed_ptr: *mut i32 = &mut *my_speed; -/// ``` -/// -/// This does not take ownership of the original allocation -/// and requires no resource management later, -/// but you must not use the pointer after its lifetime. -/// -/// ## 2. Consume a box (`Box`). -/// -/// The [`into_raw`] function consumes a box and returns -/// the raw pointer. It doesn't destroy `T` or deallocate any memory. -/// -/// ``` -/// let my_speed: Box = Box::new(88); -/// let my_speed: *mut i32 = Box::into_raw(my_speed); -/// -/// // By taking ownership of the original `Box` though -/// // we are obligated to put it together later to be destroyed. -/// unsafe { -/// drop(Box::from_raw(my_speed)); -/// } -/// ``` -/// -/// Note that here the call to [`drop`] is for clarity - it indicates -/// that we are done with the given value and it should be destroyed. -/// -/// ## 3. Create it using `ptr::addr_of!` -/// -/// Instead of coercing a reference to a raw pointer, you can use the macros -/// [`ptr::addr_of!`] (for `*const T`) and [`ptr::addr_of_mut!`] (for `*mut T`). -/// These macros allow you to create raw pointers to fields to which you cannot -/// create a reference (without causing undefined behaviour), such as an -/// unaligned field. This might be necessary if packed structs or uninitialized -/// memory is involved. -/// -/// ``` -/// #[derive(Debug, Default, Copy, Clone)] -/// #[repr(C, packed)] -/// struct S { -/// aligned: u8, -/// unaligned: u32, -/// } -/// let s = S::default(); -/// let p = std::ptr::addr_of!(s.unaligned); // not allowed with coercion -/// ``` -/// -/// ## 4. Get it from C. -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[allow(unused_extern_crates)] -/// extern crate libc; -/// -/// use std::mem; -/// -/// unsafe { -/// let my_num: *mut i32 = libc::malloc(mem::size_of::()) as *mut i32; -/// if my_num.is_null() { -/// panic!("failed to allocate memory"); -/// } -/// libc::free(my_num as *mut libc::c_void); -/// } -/// ``` -/// -/// Usually you wouldn't literally use `malloc` and `free` from Rust, -/// but C APIs hand out a lot of pointers generally, so are a common source -/// of raw pointers in Rust. -/// -/// [`null`]: ptr::null -/// [`null_mut`]: ptr::null_mut -/// [`is_null`]: pointer::is_null -/// [`offset`]: pointer::offset -#[doc = concat!("[`into_raw`]: ", include_str!("../primitive_docs/box_into_raw.md"))] -/// [`write`]: ptr::write -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_pointer {} - -#[rustc_doc_primitive = "array"] -#[doc(alias = "[]")] -#[doc(alias = "[T;N]")] // unfortunately, rustdoc doesn't have fuzzy search for aliases -#[doc(alias = "[T; N]")] -/// A fixed-size array, denoted `[T; N]`, for the element type, `T`, and the -/// non-negative compile-time constant size, `N`. -/// -/// There are two syntactic forms for creating an array: -/// -/// * A list with each element, i.e., `[x, y, z]`. -/// * A repeat expression `[expr; N]` where `N` is how many times to repeat `expr` in the array. `expr` must either be: -/// -/// * A value of a type implementing the [`Copy`] trait -/// * A `const` value -/// -/// Note that `[expr; 0]` is allowed, and produces an empty array. -/// This will still evaluate `expr`, however, and immediately drop the resulting value, so -/// be mindful of side effects. -/// -/// Arrays of *any* size implement the following traits if the element type allows it: -/// -/// - [`Copy`] -/// - [`Clone`] -/// - [`Debug`] -/// - [`IntoIterator`] (implemented for `[T; N]`, `&[T; N]` and `&mut [T; N]`) -/// - [`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] -/// - [`Hash`] -/// - [`AsRef`], [`AsMut`] -/// - [`Borrow`], [`BorrowMut`] -/// -/// Arrays of sizes from 0 to 32 (inclusive) implement the [`Default`] trait -/// if the element type allows it. As a stopgap, trait implementations are -/// statically generated up to size 32. -/// -/// Arrays of sizes from 1 to 12 (inclusive) implement [`From`], where `Tuple` -/// is a homogenous [prim@tuple] of appropriate length. -/// -/// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on -/// an array. Indeed, this provides most of the API for working with arrays. -/// -/// Slices have a dynamic size and do not coerce to arrays. Instead, use -/// `slice.try_into().unwrap()` or `::try_from(slice).unwrap()`. -/// -/// Array's `try_from(slice)` implementations (and the corresponding `slice.try_into()` -/// array implementations) succeed if the input slice length is the same as the result -/// array length. They optimize especially well when the optimizer can easily determine -/// the slice length, e.g. `<[u8; 4]>::try_from(&slice[4..8]).unwrap()`. Array implements -/// [TryFrom](crate::convert::TryFrom) returning: -/// -/// - `[T; N]` copies from the slice's elements -/// - `&[T; N]` references the original slice's elements -/// - `&mut [T; N]` references the original slice's elements -/// -/// You can move elements out of an array with a [slice pattern]. If you want -/// one element, see [`mem::replace`]. -/// -/// # Examples -/// -/// ``` -/// let mut array: [i32; 3] = [0; 3]; -/// -/// array[1] = 1; -/// array[2] = 2; -/// -/// assert_eq!([1, 2], &array[1..]); -/// -/// // This loop prints: 0 1 2 -/// for x in array { -/// print!("{x} "); -/// } -/// ``` -/// -/// You can also iterate over reference to the array's elements: -/// -/// ``` -/// let array: [i32; 3] = [0; 3]; -/// -/// for x in &array { } -/// ``` -/// -/// You can use `::try_from(slice)` or `slice.try_into()` to get an array from -/// a slice: -/// -/// ``` -/// let bytes: [u8; 3] = [1, 0, 2]; -/// assert_eq!(1, u16::from_le_bytes(<[u8; 2]>::try_from(&bytes[0..2]).unwrap())); -/// assert_eq!(512, u16::from_le_bytes(bytes[1..3].try_into().unwrap())); -/// ``` -/// -/// You can use a [slice pattern] to move elements out of an array: -/// -/// ``` -/// fn move_away(_: String) { /* Do interesting things. */ } -/// -/// let [john, roa] = ["John".to_string(), "Roa".to_string()]; -/// move_away(john); -/// move_away(roa); -/// ``` -/// -/// Arrays can be created from homogenous tuples of appropriate length: -/// -/// ``` -/// let tuple: (u32, u32, u32) = (1, 2, 3); -/// let array: [u32; 3] = tuple.into(); -/// ``` -/// -/// # Editions -/// -/// Prior to Rust 1.53, arrays did not implement [`IntoIterator`] by value, so the method call -/// `array.into_iter()` auto-referenced into a [slice iterator](slice::iter). Right now, the old -/// behavior is preserved in the 2015 and 2018 editions of Rust for compatibility, ignoring -/// [`IntoIterator`] by value. In the future, the behavior on the 2015 and 2018 edition -/// might be made consistent to the behavior of later editions. -/// -/// ```rust,edition2018 -/// // Rust 2015 and 2018: -/// -/// # #![allow(array_into_iter)] // override our `deny(warnings)` -/// let array: [i32; 3] = [0; 3]; -/// -/// // This creates a slice iterator, producing references to each value. -/// for item in array.into_iter().enumerate() { -/// let (i, x): (usize, &i32) = item; -/// println!("array[{i}] = {x}"); -/// } -/// -/// // The `array_into_iter` lint suggests this change for future compatibility: -/// for item in array.iter().enumerate() { -/// let (i, x): (usize, &i32) = item; -/// println!("array[{i}] = {x}"); -/// } -/// -/// // You can explicitly iterate an array by value using `IntoIterator::into_iter` -/// for item in IntoIterator::into_iter(array).enumerate() { -/// let (i, x): (usize, i32) = item; -/// println!("array[{i}] = {x}"); -/// } -/// ``` -/// -/// Starting in the 2021 edition, `array.into_iter()` uses `IntoIterator` normally to iterate -/// by value, and `iter()` should be used to iterate by reference like previous editions. -/// -/// ```rust,edition2021 -/// // Rust 2021: -/// -/// let array: [i32; 3] = [0; 3]; -/// -/// // This iterates by reference: -/// for item in array.iter().enumerate() { -/// let (i, x): (usize, &i32) = item; -/// println!("array[{i}] = {x}"); -/// } -/// -/// // This iterates by value: -/// for item in array.into_iter().enumerate() { -/// let (i, x): (usize, i32) = item; -/// println!("array[{i}] = {x}"); -/// } -/// ``` -/// -/// Future language versions might start treating the `array.into_iter()` -/// syntax on editions 2015 and 2018 the same as on edition 2021. So code using -/// those older editions should still be written with this change in mind, to -/// prevent breakage in the future. The safest way to accomplish this is to -/// avoid the `into_iter` syntax on those editions. If an edition update is not -/// viable/desired, there are multiple alternatives: -/// * use `iter`, equivalent to the old behavior, creating references -/// * use [`IntoIterator::into_iter`], equivalent to the post-2021 behavior (Rust 1.53+) -/// * replace `for ... in array.into_iter() {` with `for ... in array {`, -/// equivalent to the post-2021 behavior (Rust 1.53+) -/// -/// ```rust,edition2018 -/// // Rust 2015 and 2018: -/// -/// let array: [i32; 3] = [0; 3]; -/// -/// // This iterates by reference: -/// for item in array.iter() { -/// let x: &i32 = item; -/// println!("{x}"); -/// } -/// -/// // This iterates by value: -/// for item in IntoIterator::into_iter(array) { -/// let x: i32 = item; -/// println!("{x}"); -/// } -/// -/// // This iterates by value: -/// for item in array { -/// let x: i32 = item; -/// println!("{x}"); -/// } -/// -/// // IntoIter can also start a chain. -/// // This iterates by value: -/// for item in IntoIterator::into_iter(array).enumerate() { -/// let (i, x): (usize, i32) = item; -/// println!("array[{i}] = {x}"); -/// } -/// ``` -/// -/// [slice]: prim@slice -/// [`Debug`]: fmt::Debug -/// [`Hash`]: hash::Hash -/// [`Borrow`]: borrow::Borrow -/// [`BorrowMut`]: borrow::BorrowMut -/// [slice pattern]: ../reference/patterns.html#slice-patterns -/// [`From`]: convert::From -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_array {} - -#[rustc_doc_primitive = "slice"] -#[doc(alias = "[")] -#[doc(alias = "]")] -#[doc(alias = "[]")] -/// A dynamically-sized view into a contiguous sequence, `[T]`. Contiguous here -/// means that elements are laid out so that every element is the same -/// distance from its neighbors. -/// -/// *[See also the `std::slice` module](crate::slice).* -/// -/// Slices are a view into a block of memory represented as a pointer and a -/// length. -/// -/// ``` -/// // slicing a Vec -/// let vec = vec![1, 2, 3]; -/// let int_slice = &vec[..]; -/// // coercing an array to a slice -/// let str_slice: &[&str] = &["one", "two", "three"]; -/// ``` -/// -/// Slices are either mutable or shared. The shared slice type is `&[T]`, -/// while the mutable slice type is `&mut [T]`, where `T` represents the element -/// type. For example, you can mutate the block of memory that a mutable slice -/// points to: -/// -/// ``` -/// let mut x = [1, 2, 3]; -/// let x = &mut x[..]; // Take a full slice of `x`. -/// x[1] = 7; -/// assert_eq!(x, &[1, 7, 3]); -/// ``` -/// -/// As slices store the length of the sequence they refer to, they have twice -/// the size of pointers to [`Sized`](marker/trait.Sized.html) types. -/// Also see the reference on -/// [dynamically sized types](../reference/dynamically-sized-types.html). -/// -/// ``` -/// # use std::rc::Rc; -/// let pointer_size = std::mem::size_of::<&u8>(); -/// assert_eq!(2 * pointer_size, std::mem::size_of::<&[u8]>()); -/// assert_eq!(2 * pointer_size, std::mem::size_of::<*const [u8]>()); -/// assert_eq!(2 * pointer_size, std::mem::size_of::>()); -/// assert_eq!(2 * pointer_size, std::mem::size_of::>()); -/// ``` -/// -/// ## Trait Implementations -/// -/// Some traits are implemented for slices if the element type implements -/// that trait. This includes [`Eq`], [`Hash`] and [`Ord`]. -/// -/// ## Iteration -/// -/// The slices implement `IntoIterator`. The iterator yields references to the -/// slice elements. -/// -/// ``` -/// let numbers: &[i32] = &[0, 1, 2]; -/// for n in numbers { -/// println!("{n} is a number!"); -/// } -/// ``` -/// -/// The mutable slice yields mutable references to the elements: -/// -/// ``` -/// let mut scores: &mut [i32] = &mut [7, 8, 9]; -/// for score in scores { -/// *score += 1; -/// } -/// ``` -/// -/// This iterator yields mutable references to the slice's elements, so while -/// the element type of the slice is `i32`, the element type of the iterator is -/// `&mut i32`. -/// -/// * [`.iter`] and [`.iter_mut`] are the explicit methods to return the default -/// iterators. -/// * Further methods that return iterators are [`.split`], [`.splitn`], -/// [`.chunks`], [`.windows`] and more. -/// -/// [`Hash`]: core::hash::Hash -/// [`.iter`]: slice::iter -/// [`.iter_mut`]: slice::iter_mut -/// [`.split`]: slice::split -/// [`.splitn`]: slice::splitn -/// [`.chunks`]: slice::chunks -/// [`.windows`]: slice::windows -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_slice {} - -#[rustc_doc_primitive = "str"] -/// String slices. -/// -/// *[See also the `std::str` module](crate::str).* -/// -/// The `str` type, also called a 'string slice', is the most primitive string -/// type. It is usually seen in its borrowed form, `&str`. It is also the type -/// of string literals, `&'static str`. -/// -/// String slices are always valid UTF-8. -/// -/// # Basic Usage -/// -/// String literals are string slices: -/// -/// ``` -/// let hello_world = "Hello, World!"; -/// ``` -/// -/// Here we have declared a string slice initialized with a string literal. -/// String literals have a static lifetime, which means the string `hello_world` -/// is guaranteed to be valid for the duration of the entire program. -/// We can explicitly specify `hello_world`'s lifetime as well: -/// -/// ``` -/// let hello_world: &'static str = "Hello, world!"; -/// ``` -/// -/// # Representation -/// -/// A `&str` is made up of two components: a pointer to some bytes, and a -/// length. You can look at these with the [`as_ptr`] and [`len`] methods: -/// -/// ``` -/// use std::slice; -/// use std::str; -/// -/// let story = "Once upon a time..."; -/// -/// let ptr = story.as_ptr(); -/// let len = story.len(); -/// -/// // story has nineteen bytes -/// assert_eq!(19, len); -/// -/// // We can re-build a str out of ptr and len. This is all unsafe because -/// // we are responsible for making sure the two components are valid: -/// let s = unsafe { -/// // First, we build a &[u8]... -/// let slice = slice::from_raw_parts(ptr, len); -/// -/// // ... and then convert that slice into a string slice -/// str::from_utf8(slice) -/// }; -/// -/// assert_eq!(s, Ok(story)); -/// ``` -/// -/// [`as_ptr`]: str::as_ptr -/// [`len`]: str::len -/// -/// Note: This example shows the internals of `&str`. `unsafe` should not be -/// used to get a string slice under normal circumstances. Use `as_str` -/// instead. -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_str {} - -#[rustc_doc_primitive = "tuple"] -#[doc(alias = "(")] -#[doc(alias = ")")] -#[doc(alias = "()")] -// -/// A finite heterogeneous sequence, `(T, U, ..)`. -/// -/// Let's cover each of those in turn: -/// -/// Tuples are *finite*. In other words, a tuple has a length. Here's a tuple -/// of length `3`: -/// -/// ``` -/// ("hello", 5, 'c'); -/// ``` -/// -/// 'Length' is also sometimes called 'arity' here; each tuple of a different -/// length is a different, distinct type. -/// -/// Tuples are *heterogeneous*. This means that each element of the tuple can -/// have a different type. In that tuple above, it has the type: -/// -/// ``` -/// # let _: -/// (&'static str, i32, char) -/// # = ("hello", 5, 'c'); -/// ``` -/// -/// Tuples are a *sequence*. This means that they can be accessed by position; -/// this is called 'tuple indexing', and it looks like this: -/// -/// ```rust -/// let tuple = ("hello", 5, 'c'); -/// -/// assert_eq!(tuple.0, "hello"); -/// assert_eq!(tuple.1, 5); -/// assert_eq!(tuple.2, 'c'); -/// ``` -/// -/// The sequential nature of the tuple applies to its implementations of various -/// traits. For example, in [`PartialOrd`] and [`Ord`], the elements are compared -/// sequentially until the first non-equal set is found. -/// -/// For more about tuples, see [the book](../book/ch03-02-data-types.html#the-tuple-type). -/// -// Hardcoded anchor in src/librustdoc/html/format.rs -// linked to as `#trait-implementations-1` -/// # Trait implementations -/// -/// In this documentation the shorthand `(T₁, T₂, …, Tₙ)` is used to represent tuples of varying -/// length. When that is used, any trait bound expressed on `T` applies to each element of the -/// tuple independently. Note that this is a convenience notation to avoid repetitive -/// documentation, not valid Rust syntax. -/// -/// Due to a temporary restriction in Rust’s type system, the following traits are only -/// implemented on tuples of arity 12 or less. In the future, this may change: -/// -/// * [`PartialEq`] -/// * [`Eq`] -/// * [`PartialOrd`] -/// * [`Ord`] -/// * [`Debug`] -/// * [`Default`] -/// * [`Hash`] -/// * [`From<[T; N]>`][from] -/// -/// [from]: convert::From -/// [`Debug`]: fmt::Debug -/// [`Hash`]: hash::Hash -/// -/// The following traits are implemented for tuples of any length. These traits have -/// implementations that are automatically generated by the compiler, so are not limited by -/// missing language features. -/// -/// * [`Clone`] -/// * [`Copy`] -/// * [`Send`] -/// * [`Sync`] -/// * [`Unpin`] -/// * [`UnwindSafe`] -/// * [`RefUnwindSafe`] -/// -/// [`UnwindSafe`]: panic::UnwindSafe -/// [`RefUnwindSafe`]: panic::RefUnwindSafe -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// let tuple = ("hello", 5, 'c'); -/// -/// assert_eq!(tuple.0, "hello"); -/// ``` -/// -/// Tuples are often used as a return type when you want to return more than -/// one value: -/// -/// ``` -/// fn calculate_point() -> (i32, i32) { -/// // Don't do a calculation, that's not the point of the example -/// (4, 5) -/// } -/// -/// let point = calculate_point(); -/// -/// assert_eq!(point.0, 4); -/// assert_eq!(point.1, 5); -/// -/// // Combining this with patterns can be nicer. -/// -/// let (x, y) = calculate_point(); -/// -/// assert_eq!(x, 4); -/// assert_eq!(y, 5); -/// ``` -/// -/// Homogenous tuples can be created from arrays of appropriate length: -/// -/// ``` -/// let array: [u32; 3] = [1, 2, 3]; -/// let tuple: (u32, u32, u32) = array.into(); -/// ``` -/// -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_tuple {} - -// Required to make auto trait impls render. -// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls -#[doc(hidden)] -impl (T,) {} - -// Fake impl that's only really used for docs. -#[cfg(doc)] -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(fake_variadic)] -/// This trait is implemented on arbitrary-length tuples. -impl Clone for (T,) { - fn clone(&self) -> Self { - loop {} - } -} - -// Fake impl that's only really used for docs. -#[cfg(doc)] -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(fake_variadic)] -/// This trait is implemented on arbitrary-length tuples. -impl Copy for (T,) { - // empty -} - -#[rustc_doc_primitive = "f32"] -/// A 32-bit floating point type (specifically, the "binary32" type defined in IEEE 754-2008). -/// -/// This type can represent a wide range of decimal numbers, like `3.5`, `27`, -/// `-113.75`, `0.0078125`, `34359738368`, `0`, `-1`. So unlike integer types -/// (such as `i32`), floating point types can represent non-integer numbers, -/// too. -/// -/// However, being able to represent this wide range of numbers comes at the -/// cost of precision: floats can only represent some of the real numbers and -/// calculation with floats round to a nearby representable number. For example, -/// `5.0` and `1.0` can be exactly represented as `f32`, but `1.0 / 5.0` results -/// in `0.20000000298023223876953125` since `0.2` cannot be exactly represented -/// as `f32`. Note, however, that printing floats with `println` and friends will -/// often discard insignificant digits: `println!("{}", 1.0f32 / 5.0f32)` will -/// print `0.2`. -/// -/// Additionally, `f32` can represent some special values: -/// -/// - −0.0: IEEE 754 floating point numbers have a bit that indicates their sign, so −0.0 is a -/// possible value. For comparison −0.0 = +0.0, but floating point operations can carry -/// the sign bit through arithmetic operations. This means −0.0 × +0.0 produces −0.0 and -/// a negative number rounded to a value smaller than a float can represent also produces −0.0. -/// - [∞](#associatedconstant.INFINITY) and -/// [−∞](#associatedconstant.NEG_INFINITY): these result from calculations -/// like `1.0 / 0.0`. -/// - [NaN (not a number)](#associatedconstant.NAN): this value results from -/// calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected -/// behavior: -/// - It is not equal to any float, including itself! This is the reason `f32` -/// doesn't implement the `Eq` trait. -/// - It is also neither smaller nor greater than any float, making it -/// impossible to sort by the default comparison operation, which is the -/// reason `f32` doesn't implement the `Ord` trait. -/// - It is also considered *infectious* as almost all calculations where one -/// of the operands is NaN will also result in NaN. The explanations on this -/// page only explicitly document behavior on NaN operands if this default -/// is deviated from. -/// - Lastly, there are multiple bit patterns that are considered NaN. -/// Rust does not currently guarantee that the bit patterns of NaN are -/// preserved over arithmetic operations, and they are not guaranteed to be -/// portable or even fully deterministic! This means that there may be some -/// surprising results upon inspecting the bit patterns, -/// as the same calculations might produce NaNs with different bit patterns. -/// -/// When the number resulting from a primitive operation (addition, -/// subtraction, multiplication, or division) on this type is not exactly -/// representable as `f32`, it is rounded according to the roundTiesToEven -/// direction defined in IEEE 754-2008. That means: -/// -/// - The result is the representable value closest to the true value, if there -/// is a unique closest representable value. -/// - If the true value is exactly half-way between two representable values, -/// the result is the one with an even least-significant binary digit. -/// - If the true value's magnitude is ≥ `f32::MAX` + 2(`f32::MAX_EXP` − -/// `f32::MANTISSA_DIGITS` − 1), the result is ∞ or −∞ (preserving the -/// true value's sign). -/// -/// For more information on floating point numbers, see [Wikipedia][wikipedia]. -/// -/// *[See also the `std::f32::consts` module](crate::f32::consts).* -/// -/// [wikipedia]: https://en.wikipedia.org/wiki/Single-precision_floating-point_format -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_f32 {} - -#[rustc_doc_primitive = "f64"] -/// A 64-bit floating point type (specifically, the "binary64" type defined in IEEE 754-2008). -/// -/// This type is very similar to [`f32`], but has increased -/// precision by using twice as many bits. Please see [the documentation for -/// `f32`][`f32`] or [Wikipedia on double precision -/// values][wikipedia] for more information. -/// -/// *[See also the `std::f64::consts` module](crate::f64::consts).* -/// -/// [`f32`]: prim@f32 -/// [wikipedia]: https://en.wikipedia.org/wiki/Double-precision_floating-point_format -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_f64 {} - -#[rustc_doc_primitive = "i8"] -// -/// The 8-bit signed integer type. -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_i8 {} - -#[rustc_doc_primitive = "i16"] -// -/// The 16-bit signed integer type. -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_i16 {} - -#[rustc_doc_primitive = "i32"] -// -/// The 32-bit signed integer type. -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_i32 {} - -#[rustc_doc_primitive = "i64"] -// -/// The 64-bit signed integer type. -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_i64 {} - -#[rustc_doc_primitive = "i128"] -// -/// The 128-bit signed integer type. -#[stable(feature = "i128", since = "1.26.0")] -mod prim_i128 {} - -#[rustc_doc_primitive = "u8"] -// -/// The 8-bit unsigned integer type. -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_u8 {} - -#[rustc_doc_primitive = "u16"] -// -/// The 16-bit unsigned integer type. -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_u16 {} - -#[rustc_doc_primitive = "u32"] -// -/// The 32-bit unsigned integer type. -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_u32 {} - -#[rustc_doc_primitive = "u64"] -// -/// The 64-bit unsigned integer type. -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_u64 {} - -#[rustc_doc_primitive = "u128"] -// -/// The 128-bit unsigned integer type. -#[stable(feature = "i128", since = "1.26.0")] -mod prim_u128 {} - -#[rustc_doc_primitive = "isize"] -// -/// The pointer-sized signed integer type. -/// -/// The size of this primitive is how many bytes it takes to reference any -/// location in memory. For example, on a 32 bit target, this is 4 bytes -/// and on a 64 bit target, this is 8 bytes. -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_isize {} - -#[rustc_doc_primitive = "usize"] -// -/// The pointer-sized unsigned integer type. -/// -/// The size of this primitive is how many bytes it takes to reference any -/// location in memory. For example, on a 32 bit target, this is 4 bytes -/// and on a 64 bit target, this is 8 bytes. -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_usize {} - -#[rustc_doc_primitive = "reference"] -#[doc(alias = "&")] -#[doc(alias = "&mut")] -// -/// References, `&T` and `&mut T`. -/// -/// A reference represents a borrow of some owned value. You can get one by using the `&` or `&mut` -/// operators on a value, or by using a [`ref`](../std/keyword.ref.html) or -/// [ref](../std/keyword.ref.html) [mut](../std/keyword.mut.html) pattern. -/// -/// For those familiar with pointers, a reference is just a pointer that is assumed to be -/// aligned, not null, and pointing to memory containing a valid value of `T` - for example, -/// &[bool] can only point to an allocation containing the integer values `1` -/// ([`true`](../std/keyword.true.html)) or `0` ([`false`](../std/keyword.false.html)), but -/// creating a &[bool] that points to an allocation containing -/// the value `3` causes undefined behaviour. -/// In fact, [Option]\<&T> has the same memory representation as a -/// nullable but aligned pointer, and can be passed across FFI boundaries as such. -/// -/// In most cases, references can be used much like the original value. Field access, method -/// calling, and indexing work the same (save for mutability rules, of course). In addition, the -/// comparison operators transparently defer to the referent's implementation, allowing references -/// to be compared the same as owned values. -/// -/// References have a lifetime attached to them, which represents the scope for which the borrow is -/// valid. A lifetime is said to "outlive" another one if its representative scope is as long or -/// longer than the other. The `'static` lifetime is the longest lifetime, which represents the -/// total life of the program. For example, string literals have a `'static` lifetime because the -/// text data is embedded into the binary of the program, rather than in an allocation that needs -/// to be dynamically managed. -/// -/// `&mut T` references can be freely coerced into `&T` references with the same referent type, and -/// references with longer lifetimes can be freely coerced into references with shorter ones. -/// -/// Reference equality by address, instead of comparing the values pointed to, is accomplished via -/// implicit reference-pointer coercion and raw pointer equality via [`ptr::eq`], while -/// [`PartialEq`] compares values. -/// -/// ``` -/// use std::ptr; -/// -/// let five = 5; -/// let other_five = 5; -/// let five_ref = &five; -/// let same_five_ref = &five; -/// let other_five_ref = &other_five; -/// -/// assert!(five_ref == same_five_ref); -/// assert!(five_ref == other_five_ref); -/// -/// assert!(ptr::eq(five_ref, same_five_ref)); -/// assert!(!ptr::eq(five_ref, other_five_ref)); -/// ``` -/// -/// For more information on how to use references, see [the book's section on "References and -/// Borrowing"][book-refs]. -/// -/// [book-refs]: ../book/ch04-02-references-and-borrowing.html -/// -/// # Trait implementations -/// -/// The following traits are implemented for all `&T`, regardless of the type of its referent: -/// -/// * [`Copy`] -/// * [`Clone`] \(Note that this will not defer to `T`'s `Clone` implementation if it exists!) -/// * [`Deref`] -/// * [`Borrow`] -/// * [`fmt::Pointer`] -/// -/// [`Deref`]: ops::Deref -/// [`Borrow`]: borrow::Borrow -/// -/// `&mut T` references get all of the above except `Copy` and `Clone` (to prevent creating -/// multiple simultaneous mutable borrows), plus the following, regardless of the type of its -/// referent: -/// -/// * [`DerefMut`] -/// * [`BorrowMut`] -/// -/// [`DerefMut`]: ops::DerefMut -/// [`BorrowMut`]: borrow::BorrowMut -/// [bool]: prim@bool -/// -/// The following traits are implemented on `&T` references if the underlying `T` also implements -/// that trait: -/// -/// * All the traits in [`std::fmt`] except [`fmt::Pointer`] (which is implemented regardless of the type of its referent) and [`fmt::Write`] -/// * [`PartialOrd`] -/// * [`Ord`] -/// * [`PartialEq`] -/// * [`Eq`] -/// * [`AsRef`] -/// * [`Fn`] \(in addition, `&T` references get [`FnMut`] and [`FnOnce`] if `T: Fn`) -/// * [`Hash`] -/// * [`ToSocketAddrs`] -/// * [`Send`] \(`&T` references also require T: [Sync]) -/// * [`Sync`] -/// -/// [`std::fmt`]: fmt -/// [`Hash`]: hash::Hash -#[doc = concat!("[`ToSocketAddrs`]: ", include_str!("../primitive_docs/net_tosocketaddrs.md"))] -/// -/// `&mut T` references get all of the above except `ToSocketAddrs`, plus the following, if `T` -/// implements that trait: -/// -/// * [`AsMut`] -/// * [`FnMut`] \(in addition, `&mut T` references get [`FnOnce`] if `T: FnMut`) -/// * [`fmt::Write`] -/// * [`Iterator`] -/// * [`DoubleEndedIterator`] -/// * [`ExactSizeIterator`] -/// * [`FusedIterator`] -/// * [`TrustedLen`] -/// * [`io::Write`] -/// * [`Read`] -/// * [`Seek`] -/// * [`BufRead`] -/// -/// [`FusedIterator`]: iter::FusedIterator -/// [`TrustedLen`]: iter::TrustedLen -#[doc = concat!("[`Seek`]: ", include_str!("../primitive_docs/io_seek.md"))] -#[doc = concat!("[`BufRead`]: ", include_str!("../primitive_docs/io_bufread.md"))] -#[doc = concat!("[`Read`]: ", include_str!("../primitive_docs/io_read.md"))] -#[doc = concat!("[`io::Write`]: ", include_str!("../primitive_docs/io_write.md"))] -/// -/// Note that due to method call deref coercion, simply calling a trait method will act like they -/// work on references as well as they do on owned values! The implementations described here are -/// meant for generic contexts, where the final type `T` is a type parameter or otherwise not -/// locally known. -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_ref {} - -#[rustc_doc_primitive = "fn"] -// -/// Function pointers, like `fn(usize) -> bool`. -/// -/// *See also the traits [`Fn`], [`FnMut`], and [`FnOnce`].* -/// -/// Function pointers are pointers that point to *code*, not data. They can be called -/// just like functions. Like references, function pointers are, among other things, assumed to -/// not be null, so if you want to pass a function pointer over FFI and be able to accommodate null -/// pointers, make your type [`Option`](core::option#options-and-pointers-nullable-pointers) -/// with your required signature. -/// -/// ### Safety -/// -/// Plain function pointers are obtained by casting either plain functions, or closures that don't -/// capture an environment: -/// -/// ``` -/// fn add_one(x: usize) -> usize { -/// x + 1 -/// } -/// -/// let ptr: fn(usize) -> usize = add_one; -/// assert_eq!(ptr(5), 6); -/// -/// let clos: fn(usize) -> usize = |x| x + 5; -/// assert_eq!(clos(5), 10); -/// ``` -/// -/// In addition to varying based on their signature, function pointers come in two flavors: safe -/// and unsafe. Plain `fn()` function pointers can only point to safe functions, -/// while `unsafe fn()` function pointers can point to safe or unsafe functions. -/// -/// ``` -/// fn add_one(x: usize) -> usize { -/// x + 1 -/// } -/// -/// unsafe fn add_one_unsafely(x: usize) -> usize { -/// x + 1 -/// } -/// -/// let safe_ptr: fn(usize) -> usize = add_one; -/// -/// //ERROR: mismatched types: expected normal fn, found unsafe fn -/// //let bad_ptr: fn(usize) -> usize = add_one_unsafely; -/// -/// let unsafe_ptr: unsafe fn(usize) -> usize = add_one_unsafely; -/// let really_safe_ptr: unsafe fn(usize) -> usize = add_one; -/// ``` -/// -/// ### ABI -/// -/// On top of that, function pointers can vary based on what ABI they use. This -/// is achieved by adding the `extern` keyword before the type, followed by the -/// ABI in question. The default ABI is "Rust", i.e., `fn()` is the exact same -/// type as `extern "Rust" fn()`. A pointer to a function with C ABI would have -/// type `extern "C" fn()`. -/// -/// `extern "ABI" { ... }` blocks declare functions with ABI "ABI". The default -/// here is "C", i.e., functions declared in an `extern {...}` block have "C" -/// ABI. -/// -/// For more information and a list of supported ABIs, see [the nomicon's -/// section on foreign calling conventions][nomicon-abi]. -/// -/// [nomicon-abi]: ../nomicon/ffi.html#foreign-calling-conventions -/// -/// ### Variadic functions -/// -/// Extern function declarations with the "C" or "cdecl" ABIs can also be *variadic*, allowing them -/// to be called with a variable number of arguments. Normal Rust functions, even those with an -/// `extern "ABI"`, cannot be variadic. For more information, see [the nomicon's section on -/// variadic functions][nomicon-variadic]. -/// -/// [nomicon-variadic]: ../nomicon/ffi.html#variadic-functions -/// -/// ### Creating function pointers -/// -/// When `bar` is the name of a function, then the expression `bar` is *not* a -/// function pointer. Rather, it denotes a value of an unnameable type that -/// uniquely identifies the function `bar`. The value is zero-sized because the -/// type already identifies the function. This has the advantage that "calling" -/// the value (it implements the `Fn*` traits) does not require dynamic -/// dispatch. -/// -/// This zero-sized type *coerces* to a regular function pointer. For example: -/// -/// ```rust -/// use std::mem; -/// -/// fn bar(x: i32) {} -/// -/// let not_bar_ptr = bar; // `not_bar_ptr` is zero-sized, uniquely identifying `bar` -/// assert_eq!(mem::size_of_val(¬_bar_ptr), 0); -/// -/// let bar_ptr: fn(i32) = not_bar_ptr; // force coercion to function pointer -/// assert_eq!(mem::size_of_val(&bar_ptr), mem::size_of::()); -/// -/// let footgun = &bar; // this is a shared reference to the zero-sized type identifying `bar` -/// ``` -/// -/// The last line shows that `&bar` is not a function pointer either. Rather, it -/// is a reference to the function-specific ZST. `&bar` is basically never what you -/// want when `bar` is a function. -/// -/// ### Casting to and from integers -/// -/// You cast function pointers directly to integers: -/// -/// ```rust -/// let fnptr: fn(i32) -> i32 = |x| x+2; -/// let fnptr_addr = fnptr as usize; -/// ``` -/// -/// However, a direct cast back is not possible. You need to use `transmute`: -/// -/// ```rust -/// # #[cfg(not(miri))] { // FIXME: use strict provenance APIs once they are stable, then remove this `cfg` -/// # let fnptr: fn(i32) -> i32 = |x| x+2; -/// # let fnptr_addr = fnptr as usize; -/// let fnptr = fnptr_addr as *const (); -/// let fnptr: fn(i32) -> i32 = unsafe { std::mem::transmute(fnptr) }; -/// assert_eq!(fnptr(40), 42); -/// # } -/// ``` -/// -/// Crucially, we `as`-cast to a raw pointer before `transmute`ing to a function pointer. -/// This avoids an integer-to-pointer `transmute`, which can be problematic. -/// Transmuting between raw pointers and function pointers (i.e., two pointer types) is fine. -/// -/// Note that all of this is not portable to platforms where function pointers and data pointers -/// have different sizes. -/// -/// ### Trait implementations -/// -/// In this documentation the shorthand `fn (T₁, T₂, …, Tₙ)` is used to represent non-variadic -/// function pointers of varying length. Note that this is a convenience notation to avoid -/// repetitive documentation, not valid Rust syntax. -/// -/// Due to a temporary restriction in Rust's type system, these traits are only implemented on -/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this -/// may change: -/// -/// * [`PartialEq`] -/// * [`Eq`] -/// * [`PartialOrd`] -/// * [`Ord`] -/// * [`Hash`] -/// * [`Pointer`] -/// * [`Debug`] -/// -/// The following traits are implemented for function pointers with any number of arguments and -/// any ABI. These traits have implementations that are automatically generated by the compiler, -/// so are not limited by missing language features: -/// -/// * [`Clone`] -/// * [`Copy`] -/// * [`Send`] -/// * [`Sync`] -/// * [`Unpin`] -/// * [`UnwindSafe`] -/// * [`RefUnwindSafe`] -/// -/// [`Hash`]: hash::Hash -/// [`Pointer`]: fmt::Pointer -/// [`UnwindSafe`]: panic::UnwindSafe -/// [`RefUnwindSafe`]: panic::RefUnwindSafe -/// -/// In addition, all *safe* function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`], because -/// these traits are specially known to the compiler. -#[stable(feature = "rust1", since = "1.0.0")] -mod prim_fn {} - -// Required to make auto trait impls render. -// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls -#[doc(hidden)] -impl fn(T) -> Ret {} - -// Fake impl that's only really used for docs. -#[cfg(doc)] -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(fake_variadic)] -/// This trait is implemented on function pointers with any number of arguments. -impl Clone for fn(T) -> Ret { - fn clone(&self) -> Self { - loop {} - } -} - -// Fake impl that's only really used for docs. -#[cfg(doc)] -#[stable(feature = "rust1", since = "1.0.0")] -#[doc(fake_variadic)] -/// This trait is implemented on function pointers with any number of arguments. -impl Copy for fn(T) -> Ret { - // empty -} diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index f92bb1a4b1f..d353c7bd5de 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -626,11 +626,6 @@ impl Clone for Sender { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl Drop for Sender { - fn drop(&mut self) {} -} - #[stable(feature = "mpsc_debug", since = "1.8.0")] impl fmt::Debug for Sender { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -755,11 +750,6 @@ impl Clone for SyncSender { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl Drop for SyncSender { - fn drop(&mut self) {} -} - #[stable(feature = "mpsc_debug", since = "1.8.0")] impl fmt::Debug for SyncSender { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -1096,11 +1086,6 @@ impl IntoIterator for Receiver { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl Drop for Receiver { - fn drop(&mut self) {} -} - #[stable(feature = "mpsc_debug", since = "1.8.0")] impl fmt::Debug for Receiver { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index e4581c2de78..7b26068c294 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -178,7 +178,7 @@ use crate::sys_common::thread; use crate::sys_common::thread_info; use crate::sys_common::thread_parking::Parker; use crate::sys_common::{AsInner, IntoInner}; -use crate::time::Duration; +use crate::time::{Duration, Instant}; #[stable(feature = "scoped_threads", since = "1.63.0")] mod scoped; @@ -872,6 +872,86 @@ pub fn sleep(dur: Duration) { imp::Thread::sleep(dur) } +/// Puts the current thread to sleep until the specified deadline has passed. +/// +/// The thread may still be asleep after the deadline specified due to +/// scheduling specifics or platform-dependent functionality. It will never +/// wake before. +/// +/// This function is blocking, and should not be used in `async` functions. +/// +/// # Platform-specific behavior +/// +/// This function uses [`sleep`] internally, see its platform-specific behaviour. +/// +/// +/// # Examples +/// +/// A simple game loop that limits the game to 60 frames per second. +/// +/// ```no_run +/// #![feature(thread_sleep_until)] +/// # use std::time::{Duration, Instant}; +/// # use std::thread; +/// # +/// # fn update() {} +/// # fn render() {} +/// # +/// let max_fps = 60.0; +/// let frame_time = Duration::from_secs_f32(1.0/max_fps); +/// let mut next_frame = Instant::now(); +/// loop { +/// thread::sleep_until(next_frame); +/// next_frame += frame_time; +/// update(); +/// render(); +/// } +/// ``` +/// +/// A slow api we must not call too fast and which takes a few +/// tries before succeeding. By using `sleep_until` the time the +/// api call takes does not influence when we retry or when we give up +/// +/// ```no_run +/// #![feature(thread_sleep_until)] +/// # use std::time::{Duration, Instant}; +/// # use std::thread; +/// # +/// # enum Status { +/// # Ready(usize), +/// # Waiting, +/// # } +/// # fn slow_web_api_call() -> Status { Status::Ready(42) } +/// # +/// # const MAX_DURATION: Duration = Duration::from_secs(10); +/// # +/// # fn try_api_call() -> Result { +/// let deadline = Instant::now() + MAX_DURATION; +/// let delay = Duration::from_millis(250); +/// let mut next_attempt = Instant::now(); +/// loop { +/// if Instant::now() > deadline { +/// break Err(()); +/// } +/// if let Status::Ready(data) = slow_web_api_call() { +/// break Ok(data); +/// } +/// +/// next_attempt = deadline.min(next_attempt + delay); +/// thread::sleep_until(next_attempt); +/// } +/// # } +/// # let _data = try_api_call(); +/// ``` +#[unstable(feature = "thread_sleep_until", issue = "113752")] +pub fn sleep_until(deadline: Instant) { + let now = Instant::now(); + + if let Some(delay) = deadline.checked_duration_since(now) { + sleep(delay); + } +} + /// Used to ensure that `park` and `park_timeout` do not unwind, as that can /// cause undefined behaviour if not handled correctly (see #102398 for context). struct PanicGuard; diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 253d504d7bd..548281ca506 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -1,8 +1,7 @@ # rustbuild - Bootstrapping Rust -This is an in-progress README which is targeted at helping to explain how Rust -is bootstrapped and in general, some of the technical details of the build -system. +This README is aimed at helping to explain how Rust is bootstrapped and in general, +some of the technical details of the build system. Note that this README only covers internal information, not how to use the tool. Please check [bootstrapping dev guide][bootstrapping-dev-guide] for further information. diff --git a/src/bootstrap/bin/_helper.rs b/src/bootstrap/bin/_helper.rs new file mode 100644 index 00000000000..09aa471dba4 --- /dev/null +++ b/src/bootstrap/bin/_helper.rs @@ -0,0 +1,24 @@ +/// 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 { + use std::str::FromStr; + + match std::env::var("RUSTC_VERBOSE") { + Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"), + Err(_) => 0, + } +} + +/// 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 { + 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); + }) +} diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 10718aeb89f..20cd63b966b 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -16,27 +16,25 @@ //! 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::str::FromStr; use std::time::Instant; fn main() { let args = env::args_os().skip(1).collect::>(); 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(); + // Detect whether or not we're a build script depending on whether --target // is passed (a bit janky...) let target = arg("--target"); let version = args.iter().find(|w| &**w == "-vV"); - let verbose = match env::var("RUSTC_VERBOSE") { - Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"), - Err(_) => 0, - }; - // Use a different compiler for build scripts, since there may not yet be a // libstd for the real compiler to use. However, if Cargo is attempting to // determine the version of the compiler, the real compiler needs to be @@ -47,12 +45,7 @@ fn main() { } else { ("RUSTC_REAL", "RUSTC_LIBDIR") }; - let stage = 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); - }); + let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set"); let on_fail = env::var_os("RUSTC_ON_FAIL").map(Command::new); diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index 4ecb3349816..6561c1c1933 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -9,14 +9,14 @@ use std::process::{exit, Command}; include!("../dylib_util.rs"); +include!("./_helper.rs"); + fn main() { let args = env::args_os().skip(1).collect::>(); - let stage = 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); - }); + + let stage = parse_rustc_stage(); + let verbose = 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"); let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set"); @@ -25,13 +25,6 @@ fn main() { // is passed (a bit janky...) let target = args.windows(2).find(|w| &*w[0] == "--target").and_then(|w| w[1].to_str()); - use std::str::FromStr; - - let verbose = match env::var("RUSTC_VERBOSE") { - Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"), - Err(_) => 0, - }; - let mut dylib_path = dylib_path(); dylib_path.insert(0, PathBuf::from(libdir.clone())); diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index e4c76226454..a9aa7524e8b 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -312,6 +312,14 @@ def default_build_triple(verbose): # non-standard string (e.g. gnuwin32 tools returns `windows32`). In # these cases, fall back to using sys.platform. return 'x86_64-pc-windows-msvc' + elif kernel == 'AIX': + # `uname -m` returns the machine ID rather than machine hardware on AIX, + # so we are unable to use cputype to form triple. AIX 7.2 and + # above supports 32-bit and 64-bit mode simultaneously and `uname -p` + # returns `powerpc`, however we only supports `powerpc64-ibm-aix` in + # rust on AIX. For above reasons, kerneltype_mapper and cputype_mapper + # are not used to infer AIX's triple. + return 'powerpc64-ibm-aix' else: err = "unknown OS type: {}".format(kernel) sys.exit(err) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 91fa5ec6633..50f1007e1ff 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -525,7 +525,7 @@ impl<'a> ShouldRun<'a> { .iter() .map(|p| { // assert only if `p` isn't submodule - if !submodules_paths.iter().find(|sm_p| p.contains(*sm_p)).is_some() { + if submodules_paths.iter().find(|sm_p| p.contains(*sm_p)).is_none() { assert!( self.builder.src.join(p).exists(), "`should_run.paths` should correspond to real on-disk paths - use `alias` if there is no relevant path: {}", diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 9c68e5a78d8..4f19ffa83db 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -570,6 +570,9 @@ fn copy_sanitizers( let dst = libdir.join(&runtime.name); builder.copy(&runtime.path, &dst); + // The `aarch64-apple-ios-macabi` and `x86_64-apple-ios-macabi` are also supported for + // sanitizers, but they share a sanitizer runtime with `${arch}-apple-darwin`, so we do + // not list them here to rename and sign the runtime library. if target == "x86_64-apple-darwin" || target == "aarch64-apple-darwin" || target == "aarch64-apple-ios" @@ -876,10 +879,8 @@ impl Step for Rustc { cargo.rustflag("-Clto=off"); } } - } else { - if builder.config.rust_lto == RustcLto::Off { - cargo.rustflag("-Clto=off"); - } + } else if builder.config.rust_lto == RustcLto::Off { + cargo.rustflag("-Clto=off"); } for krate in &*self.crates { diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index e5fdac3ceda..176ef8e92db 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -322,33 +322,23 @@ pub struct RustfmtMetadata { pub version: String, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub enum RustfmtState { SystemToolchain(PathBuf), Downloaded(PathBuf), Unavailable, + #[default] LazyEvaluated, } -impl Default for RustfmtState { - fn default() -> Self { - RustfmtState::LazyEvaluated - } -} - -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Default, Clone, Copy, PartialEq)] pub enum LlvmLibunwind { + #[default] No, InTree, System, } -impl Default for LlvmLibunwind { - fn default() -> Self { - Self::No - } -} - impl FromStr for LlvmLibunwind { type Err = String; @@ -362,19 +352,14 @@ impl FromStr for LlvmLibunwind { } } -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum SplitDebuginfo { Packed, Unpacked, + #[default] Off, } -impl Default for SplitDebuginfo { - fn default() -> Self { - SplitDebuginfo::Off - } -} - impl std::str::FromStr for SplitDebuginfo { type Err = (); @@ -1529,7 +1514,7 @@ impl Config { let asserts = llvm_assertions.unwrap_or(false); config.llvm_from_ci = match llvm.download_ci_llvm { Some(StringOrBool::String(s)) => { - assert!(s == "if-available", "unknown option `{s}` for download-ci-llvm"); + assert_eq!(s, "if-available", "unknown option `{s}` for download-ci-llvm"); crate::llvm::is_ci_llvm_available(&config, asserts) } Some(StringOrBool::Bool(b)) => b, diff --git a/src/bootstrap/config/tests.rs b/src/bootstrap/config/tests.rs index b8f3be96062..aac76cdcbcf 100644 --- a/src/bootstrap/config/tests.rs +++ b/src/bootstrap/config/tests.rs @@ -136,7 +136,7 @@ build-config = {} "setting string value without quotes" ); assert_eq!(config.gdb, Some("bar".into()), "setting string value with quotes"); - assert_eq!(config.deny_warnings, false, "setting boolean value"); + assert!(!config.deny_warnings, "setting boolean value"); assert_eq!( config.tools, Some(["cargo".to_string()].into_iter().collect()), @@ -181,13 +181,13 @@ fn profile_user_dist() { #[test] fn rust_optimize() { - assert_eq!(parse("").rust_optimize.is_release(), true); - assert_eq!(parse("rust.optimize = false").rust_optimize.is_release(), false); - assert_eq!(parse("rust.optimize = true").rust_optimize.is_release(), true); - assert_eq!(parse("rust.optimize = 0").rust_optimize.is_release(), false); - assert_eq!(parse("rust.optimize = 1").rust_optimize.is_release(), true); + assert!(parse("").rust_optimize.is_release()); + assert!(!parse("rust.optimize = false").rust_optimize.is_release()); + assert!(parse("rust.optimize = true").rust_optimize.is_release()); + assert!(!parse("rust.optimize = 0").rust_optimize.is_release()); + assert!(parse("rust.optimize = 1").rust_optimize.is_release()); + assert!(parse("rust.optimize = \"s\"").rust_optimize.is_release()); assert_eq!(parse("rust.optimize = 1").rust_optimize.get_opt_level(), Some("1".to_string())); - assert_eq!(parse("rust.optimize = \"s\"").rust_optimize.is_release(), true); assert_eq!(parse("rust.optimize = \"s\"").rust_optimize.get_opt_level(), Some("s".to_string())); } diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs index 9489297d67d..8e9614ec89a 100644 --- a/src/bootstrap/download.rs +++ b/src/bootstrap/download.rs @@ -441,7 +441,7 @@ impl Config { } pub(crate) fn download_beta_toolchain(&self) { - self.verbose(&format!("downloading stage0 beta artifacts")); + self.verbose("downloading stage0 beta artifacts"); let date = &self.stage0_metadata.compiler.date; let version = &self.stage0_metadata.compiler.version; diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 671d25484d0..1e001fae8ab 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -116,7 +116,7 @@ pub const VERSION: usize = 2; /// Extra --check-cfg to add when building /// (Mode restriction, config name, config values (if any)) -const EXTRA_CHECK_CFGS: &[(Option, &'static str, Option<&[&'static str]>)] = &[ +const EXTRA_CHECK_CFGS: &[(Option, &str, Option<&[&'static str]>)] = &[ (None, "bootstrap", None), (Some(Mode::Rustc), "parallel_compiler", None), (Some(Mode::ToolRustc), "parallel_compiler", None), @@ -1757,10 +1757,11 @@ to download LLVM rather than building it. // // In these cases we automatically enable Ninja if we find it in the // environment. - if !self.config.ninja_in_file && self.config.build.contains("msvc") { - if cmd_finder.maybe_have("ninja").is_some() { - return true; - } + if !self.config.ninja_in_file + && self.config.build.contains("msvc") + && cmd_finder.maybe_have("ninja").is_some() + { + return true; } self.config.ninja_in_file diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs index aefed501513..7e5ade50ca7 100644 --- a/src/bootstrap/llvm.rs +++ b/src/bootstrap/llvm.rs @@ -155,7 +155,7 @@ pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String { "".to_owned() }; - if &llvm_sha == "" { + if llvm_sha.is_empty() { eprintln!("error: could not find commit hash for downloading LLVM"); eprintln!("help: maybe your repository history is too shallow?"); eprintln!("help: consider disabling `download-ci-llvm`"); @@ -208,10 +208,10 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool { ("x86_64-unknown-netbsd", false), ]; - if !supported_platforms.contains(&(&*config.build.triple, asserts)) { - if asserts == true || !supported_platforms.contains(&(&*config.build.triple, true)) { - return false; - } + if !supported_platforms.contains(&(&*config.build.triple, asserts)) + && (asserts || !supported_platforms.contains(&(&*config.build.triple, true))) + { + return false; } if is_ci_llvm_modified(config) { @@ -497,11 +497,11 @@ impl Step for Llvm { let mut cmd = Command::new(&res.llvm_config); let version = output(cmd.arg("--version")); let major = version.split('.').next().unwrap(); - let lib_name = match &llvm_version_suffix { + + match &llvm_version_suffix { Some(version_suffix) => format!("libLLVM-{major}{version_suffix}.{extension}"), None => format!("libLLVM-{major}.{extension}"), - }; - lib_name + } }; // When building LLVM with LLVM_LINK_LLVM_DYLIB for macOS, an unversioned @@ -756,13 +756,15 @@ fn configure_cmake( // For distribution we want the LLVM tools to be *statically* linked to libstdc++. // We also do this if the user explicitly requested static libstdc++. - if builder.config.llvm_static_stdcpp { - if !target.contains("msvc") && !target.contains("netbsd") && !target.contains("solaris") { - if target.contains("apple") || target.contains("windows") { - ldflags.push_all("-static-libstdc++"); - } else { - ldflags.push_all("-Wl,-Bsymbolic -static-libstdc++"); - } + if builder.config.llvm_static_stdcpp + && !target.contains("msvc") + && !target.contains("netbsd") + && !target.contains("solaris") + { + if target.contains("apple") || target.contains("windows") { + ldflags.push_all("-static-libstdc++"); + } else { + ldflags.push_all("-Wl,-Bsymbolic -static-libstdc++"); } } @@ -1061,6 +1063,7 @@ fn supported_sanitizers( "aarch64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]), "aarch64-apple-ios" => darwin_libs("ios", &["asan", "tsan"]), "aarch64-apple-ios-sim" => darwin_libs("iossim", &["asan", "tsan"]), + "aarch64-apple-ios-macabi" => darwin_libs("osx", &["asan", "lsan", "tsan"]), "aarch64-unknown-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]), "aarch64-unknown-linux-gnu" => { common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"]) @@ -1071,6 +1074,7 @@ fn supported_sanitizers( "x86_64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]), "x86_64-unknown-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]), "x86_64-apple-ios" => darwin_libs("iossim", &["asan", "tsan"]), + "x86_64-apple-ios-macabi" => darwin_libs("osx", &["asan", "lsan", "tsan"]), "x86_64-unknown-freebsd" => common_libs("freebsd", "x86_64", &["asan", "msan", "tsan"]), "x86_64-unknown-netbsd" => { common_libs("netbsd", "x86_64", &["asan", "lsan", "msan", "tsan"]) diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 144e2acd09e..0febdf250d3 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -95,20 +95,19 @@ pub fn check(build: &mut Build) { .unwrap_or(true) }) .any(|build_llvm_ourselves| build_llvm_ourselves); + let need_cmake = building_llvm || build.config.any_sanitizers_enabled(); - if need_cmake { - if cmd_finder.maybe_have("cmake").is_none() { - eprintln!( - " + if need_cmake && cmd_finder.maybe_have("cmake").is_none() { + eprintln!( + " Couldn't find required command: cmake You should install cmake, or set `download-ci-llvm = true` in the `[llvm]` section of `config.toml` to download LLVM rather than building it. " - ); - crate::exit!(1); - } + ); + crate::exit!(1); } build.config.python = build @@ -202,10 +201,10 @@ than building it. .entry(*target) .or_insert_with(|| Target::from_triple(&target.triple)); - if target.contains("-none-") || target.contains("nvptx") { - if build.no_std(*target) == Some(false) { - panic!("All the *-none-* and nvptx* targets are no-std targets") - } + if (target.contains("-none-") || target.contains("nvptx")) + && build.no_std(*target) == Some(false) + { + panic!("All the *-none-* and nvptx* targets are no-std targets") } // Some environments don't want or need these tools, such as when testing Miri. diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index 30730f50491..ef0234957b5 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -33,6 +33,7 @@ static SETTINGS_HASHES: &[&str] = &[ "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0", "3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541", "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923", + "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a", ]; static RUST_ANALYZER_SETTINGS: &str = include_str!("../etc/rust_analyzer_settings.json"); diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 35e2e98e08e..ba030f0f525 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -846,7 +846,7 @@ impl Step for RustdocTheme { let rustdoc = builder.bootstrap_out.join("rustdoc"); let mut cmd = builder.tool_cmd(Tool::RustdocTheme); cmd.arg(rustdoc.to_str().unwrap()) - .arg(builder.src.join("src/librustdoc/html/static/css/themes").to_str().unwrap()) + .arg(builder.src.join("src/librustdoc/html/static/css/rustdoc.css").to_str().unwrap()) .env("RUSTC_STAGE", self.compiler.stage.to_string()) .env("RUSTC_SYSROOT", builder.sysroot(self.compiler)) .env("RUSTDOC_LIBDIR", builder.sysroot_libdir(self.compiler, self.compiler.host)) @@ -1139,16 +1139,14 @@ help: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to .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() - { - eprintln!( - "x.py completions were changed; run `x.py run generate-completions` to update them" - ); - crate::exit!(1); - } + } 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() + { + eprintln!( + "x.py completions were changed; run `x.py run generate-completions` to update them" + ); + crate::exit!(1); } } @@ -1378,7 +1376,7 @@ impl Step for MirOpt { let run = |target| { builder.ensure(Compiletest { compiler: self.compiler, - target: target, + target, mode: "mir-opt", suite: "mir-opt", path: "tests/mir-opt", diff --git a/src/ci/docker/host-x86_64/arm-android/Dockerfile b/src/ci/docker/host-x86_64/arm-android/Dockerfile index b6b4fdc67a9..db11700af28 100644 --- a/src/ci/docker/host-x86_64/arm-android/Dockerfile +++ b/src/ci/docker/host-x86_64/arm-android/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.10 +FROM ubuntu:23.04 ARG DEBIAN_FRONTEND=noninteractive COPY scripts/android-base-apt-get.sh /scripts/ diff --git a/src/ci/docker/host-x86_64/dist-android/Dockerfile b/src/ci/docker/host-x86_64/dist-android/Dockerfile index 9c6f648896b..b09b6edb01a 100644 --- a/src/ci/docker/host-x86_64/dist-android/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-android/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:22.10 +FROM ubuntu:23.04 COPY scripts/android-base-apt-get.sh /scripts/ RUN sh /scripts/android-base-apt-get.sh diff --git a/src/ci/docker/host-x86_64/dist-various-1/install-x86_64-redox.sh b/src/ci/docker/host-x86_64/dist-various-1/install-x86_64-redox.sh index dad97922338..f86402b0180 100755 --- a/src/ci/docker/host-x86_64/dist-various-1/install-x86_64-redox.sh +++ b/src/ci/docker/host-x86_64/dist-various-1/install-x86_64-redox.sh @@ -2,5 +2,5 @@ set -ex -curl https://static.redox-os.org/toolchain/x86_64-unknown-redox/relibc-install.tar.gz | \ +curl https://ci-mirrors.rust-lang.org/rustc/2022-11-27-relibc-install.tar.gz | \ tar --extract --gzip --directory /usr/local diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index f6954275ad4..6f1b2a6a638 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -87,7 +87,7 @@ ENV RUST_CONFIGURE_ARGS \ --set rust.lto=thin ENV SCRIPT python3 ../x.py build --set rust.debug=true opt-dist && \ - ./build/$HOSTS/stage0-tools-bin/opt-dist python3 ../x.py dist \ + ./build/$HOSTS/stage0-tools-bin/opt-dist linux-ci -- python3 ../x.py dist \ --host $HOSTS --target $HOSTS \ --include-default-paths \ build-manifest bootstrap diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index b31629ad605..0d67319168d 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.16.8 \ No newline at end of file +0.16.9 \ No newline at end of file diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 89b82d59d31..973b9a0a089 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -114,7 +114,7 @@ x--expand-yaml-anchors--remove: run: git config --global core.autocrlf false - name: checkout the source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 2 @@ -624,7 +624,7 @@ jobs: --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler - SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist python x.py dist bootstrap --include-default-paths + SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist windows-ci -- python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 <<: *job-windows-8c @@ -707,7 +707,7 @@ jobs: if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'rust-lang-ci/rust' steps: - name: checkout the source code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 2 diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index f69156b7c05..0d3f6338af4 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -625,3 +625,47 @@ and check the values of `feature`: `foo` and `bar`. This flag enables the generation of links in the source code pages which allow the reader to jump to a type definition. + +### Custom CSS classes for code blocks + +```rust +#![feature(custom_code_classes_in_docs)] + +/// ```custom,{class=language-c} +/// int main(void) { return 0; } +/// ``` +pub struct Bar; +``` + +The text `int main(void) { return 0; }` is rendered without highlighting in a code block +with the class `language-c`. This can be used to highlight other languages through JavaScript +libraries for example. + +Without the `custom` attribute, it would be generated as a Rust code example with an additional +`language-C` CSS class. Therefore, if you specifically don't want it to be a Rust code example, +don't forget to add the `custom` attribute. + +To be noted that you can replace `class=` with `.` to achieve the same result: + +```rust +#![feature(custom_code_classes_in_docs)] + +/// ```custom,{.language-c} +/// int main(void) { return 0; } +/// ``` +pub struct Bar; +``` + +To be noted, `rust` and `.rust`/`class=rust` have different effects: `rust` indicates that this is +a Rust code block whereas the two others add a "rust" CSS class on the code block. + +You can also use double quotes: + +```rust +#![feature(custom_code_classes_in_docs)] + +/// ```"not rust" {."hello everyone"} +/// int main(void) { return 0; } +/// ``` +pub struct Bar; +``` diff --git a/src/etc/rust_analyzer_settings.json b/src/etc/rust_analyzer_settings.json index 6e5e2c35005..32a04cfd5d1 100644 --- a/src/etc/rust_analyzer_settings.json +++ b/src/etc/rust_analyzer_settings.json @@ -16,10 +16,10 @@ "compiler/rustc_codegen_gcc/Cargo.toml" ], "rust-analyzer.rustfmt.overrideCommand": [ - "./build/host/rustfmt/bin/rustfmt", + "${workspaceFolder}/build/host/rustfmt/bin/rustfmt", "--edition=2021" ], - "rust-analyzer.procMacro.server": "./build/host/stage0/libexec/rust-analyzer-proc-macro-srv", + "rust-analyzer.procMacro.server": "${workspaceFolder}/build/host/stage0/libexec/rust-analyzer-proc-macro-srv", "rust-analyzer.procMacro.enable": true, "rust-analyzer.cargo.buildScripts.enable": true, "rust-analyzer.cargo.buildScripts.invocationLocation": "root", diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 974dc1c5135..99aa979027f 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -410,9 +410,15 @@ impl Options { let to_check = matches.opt_strs("check-theme"); if !to_check.is_empty() { - let paths = match theme::load_css_paths( - std::str::from_utf8(static_files::STATIC_FILES.theme_light_css.bytes).unwrap(), - ) { + let mut content = + std::str::from_utf8(static_files::STATIC_FILES.rustdoc_css.bytes).unwrap(); + if let Some((_, inside)) = content.split_once("/* Begin theme: light */") { + content = inside; + } + if let Some((inside, _)) = content.split_once("/* End theme: light */") { + content = inside; + } + let paths = match theme::load_css_paths(content) { Ok(p) => p, Err(e) => { diag.struct_err(e).emit(); @@ -550,9 +556,15 @@ impl Options { let mut themes = Vec::new(); if matches.opt_present("theme") { - let paths = match theme::load_css_paths( - std::str::from_utf8(static_files::STATIC_FILES.theme_light_css.bytes).unwrap(), - ) { + let mut content = + std::str::from_utf8(static_files::STATIC_FILES.rustdoc_css.bytes).unwrap(); + if let Some((_, inside)) = content.split_once("/* Begin theme: light */") { + content = inside; + } + if let Some((inside, _)) = content.split_once("/* End theme: light */") { + content = inside; + } + let paths = match theme::load_css_paths(content) { Ok(p) => p, Err(e) => { diag.struct_err(e).emit(); diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index ea87268877f..24597c3aca3 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1243,6 +1243,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> { def_id.to_def_id(), span_of_fragments(&attrs.doc_strings).unwrap_or(sp), )), + self.tcx.features().custom_code_classes_in_docs, ); } diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index f0ebb8e5a39..b34b69b1f15 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -46,6 +46,8 @@ impl ExternalHtml { edition, playground, heading_offset: HeadingOffset::H2, + // For external files, it'll be disabled until the feature is enabled by default. + custom_code_classes_in_docs: false, } .into_string() ); @@ -61,6 +63,8 @@ impl ExternalHtml { edition, playground, heading_offset: HeadingOffset::H2, + // For external files, it'll be disabled until the feature is enabled by default. + custom_code_classes_in_docs: false, } .into_string() ); diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 039e8cdb987..d8e36139a78 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -52,8 +52,9 @@ pub(crate) fn render_example_with_highlighting( out: &mut Buffer, tooltip: Tooltip, playground_button: Option<&str>, + extra_classes: &[String], ) { - write_header(out, "rust-example-rendered", None, tooltip); + write_header(out, "rust-example-rendered", None, tooltip, extra_classes); write_code(out, src, None, None); write_footer(out, playground_button); } @@ -65,7 +66,13 @@ pub(crate) fn render_item_decl_with_highlighting(src: &str, out: &mut Buffer) { write!(out, ""); } -fn write_header(out: &mut Buffer, class: &str, extra_content: Option, tooltip: Tooltip) { +fn write_header( + out: &mut Buffer, + class: &str, + extra_content: Option, + tooltip: Tooltip, + extra_classes: &[String], +) { write!( out, "
", @@ -100,9 +107,19 @@ fn write_header(out: &mut Buffer, class: &str, extra_content: Option, to out.push_buffer(extra); } if class.is_empty() { - write!(out, "
");
+        write!(
+            out,
+            "
",
+            if extra_classes.is_empty() { "" } else { " " },
+            extra_classes.join(" "),
+        );
     } else {
-        write!(out, "
");
+        write!(
+            out,
+            "
",
+            if extra_classes.is_empty() { "" } else { " " },
+            extra_classes.join(" "),
+        );
     }
     write!(out, "");
 }
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index b28019e3f91..59958fbaef9 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -20,12 +20,14 @@
 //!     edition: Edition::Edition2015,
 //!     playground: &None,
 //!     heading_offset: HeadingOffset::H2,
+//!     custom_code_classes_in_docs: true,
 //! };
 //! let html = md.into_string();
 //! // ... something using html
 //! ```
 
 use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::TyCtxt;
 pub(crate) use rustc_resolve::rustdoc::main_body_opts;
@@ -37,8 +39,9 @@ use once_cell::sync::Lazy;
 use std::borrow::Cow;
 use std::collections::VecDeque;
 use std::fmt::Write;
+use std::iter::Peekable;
 use std::ops::{ControlFlow, Range};
-use std::str;
+use std::str::{self, CharIndices};
 
 use crate::clean::RenderedLink;
 use crate::doctest;
@@ -93,6 +96,8 @@ pub struct Markdown<'a> {
     /// Offset at which we render headings.
     /// E.g. if `heading_offset: HeadingOffset::H2`, then `# something` renders an `

`. pub heading_offset: HeadingOffset, + /// `true` if the `custom_code_classes_in_docs` feature is enabled. + pub custom_code_classes_in_docs: bool, } /// A struct like `Markdown` that renders the markdown with a table of contents. pub(crate) struct MarkdownWithToc<'a> { @@ -101,6 +106,8 @@ pub(crate) struct MarkdownWithToc<'a> { pub(crate) error_codes: ErrorCodes, pub(crate) edition: Edition, pub(crate) playground: &'a Option, + /// `true` if the `custom_code_classes_in_docs` feature is enabled. + pub(crate) custom_code_classes_in_docs: bool, } /// A tuple struct like `Markdown` that renders the markdown escaping HTML tags /// and includes no paragraph tags. @@ -201,6 +208,7 @@ struct CodeBlocks<'p, 'a, I: Iterator>> { // Information about the playground if a URL has been specified, containing an // optional crate name and the URL. playground: &'p Option, + custom_code_classes_in_docs: bool, } impl<'p, 'a, I: Iterator>> CodeBlocks<'p, 'a, I> { @@ -209,8 +217,15 @@ impl<'p, 'a, I: Iterator>> CodeBlocks<'p, 'a, I> { error_codes: ErrorCodes, edition: Edition, playground: &'p Option, + custom_code_classes_in_docs: bool, ) -> Self { - CodeBlocks { inner: iter, check_error_codes: error_codes, edition, playground } + CodeBlocks { + inner: iter, + check_error_codes: error_codes, + edition, + playground, + custom_code_classes_in_docs, + } } } @@ -240,14 +255,28 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { let parse_result = match kind { CodeBlockKind::Fenced(ref lang) => { - let parse_result = - LangString::parse_without_check(lang, self.check_error_codes, false); + let parse_result = LangString::parse_without_check( + lang, + self.check_error_codes, + false, + self.custom_code_classes_in_docs, + ); if !parse_result.rust { + let added_classes = parse_result.added_classes; + let lang_string = if let Some(lang) = parse_result.unknown.first() { + format!("language-{}", lang) + } else { + String::new() + }; + let whitespace = if added_classes.is_empty() { "" } else { " " }; return Some(Event::Html( format!( "
\ -
{text}
\ +
\
+                                     {text}\
+                                 
\
", + added_classes = added_classes.join(" "), text = Escape(&original_text), ) .into(), @@ -258,6 +287,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { CodeBlockKind::Indented => Default::default(), }; + let added_classes = parse_result.added_classes; let lines = original_text.lines().filter_map(|l| map_line(l).for_html()); let text = lines.intersperse("\n".into()).collect::(); @@ -315,6 +345,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { &mut s, tooltip, playground_button.as_deref(), + &added_classes, ); Some(Event::Html(s.into_inner().into())) } @@ -711,6 +742,27 @@ pub(crate) fn find_testable_code( error_codes: ErrorCodes, enable_per_target_ignores: bool, extra_info: Option<&ExtraInfo<'_>>, + custom_code_classes_in_docs: bool, +) { + find_codes( + doc, + tests, + error_codes, + enable_per_target_ignores, + extra_info, + false, + custom_code_classes_in_docs, + ) +} + +pub(crate) fn find_codes( + doc: &str, + tests: &mut T, + error_codes: ErrorCodes, + enable_per_target_ignores: bool, + extra_info: Option<&ExtraInfo<'_>>, + include_non_rust: bool, + custom_code_classes_in_docs: bool, ) { let mut parser = Parser::new(doc).into_offset_iter(); let mut prev_offset = 0; @@ -729,12 +781,13 @@ pub(crate) fn find_testable_code( error_codes, enable_per_target_ignores, extra_info, + custom_code_classes_in_docs, ) } } CodeBlockKind::Indented => Default::default(), }; - if !block_info.rust { + if !include_non_rust && !block_info.rust { continue; } @@ -784,7 +837,23 @@ impl<'tcx> ExtraInfo<'tcx> { ExtraInfo { def_id, sp, tcx } } - fn error_invalid_codeblock_attr(&self, msg: String, help: &'static str) { + fn error_invalid_codeblock_attr(&self, msg: impl Into) { + if let Some(def_id) = self.def_id.as_local() { + self.tcx.struct_span_lint_hir( + crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, + self.tcx.hir().local_def_id_to_hir_id(def_id), + self.sp, + msg, + |l| l, + ); + } + } + + fn error_invalid_codeblock_attr_with_help( + &self, + msg: impl Into, + help: impl Into, + ) { if let Some(def_id) = self.def_id.as_local() { self.tcx.struct_span_lint_hir( crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, @@ -808,6 +877,8 @@ pub(crate) struct LangString { pub(crate) compile_fail: bool, pub(crate) error_codes: Vec, pub(crate) edition: Option, + pub(crate) added_classes: Vec, + pub(crate) unknown: Vec, } #[derive(Eq, PartialEq, Clone, Debug)] @@ -817,6 +888,276 @@ pub(crate) enum Ignore { Some(Vec), } +/// This is the parser for fenced codeblocks attributes. It implements the following eBNF: +/// +/// ```eBNF +/// lang-string = *(token-list / delimited-attribute-list / comment) +/// +/// bareword = CHAR *(CHAR) +/// quoted-string = QUOTE *(NONQUOTE) QUOTE +/// token = bareword / quoted-string +/// sep = COMMA/WS *(COMMA/WS) +/// attribute = (DOT token)/(token EQUAL token) +/// attribute-list = [sep] attribute *(sep attribute) [sep] +/// delimited-attribute-list = OPEN-CURLY-BRACKET attribute-list CLOSE-CURLY-BRACKET +/// token-list = [sep] token *(sep token) [sep] +/// comment = OPEN_PAREN *(all characters) CLOSE_PAREN +/// +/// OPEN_PAREN = "(" +/// CLOSE_PARENT = ")" +/// OPEN-CURLY-BRACKET = "{" +/// CLOSE-CURLY-BRACKET = "}" +/// CHAR = ALPHA / DIGIT / "_" / "-" / ":" +/// QUOTE = %x22 +/// NONQUOTE = %x09 / %x20 / %x21 / %x23-7E ; TAB / SPACE / all printable characters except `"` +/// COMMA = "," +/// DOT = "." +/// EQUAL = "=" +/// +/// ALPHA = %x41-5A / %x61-7A ; A-Z / a-z +/// DIGIT = %x30-39 +/// WS = %x09 / " " +/// ``` +pub(crate) struct TagIterator<'a, 'tcx> { + inner: Peekable>, + data: &'a str, + is_in_attribute_block: bool, + extra: Option<&'a ExtraInfo<'tcx>>, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub(crate) enum LangStringToken<'a> { + LangToken(&'a str), + ClassAttribute(&'a str), + KeyValueAttribute(&'a str, &'a str), +} + +fn is_bareword_char(c: char) -> bool { + c == '_' || c == '-' || c == ':' || c.is_ascii_alphabetic() || c.is_ascii_digit() +} +fn is_separator(c: char) -> bool { + c == ' ' || c == ',' || c == '\t' +} + +struct Indices { + start: usize, + end: usize, +} + +impl<'a, 'tcx> TagIterator<'a, 'tcx> { + pub(crate) fn new(data: &'a str, extra: Option<&'a ExtraInfo<'tcx>>) -> Self { + Self { inner: data.char_indices().peekable(), data, is_in_attribute_block: false, extra } + } + + fn emit_error(&self, err: impl Into) { + if let Some(extra) = self.extra { + extra.error_invalid_codeblock_attr(err); + } + } + + fn skip_separators(&mut self) -> Option { + while let Some((pos, c)) = self.inner.peek() { + if !is_separator(*c) { + return Some(*pos); + } + self.inner.next(); + } + None + } + + fn parse_string(&mut self, start: usize) -> Option { + while let Some((pos, c)) = self.inner.next() { + if c == '"' { + return Some(Indices { start: start + 1, end: pos }); + } + } + self.emit_error("unclosed quote string `\"`"); + None + } + + fn parse_class(&mut self, start: usize) -> Option> { + while let Some((pos, c)) = self.inner.peek().copied() { + if is_bareword_char(c) { + self.inner.next(); + } else { + let class = &self.data[start + 1..pos]; + if class.is_empty() { + self.emit_error(format!("unexpected `{c}` character after `.`")); + return None; + } else if self.check_after_token() { + return Some(LangStringToken::ClassAttribute(class)); + } else { + return None; + } + } + } + let class = &self.data[start + 1..]; + if class.is_empty() { + self.emit_error("missing character after `.`"); + None + } else if self.check_after_token() { + Some(LangStringToken::ClassAttribute(class)) + } else { + None + } + } + + fn parse_token(&mut self, start: usize) -> Option { + while let Some((pos, c)) = self.inner.peek() { + if !is_bareword_char(*c) { + return Some(Indices { start, end: *pos }); + } + self.inner.next(); + } + self.emit_error("unexpected end"); + None + } + + fn parse_key_value(&mut self, c: char, start: usize) -> Option> { + let key_indices = + if c == '"' { self.parse_string(start)? } else { self.parse_token(start)? }; + if key_indices.start == key_indices.end { + self.emit_error("unexpected empty string as key"); + return None; + } + + if let Some((_, c)) = self.inner.next() { + if c != '=' { + self.emit_error(format!("expected `=`, found `{}`", c)); + return None; + } + } else { + self.emit_error("unexpected end"); + return None; + } + let value_indices = match self.inner.next() { + Some((pos, '"')) => self.parse_string(pos)?, + Some((pos, c)) if is_bareword_char(c) => self.parse_token(pos)?, + Some((_, c)) => { + self.emit_error(format!("unexpected `{c}` character after `=`")); + return None; + } + None => { + self.emit_error("expected value after `=`"); + return None; + } + }; + if value_indices.start == value_indices.end { + self.emit_error("unexpected empty string as value"); + None + } else if self.check_after_token() { + Some(LangStringToken::KeyValueAttribute( + &self.data[key_indices.start..key_indices.end], + &self.data[value_indices.start..value_indices.end], + )) + } else { + None + } + } + + /// Returns `false` if an error was emitted. + fn check_after_token(&mut self) -> bool { + if let Some((_, c)) = self.inner.peek().copied() { + if c == '}' || is_separator(c) || c == '(' { + true + } else { + self.emit_error(format!("unexpected `{c}` character")); + false + } + } else { + // The error will be caught on the next iteration. + true + } + } + + fn parse_in_attribute_block(&mut self) -> Option> { + while let Some((pos, c)) = self.inner.next() { + if c == '}' { + self.is_in_attribute_block = false; + return self.next(); + } else if c == '.' { + return self.parse_class(pos); + } else if c == '"' || is_bareword_char(c) { + return self.parse_key_value(c, pos); + } else { + self.emit_error(format!("unexpected character `{c}`")); + return None; + } + } + self.emit_error("unclosed attribute block (`{}`): missing `}` at the end"); + None + } + + /// Returns `false` if an error was emitted. + fn skip_paren_block(&mut self) -> bool { + while let Some((_, c)) = self.inner.next() { + if c == ')' { + return true; + } + } + self.emit_error("unclosed comment: missing `)` at the end"); + false + } + + fn parse_outside_attribute_block(&mut self, start: usize) -> Option> { + while let Some((pos, c)) = self.inner.next() { + if c == '"' { + if pos != start { + self.emit_error("expected ` `, `{` or `,` found `\"`"); + return None; + } + let indices = self.parse_string(pos)?; + if let Some((_, c)) = self.inner.peek().copied() && c != '{' && !is_separator(c) && c != '(' { + self.emit_error(format!("expected ` `, `{{` or `,` after `\"`, found `{c}`")); + return None; + } + return Some(LangStringToken::LangToken(&self.data[indices.start..indices.end])); + } else if c == '{' { + self.is_in_attribute_block = true; + return self.next(); + } else if is_bareword_char(c) { + continue; + } else if is_separator(c) { + if pos != start { + return Some(LangStringToken::LangToken(&self.data[start..pos])); + } + return self.next(); + } else if c == '(' { + if !self.skip_paren_block() { + return None; + } + if pos != start { + return Some(LangStringToken::LangToken(&self.data[start..pos])); + } + return self.next(); + } else { + self.emit_error(format!("unexpected character `{c}`")); + return None; + } + } + let token = &self.data[start..]; + if token.is_empty() { None } else { Some(LangStringToken::LangToken(&self.data[start..])) } + } +} + +impl<'a, 'tcx> Iterator for TagIterator<'a, 'tcx> { + type Item = LangStringToken<'a>; + + fn next(&mut self) -> Option { + let Some(start) = self.skip_separators() else { + if self.is_in_attribute_block { + self.emit_error("unclosed attribute block (`{}`): missing `}` at the end"); + } + return None; + }; + if self.is_in_attribute_block { + self.parse_in_attribute_block() + } else { + self.parse_outside_attribute_block(start) + } + } +} + impl Default for LangString { fn default() -> Self { Self { @@ -829,6 +1170,8 @@ impl Default for LangString { compile_fail: false, error_codes: Vec::new(), edition: None, + added_classes: Vec::new(), + unknown: Vec::new(), } } } @@ -838,33 +1181,15 @@ impl LangString { string: &str, allow_error_code_check: ErrorCodes, enable_per_target_ignores: bool, - ) -> LangString { - Self::parse(string, allow_error_code_check, enable_per_target_ignores, None) - } - - fn tokens(string: &str) -> impl Iterator { - // Pandoc, which Rust once used for generating documentation, - // expects lang strings to be surrounded by `{}` and for each token - // to be proceeded by a `.`. Since some of these lang strings are still - // loose in the wild, we strip a pair of surrounding `{}` from the lang - // string and a leading `.` from each token. - - let string = string.trim(); - - let first = string.chars().next(); - let last = string.chars().last(); - - let string = if first == Some('{') && last == Some('}') { - &string[1..string.len() - 1] - } else { - string - }; - - string - .split(|c| c == ',' || c == ' ' || c == '\t') - .map(str::trim) - .map(|token| token.strip_prefix('.').unwrap_or(token)) - .filter(|token| !token.is_empty()) + custom_code_classes_in_docs: bool, + ) -> Self { + Self::parse( + string, + allow_error_code_check, + enable_per_target_ignores, + None, + custom_code_classes_in_docs, + ) } fn parse( @@ -872,52 +1197,63 @@ impl LangString { allow_error_code_check: ErrorCodes, enable_per_target_ignores: bool, extra: Option<&ExtraInfo<'_>>, - ) -> LangString { + custom_code_classes_in_docs: bool, + ) -> Self { let allow_error_code_check = allow_error_code_check.as_bool(); let mut seen_rust_tags = false; let mut seen_other_tags = false; + let mut seen_custom_tag = false; let mut data = LangString::default(); let mut ignores = vec![]; data.original = string.to_owned(); - for token in Self::tokens(string) { + for token in TagIterator::new(string, extra) { match token { - "should_panic" => { + LangStringToken::LangToken("should_panic") => { data.should_panic = true; seen_rust_tags = !seen_other_tags; } - "no_run" => { + LangStringToken::LangToken("no_run") => { data.no_run = true; seen_rust_tags = !seen_other_tags; } - "ignore" => { + LangStringToken::LangToken("ignore") => { data.ignore = Ignore::All; seen_rust_tags = !seen_other_tags; } - x if x.starts_with("ignore-") => { + LangStringToken::LangToken(x) if x.starts_with("ignore-") => { if enable_per_target_ignores { ignores.push(x.trim_start_matches("ignore-").to_owned()); seen_rust_tags = !seen_other_tags; } } - "rust" => { + LangStringToken::LangToken("rust") => { data.rust = true; seen_rust_tags = true; } - "test_harness" => { + LangStringToken::LangToken("custom") => { + if custom_code_classes_in_docs { + seen_custom_tag = true; + } else { + seen_other_tags = true; + } + } + LangStringToken::LangToken("test_harness") => { data.test_harness = true; seen_rust_tags = !seen_other_tags || seen_rust_tags; } - "compile_fail" => { + LangStringToken::LangToken("compile_fail") => { data.compile_fail = true; seen_rust_tags = !seen_other_tags || seen_rust_tags; data.no_run = true; } - x if x.starts_with("edition") => { + LangStringToken::LangToken(x) if x.starts_with("edition") => { data.edition = x[7..].parse::().ok(); } - x if allow_error_code_check && x.starts_with('E') && x.len() == 5 => { + LangStringToken::LangToken(x) + if allow_error_code_check && x.starts_with('E') && x.len() == 5 => + { if x[1..].parse::().is_ok() { data.error_codes.push(x.to_owned()); seen_rust_tags = !seen_other_tags || seen_rust_tags; @@ -925,7 +1261,7 @@ impl LangString { seen_other_tags = true; } } - x if extra.is_some() => { + LangStringToken::LangToken(x) if extra.is_some() => { let s = x.to_lowercase(); if let Some((flag, help)) = if s == "compile-fail" || s == "compile_fail" @@ -958,15 +1294,35 @@ impl LangString { None } { if let Some(extra) = extra { - extra.error_invalid_codeblock_attr( + extra.error_invalid_codeblock_attr_with_help( format!("unknown attribute `{x}`. Did you mean `{flag}`?"), help, ); } } seen_other_tags = true; + data.unknown.push(x.to_owned()); + } + LangStringToken::LangToken(x) => { + seen_other_tags = true; + data.unknown.push(x.to_owned()); + } + LangStringToken::KeyValueAttribute(key, value) => { + if custom_code_classes_in_docs { + if key == "class" { + data.added_classes.push(value.to_owned()); + } else if let Some(extra) = extra { + extra.error_invalid_codeblock_attr(format!( + "unsupported attribute `{key}`" + )); + } + } else { + seen_other_tags = true; + } + } + LangStringToken::ClassAttribute(class) => { + data.added_classes.push(class.to_owned()); } - _ => seen_other_tags = true, } } @@ -975,7 +1331,7 @@ impl LangString { data.ignore = Ignore::Some(ignores); } - data.rust &= !seen_other_tags || seen_rust_tags; + data.rust &= !seen_custom_tag && (!seen_other_tags || seen_rust_tags); data } @@ -991,6 +1347,7 @@ impl Markdown<'_> { edition, playground, heading_offset, + custom_code_classes_in_docs, } = self; // This is actually common enough to special-case @@ -1013,7 +1370,7 @@ impl Markdown<'_> { let p = Footnotes::new(p); let p = LinkReplacer::new(p.map(|(ev, _)| ev), links); let p = TableWrapper::new(p); - let p = CodeBlocks::new(p, codes, edition, playground); + let p = CodeBlocks::new(p, codes, edition, playground, custom_code_classes_in_docs); html::push_html(&mut s, p); s @@ -1022,7 +1379,14 @@ impl Markdown<'_> { impl MarkdownWithToc<'_> { pub(crate) fn into_string(self) -> String { - let MarkdownWithToc { content: md, ids, error_codes: codes, edition, playground } = self; + let MarkdownWithToc { + content: md, + ids, + error_codes: codes, + edition, + playground, + custom_code_classes_in_docs, + } = self; let p = Parser::new_ext(md, main_body_opts()).into_offset_iter(); @@ -1034,7 +1398,7 @@ impl MarkdownWithToc<'_> { let p = HeadingLinks::new(p, Some(&mut toc), ids, HeadingOffset::H1); let p = Footnotes::new(p); let p = TableWrapper::new(p.map(|(ev, _)| ev)); - let p = CodeBlocks::new(p, codes, edition, playground); + let p = CodeBlocks::new(p, codes, edition, playground, custom_code_classes_in_docs); html::push_html(&mut s, p); } @@ -1475,7 +1839,11 @@ pub(crate) struct RustCodeBlock { /// Returns a range of bytes for each code block in the markdown that is tagged as `rust` or /// untagged (and assumed to be rust). -pub(crate) fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec { +pub(crate) fn rust_code_blocks( + md: &str, + extra_info: &ExtraInfo<'_>, + custom_code_classes_in_docs: bool, +) -> Vec { let mut code_blocks = vec![]; if md.is_empty() { @@ -1492,7 +1860,13 @@ pub(crate) fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec>(); + fn case(lang_string: &str, want: &[LangStringToken<'_>]) { + let have = TagIterator::new(lang_string, None).collect::>(); assert_eq!(have, want, "Unexpected lang string split for `{}`", lang_string); } case("", &[]); - case("foo", &["foo"]); - case("foo,bar", &["foo", "bar"]); - case(".foo,.bar", &["foo", "bar"]); - case("{.foo,.bar}", &["foo", "bar"]); - case(" {.foo,.bar} ", &["foo", "bar"]); - case("foo bar", &["foo", "bar"]); - case("foo\tbar", &["foo", "bar"]); - case("foo\t, bar", &["foo", "bar"]); - case(" foo , bar ", &["foo", "bar"]); - case(",,foo,,bar,,", &["foo", "bar"]); - case("foo=bar", &["foo=bar"]); - case("a-b-c", &["a-b-c"]); - case("a_b_c", &["a_b_c"]); + case("foo", &[LangStringToken::LangToken("foo")]); + case("foo,bar", &[LangStringToken::LangToken("foo"), LangStringToken::LangToken("bar")]); + case(".foo,.bar", &[]); + case( + "{.foo,.bar}", + &[LangStringToken::ClassAttribute("foo"), LangStringToken::ClassAttribute("bar")], + ); + case( + " {.foo,.bar} ", + &[LangStringToken::ClassAttribute("foo"), LangStringToken::ClassAttribute("bar")], + ); + case("foo bar", &[LangStringToken::LangToken("foo"), LangStringToken::LangToken("bar")]); + case("foo\tbar", &[LangStringToken::LangToken("foo"), LangStringToken::LangToken("bar")]); + case("foo\t, bar", &[LangStringToken::LangToken("foo"), LangStringToken::LangToken("bar")]); + case(" foo , bar ", &[LangStringToken::LangToken("foo"), LangStringToken::LangToken("bar")]); + case(",,foo,,bar,,", &[LangStringToken::LangToken("foo"), LangStringToken::LangToken("bar")]); + case("foo=bar", &[]); + case("a-b-c", &[LangStringToken::LangToken("a-b-c")]); + case("a_b_c", &[LangStringToken::LangToken("a_b_c")]); } #[test] @@ -154,6 +290,7 @@ fn test_header() { edition: DEFAULT_EDITION, playground: &None, heading_offset: HeadingOffset::H2, + custom_code_classes_in_docs: true, } .into_string(); assert_eq!(output, expect, "original: {}", input); @@ -193,6 +330,7 @@ fn test_header_ids_multiple_blocks() { edition: DEFAULT_EDITION, playground: &None, heading_offset: HeadingOffset::H2, + custom_code_classes_in_docs: true, } .into_string(); assert_eq!(output, expect, "original: {}", input); @@ -297,7 +435,7 @@ fn test_find_testable_code_line() { } } let mut lines = Vec::::new(); - find_testable_code(input, &mut lines, ErrorCodes::No, false, None); + find_testable_code(input, &mut lines, ErrorCodes::No, false, None, true); assert_eq!(lines, expect); } @@ -322,6 +460,7 @@ fn test_ascii_with_prepending_hashtag() { edition: DEFAULT_EDITION, playground: &None, heading_offset: HeadingOffset::H2, + custom_code_classes_in_docs: true, } .into_string(); assert_eq!(output, expect, "original: {}", input); diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 736b6d7ebfa..97714afaa45 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -107,8 +107,8 @@ pub(crate) struct SharedContext<'tcx> { pub(super) module_sorting: ModuleSorting, /// Additional CSS files to be added to the generated docs. pub(crate) style_files: Vec, - /// Suffix to be added on resource files (if suffix is "-v2" then "light.css" becomes - /// "light-v2.css"). + /// Suffix to add on resource files (if suffix is "-v2" then "search-index.js" becomes + /// "search-index-v2.js"). pub(crate) resource_suffix: String, /// Optional path string to be used to load static files on output pages. If not set, uses /// combinations of `../` to reach the documentation root. @@ -714,18 +714,9 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { You need to enable JavaScript be able to update your settings.\ \ \ - \ - \ - \ - ", + ", static_root_path = page.get_static_root_path(), settings_js = static_files::STATIC_FILES.settings_js, - theme_light_css = static_files::STATIC_FILES.theme_light_css, - theme_dark_css = static_files::STATIC_FILES.theme_dark_css, - theme_ayu_css = static_files::STATIC_FILES.theme_ayu_css, ); // Pre-load all theme CSS files, so that switching feels seamless. // diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 5adbecd6d04..f70f59d3be3 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -403,7 +403,8 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String { error_codes: shared.codes, edition: shared.edition(), playground: &shared.playground, - heading_offset: HeadingOffset::H1 + heading_offset: HeadingOffset::H1, + custom_code_classes_in_docs: false, } .into_string() ) @@ -437,6 +438,7 @@ fn render_markdown<'a, 'cx: 'a>( heading_offset: HeadingOffset, ) -> impl fmt::Display + 'a + Captures<'cx> { display_fn(move |f| { + let custom_code_classes_in_docs = cx.tcx().features().custom_code_classes_in_docs; write!( f, "
{}
", @@ -448,6 +450,7 @@ fn render_markdown<'a, 'cx: 'a>( edition: cx.shared.edition(), playground: &cx.shared.playground, heading_offset, + custom_code_classes_in_docs, } .into_string() ) @@ -1778,6 +1781,7 @@ fn render_impl(

", ); } + let custom_code_classes_in_docs = cx.tcx().features().custom_code_classes_in_docs; write!( w, "
{}
", @@ -1788,7 +1792,8 @@ fn render_impl( error_codes: cx.shared.codes, edition: cx.shared.edition(), playground: &cx.shared.playground, - heading_offset: HeadingOffset::H4 + heading_offset: HeadingOffset::H4, + custom_code_classes_in_docs, } .into_string() ); diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css index 93aa11a5852..fe0cf6dc8cc 100644 --- a/src/librustdoc/html/static/css/noscript.css +++ b/src/librustdoc/html/static/css/noscript.css @@ -28,3 +28,216 @@ nav.sub { https://github.com/rust-lang/rust/issues/102576 */ display: none; } + +/* Begin: styles for themes + Keep the default light and dark themes synchronized with the ones + in rustdoc.css */ + +/* Begin theme: light */ +:root { + --main-background-color: white; + --main-color: black; + --settings-input-color: #2196f3; + --settings-input-border-color: #717171; + --settings-button-color: #000; + --settings-button-border-focus: #717171; + --sidebar-background-color: #f5f5f5; + --sidebar-background-color-hover: #e0e0e0; + --code-block-background-color: #f5f5f5; + --scrollbar-track-background-color: #dcdcdc; + --scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6); + --scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9; + --headings-border-bottom-color: #ddd; + --border-color: #e0e0e0; + --button-background-color: #fff; + --right-side-color: grey; + --code-attribute-color: #999; + --toggles-color: #999; + --toggle-filter: none; + --search-input-focused-border-color: #66afe9; + --copy-path-button-color: #999; + --copy-path-img-filter: invert(50%); + --copy-path-img-hover-filter: invert(35%); + --codeblock-error-hover-color: rgb(255, 0, 0); + --codeblock-error-color: rgba(255, 0, 0, .5); + --codeblock-ignore-hover-color: rgb(255, 142, 0); + --codeblock-ignore-color: rgba(255, 142, 0, .6); + --warning-border-color: #ff8e00; + --type-link-color: #ad378a; + --trait-link-color: #6e4fc9; + --assoc-item-link-color: #3873ad; + --function-link-color: #ad7c37; + --macro-link-color: #068000; + --keyword-link-color: #3873ad; + --mod-link-color: #3873ad; + --link-color: #3873ad; + --sidebar-link-color: #356da4; + --sidebar-current-link-background-color: #fff; + --search-result-link-focus-background-color: #ccc; + --search-result-border-color: #aaa3; + --search-color: #000; + --search-error-code-background-color: #d0cccc; + --search-results-alias-color: #000; + --search-results-grey-color: #999; + --search-tab-title-count-color: #888; + --search-tab-button-not-selected-border-top-color: #e6e6e6; + --search-tab-button-not-selected-background: #e6e6e6; + --search-tab-button-selected-border-top-color: #0089ff; + --search-tab-button-selected-background: #fff; + --stab-background-color: #fff5d6; + --stab-code-color: #000; + --code-highlight-kw-color: #8959a8; + --code-highlight-kw-2-color: #4271ae; + --code-highlight-lifetime-color: #b76514; + --code-highlight-prelude-color: #4271ae; + --code-highlight-prelude-val-color: #c82829; + --code-highlight-number-color: #718c00; + --code-highlight-string-color: #718c00; + --code-highlight-literal-color: #c82829; + --code-highlight-attribute-color: #c82829; + --code-highlight-self-color: #c82829; + --code-highlight-macro-color: #3e999f; + --code-highlight-question-mark-color: #ff9011; + --code-highlight-comment-color: #8e908c; + --code-highlight-doc-comment-color: #4d4d4c; + --src-line-numbers-span-color: #c67e2d; + --src-line-number-highlighted-background-color: #fdffd3; + --test-arrow-color: #f5f5f5; + --test-arrow-background-color: rgba(78, 139, 202, 0.2); + --test-arrow-hover-color: #f5f5f5; + --test-arrow-hover-background-color: rgb(78, 139, 202); + --target-background-color: #fdffd3; + --target-border-color: #ad7c37; + --kbd-color: #000; + --kbd-background: #fafbfc; + --kbd-box-shadow-color: #c6cbd1; + --rust-logo-filter: initial; + /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */ + --crate-search-div-filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) + brightness(114%) contrast(76%); + --crate-search-div-hover-filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) + brightness(96%) contrast(93%); + --crate-search-hover-border: #717171; + --src-sidebar-background-selected: #fff; + --src-sidebar-background-hover: #e0e0e0; + --table-alt-row-background-color: #f5f5f5; + --codeblock-link-background: #eee; + --scrape-example-toggle-line-background: #ccc; + --scrape-example-toggle-line-hover-background: #999; + --scrape-example-code-line-highlight: #fcffd6; + --scrape-example-code-line-highlight-focus: #f6fdb0; + --scrape-example-help-border-color: #555; + --scrape-example-help-color: #333; + --scrape-example-help-hover-border-color: #000; + --scrape-example-help-hover-color: #000; + --scrape-example-code-wrapper-background-start: rgba(255, 255, 255, 1); + --scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0); +} +/* End theme: light */ + +@media (prefers-color-scheme: dark) { + /* Begin theme: dark */ + :root { + --main-background-color: #353535; + --main-color: #ddd; + --settings-input-color: #2196f3; + --settings-input-border-color: #999; + --settings-button-color: #000; + --settings-button-border-focus: #ffb900; + --sidebar-background-color: #505050; + --sidebar-background-color-hover: #676767; + --code-block-background-color: #2A2A2A; + --scrollbar-track-background-color: #717171; + --scrollbar-thumb-background-color: rgba(32, 34, 37, .6); + --scrollbar-color: rgba(32,34,37,.6) #5a5a5a; + --headings-border-bottom-color: #d2d2d2; + --border-color: #e0e0e0; + --button-background-color: #f0f0f0; + --right-side-color: grey; + --code-attribute-color: #999; + --toggles-color: #999; + --toggle-filter: invert(100%); + --search-input-focused-border-color: #008dfd; + --copy-path-button-color: #999; + --copy-path-img-filter: invert(50%); + --copy-path-img-hover-filter: invert(65%); + --codeblock-error-hover-color: rgb(255, 0, 0); + --codeblock-error-color: rgba(255, 0, 0, .5); + --codeblock-ignore-hover-color: rgb(255, 142, 0); + --codeblock-ignore-color: rgba(255, 142, 0, .6); + --warning-border-color: #ff8e00; + --type-link-color: #2dbfb8; + --trait-link-color: #b78cf2; + --assoc-item-link-color: #d2991d; + --function-link-color: #2bab63; + --macro-link-color: #09bd00; + --keyword-link-color: #d2991d; + --mod-link-color: #d2991d; + --link-color: #d2991d; + --sidebar-link-color: #fdbf35; + --sidebar-current-link-background-color: #444; + --search-result-link-focus-background-color: #616161; + --search-result-border-color: #aaa3; + --search-color: #111; + --search-error-code-background-color: #484848; + --search-results-alias-color: #fff; + --search-results-grey-color: #ccc; + --search-tab-title-count-color: #888; + --search-tab-button-not-selected-border-top-color: #252525; + --search-tab-button-not-selected-background: #252525; + --search-tab-button-selected-border-top-color: #0089ff; + --search-tab-button-selected-background: #353535; + --stab-background-color: #314559; + --stab-code-color: #e6e1cf; + --code-highlight-kw-color: #ab8ac1; + --code-highlight-kw-2-color: #769acb; + --code-highlight-lifetime-color: #d97f26; + --code-highlight-prelude-color: #769acb; + --code-highlight-prelude-val-color: #ee6868; + --code-highlight-number-color: #83a300; + --code-highlight-string-color: #83a300; + --code-highlight-literal-color: #ee6868; + --code-highlight-attribute-color: #ee6868; + --code-highlight-self-color: #ee6868; + --code-highlight-macro-color: #3e999f; + --code-highlight-question-mark-color: #ff9011; + --code-highlight-comment-color: #8d8d8b; + --code-highlight-doc-comment-color: #8ca375; + --src-line-numbers-span-color: #3b91e2; + --src-line-number-highlighted-background-color: #0a042f; + --test-arrow-color: #dedede; + --test-arrow-background-color: rgba(78, 139, 202, 0.2); + --test-arrow-hover-color: #dedede; + --test-arrow-hover-background-color: #4e8bca; + --target-background-color: #494a3d; + --target-border-color: #bb7410; + --kbd-color: #000; + --kbd-background: #fafbfc; + --kbd-box-shadow-color: #c6cbd1; + --rust-logo-filter: drop-shadow(1px 0 0px #fff) + drop-shadow(0 1px 0 #fff) + drop-shadow(-1px 0 0 #fff) + drop-shadow(0 -1px 0 #fff); + /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */ + --crate-search-div-filter: invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) + brightness(90%) contrast(90%); + --crate-search-div-hover-filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) + brightness(100%) contrast(91%); + --crate-search-hover-border: #2196f3; + --src-sidebar-background-selected: #333; + --src-sidebar-background-hover: #444; + --table-alt-row-background-color: #2a2a2a; + --codeblock-link-background: #333; + --scrape-example-toggle-line-background: #999; + --scrape-example-toggle-line-hover-background: #c5c5c5; + --scrape-example-code-line-highlight: #5b3b01; + --scrape-example-code-line-highlight-focus: #7c4b0f; + --scrape-example-help-border-color: #aaa; + --scrape-example-help-color: #eee; + --scrape-example-help-hover-border-color: #fff; + --scrape-example-help-hover-color: #fff; + --scrape-example-code-wrapper-background-start: rgba(53, 53, 53, 1); + --scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0); + } +/* End theme: dark */ +} diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 84123f4e9d3..3b236641337 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -2098,3 +2098,413 @@ in src-script.js } /* End: styles for --scrape-examples feature */ + +/* Begin: styles for themes + + Keep the default light and dark themes synchronized with the ones + in noscript.css + + The special "Begin theme" and "End theme" below are used by a lot of + tooling to ensure different themes all define all the variables. Do not + alter their formatting. */ + +/* Begin theme: light */ +:root[data-theme="light"] { + --main-background-color: white; + --main-color: black; + --settings-input-color: #2196f3; + --settings-input-border-color: #717171; + --settings-button-color: #000; + --settings-button-border-focus: #717171; + --sidebar-background-color: #f5f5f5; + --sidebar-background-color-hover: #e0e0e0; + --code-block-background-color: #f5f5f5; + --scrollbar-track-background-color: #dcdcdc; + --scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6); + --scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9; + --headings-border-bottom-color: #ddd; + --border-color: #e0e0e0; + --button-background-color: #fff; + --right-side-color: grey; + --code-attribute-color: #999; + --toggles-color: #999; + --toggle-filter: none; + --search-input-focused-border-color: #66afe9; + --copy-path-button-color: #999; + --copy-path-img-filter: invert(50%); + --copy-path-img-hover-filter: invert(35%); + --codeblock-error-hover-color: rgb(255, 0, 0); + --codeblock-error-color: rgba(255, 0, 0, .5); + --codeblock-ignore-hover-color: rgb(255, 142, 0); + --codeblock-ignore-color: rgba(255, 142, 0, .6); + --warning-border-color: #ff8e00; + --type-link-color: #ad378a; + --trait-link-color: #6e4fc9; + --assoc-item-link-color: #3873ad; + --function-link-color: #ad7c37; + --macro-link-color: #068000; + --keyword-link-color: #3873ad; + --mod-link-color: #3873ad; + --link-color: #3873ad; + --sidebar-link-color: #356da4; + --sidebar-current-link-background-color: #fff; + --search-result-link-focus-background-color: #ccc; + --search-result-border-color: #aaa3; + --search-color: #000; + --search-error-code-background-color: #d0cccc; + --search-results-alias-color: #000; + --search-results-grey-color: #999; + --search-tab-title-count-color: #888; + --search-tab-button-not-selected-border-top-color: #e6e6e6; + --search-tab-button-not-selected-background: #e6e6e6; + --search-tab-button-selected-border-top-color: #0089ff; + --search-tab-button-selected-background: #fff; + --stab-background-color: #fff5d6; + --stab-code-color: #000; + --code-highlight-kw-color: #8959a8; + --code-highlight-kw-2-color: #4271ae; + --code-highlight-lifetime-color: #b76514; + --code-highlight-prelude-color: #4271ae; + --code-highlight-prelude-val-color: #c82829; + --code-highlight-number-color: #718c00; + --code-highlight-string-color: #718c00; + --code-highlight-literal-color: #c82829; + --code-highlight-attribute-color: #c82829; + --code-highlight-self-color: #c82829; + --code-highlight-macro-color: #3e999f; + --code-highlight-question-mark-color: #ff9011; + --code-highlight-comment-color: #8e908c; + --code-highlight-doc-comment-color: #4d4d4c; + --src-line-numbers-span-color: #c67e2d; + --src-line-number-highlighted-background-color: #fdffd3; + --test-arrow-color: #f5f5f5; + --test-arrow-background-color: rgba(78, 139, 202, 0.2); + --test-arrow-hover-color: #f5f5f5; + --test-arrow-hover-background-color: rgb(78, 139, 202); + --target-background-color: #fdffd3; + --target-border-color: #ad7c37; + --kbd-color: #000; + --kbd-background: #fafbfc; + --kbd-box-shadow-color: #c6cbd1; + --rust-logo-filter: initial; + /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */ + --crate-search-div-filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) + brightness(114%) contrast(76%); + --crate-search-div-hover-filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) + brightness(96%) contrast(93%); + --crate-search-hover-border: #717171; + --src-sidebar-background-selected: #fff; + --src-sidebar-background-hover: #e0e0e0; + --table-alt-row-background-color: #f5f5f5; + --codeblock-link-background: #eee; + --scrape-example-toggle-line-background: #ccc; + --scrape-example-toggle-line-hover-background: #999; + --scrape-example-code-line-highlight: #fcffd6; + --scrape-example-code-line-highlight-focus: #f6fdb0; + --scrape-example-help-border-color: #555; + --scrape-example-help-color: #333; + --scrape-example-help-hover-border-color: #000; + --scrape-example-help-hover-color: #000; + --scrape-example-code-wrapper-background-start: rgba(255, 255, 255, 1); + --scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0); +} +/* End theme: light */ + +/* Begin theme: dark */ +:root[data-theme="dark"] { + --main-background-color: #353535; + --main-color: #ddd; + --settings-input-color: #2196f3; + --settings-input-border-color: #999; + --settings-button-color: #000; + --settings-button-border-focus: #ffb900; + --sidebar-background-color: #505050; + --sidebar-background-color-hover: #676767; + --code-block-background-color: #2A2A2A; + --scrollbar-track-background-color: #717171; + --scrollbar-thumb-background-color: rgba(32, 34, 37, .6); + --scrollbar-color: rgba(32,34,37,.6) #5a5a5a; + --headings-border-bottom-color: #d2d2d2; + --border-color: #e0e0e0; + --button-background-color: #f0f0f0; + --right-side-color: grey; + --code-attribute-color: #999; + --toggles-color: #999; + --toggle-filter: invert(100%); + --search-input-focused-border-color: #008dfd; + --copy-path-button-color: #999; + --copy-path-img-filter: invert(50%); + --copy-path-img-hover-filter: invert(65%); + --codeblock-error-hover-color: rgb(255, 0, 0); + --codeblock-error-color: rgba(255, 0, 0, .5); + --codeblock-ignore-hover-color: rgb(255, 142, 0); + --codeblock-ignore-color: rgba(255, 142, 0, .6); + --warning-border-color: #ff8e00; + --type-link-color: #2dbfb8; + --trait-link-color: #b78cf2; + --assoc-item-link-color: #d2991d; + --function-link-color: #2bab63; + --macro-link-color: #09bd00; + --keyword-link-color: #d2991d; + --mod-link-color: #d2991d; + --link-color: #d2991d; + --sidebar-link-color: #fdbf35; + --sidebar-current-link-background-color: #444; + --search-result-link-focus-background-color: #616161; + --search-result-border-color: #aaa3; + --search-color: #111; + --search-error-code-background-color: #484848; + --search-results-alias-color: #fff; + --search-results-grey-color: #ccc; + --search-tab-title-count-color: #888; + --search-tab-button-not-selected-border-top-color: #252525; + --search-tab-button-not-selected-background: #252525; + --search-tab-button-selected-border-top-color: #0089ff; + --search-tab-button-selected-background: #353535; + --stab-background-color: #314559; + --stab-code-color: #e6e1cf; + --code-highlight-kw-color: #ab8ac1; + --code-highlight-kw-2-color: #769acb; + --code-highlight-lifetime-color: #d97f26; + --code-highlight-prelude-color: #769acb; + --code-highlight-prelude-val-color: #ee6868; + --code-highlight-number-color: #83a300; + --code-highlight-string-color: #83a300; + --code-highlight-literal-color: #ee6868; + --code-highlight-attribute-color: #ee6868; + --code-highlight-self-color: #ee6868; + --code-highlight-macro-color: #3e999f; + --code-highlight-question-mark-color: #ff9011; + --code-highlight-comment-color: #8d8d8b; + --code-highlight-doc-comment-color: #8ca375; + --src-line-numbers-span-color: #3b91e2; + --src-line-number-highlighted-background-color: #0a042f; + --test-arrow-color: #dedede; + --test-arrow-background-color: rgba(78, 139, 202, 0.2); + --test-arrow-hover-color: #dedede; + --test-arrow-hover-background-color: #4e8bca; + --target-background-color: #494a3d; + --target-border-color: #bb7410; + --kbd-color: #000; + --kbd-background: #fafbfc; + --kbd-box-shadow-color: #c6cbd1; + --rust-logo-filter: drop-shadow(1px 0 0px #fff) + drop-shadow(0 1px 0 #fff) + drop-shadow(-1px 0 0 #fff) + drop-shadow(0 -1px 0 #fff); + /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */ + --crate-search-div-filter: invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) + brightness(90%) contrast(90%); + --crate-search-div-hover-filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) + brightness(100%) contrast(91%); + --crate-search-hover-border: #2196f3; + --src-sidebar-background-selected: #333; + --src-sidebar-background-hover: #444; + --table-alt-row-background-color: #2a2a2a; + --codeblock-link-background: #333; + --scrape-example-toggle-line-background: #999; + --scrape-example-toggle-line-hover-background: #c5c5c5; + --scrape-example-code-line-highlight: #5b3b01; + --scrape-example-code-line-highlight-focus: #7c4b0f; + --scrape-example-help-border-color: #aaa; + --scrape-example-help-color: #eee; + --scrape-example-help-hover-border-color: #fff; + --scrape-example-help-hover-color: #fff; + --scrape-example-code-wrapper-background-start: rgba(53, 53, 53, 1); + --scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0); +} +/* End theme: dark */ + +/* Begin theme: ayu */ +/* +Based off of the Ayu theme +Original by Dempfi (https://github.com/dempfi/ayu) +*/ +:root[data-theme="ayu"] { + --main-background-color: #0f1419; + --main-color: #c5c5c5; + --settings-input-color: #ffb454; + --settings-input-border-color: #999; + --settings-button-color: #fff; + --settings-button-border-focus: #e0e0e0; + --sidebar-background-color: #14191f; + --sidebar-background-color-hover: rgba(70, 70, 70, 0.33); + --code-block-background-color: #191f26; + --scrollbar-track-background-color: transparent; + --scrollbar-thumb-background-color: #5c6773; + --scrollbar-color: #5c6773 #24292f; + --headings-border-bottom-color: #5c6773; + --border-color: #5c6773; + --button-background-color: #141920; + --right-side-color: grey; + --code-attribute-color: #999; + --toggles-color: #999; + --toggle-filter: invert(100%); + --search-input-focused-border-color: #5c6773; /* Same as `--border-color`. */ + --copy-path-button-color: #fff; + --copy-path-img-filter: invert(70%); + --copy-path-img-hover-filter: invert(100%); + --codeblock-error-hover-color: rgb(255, 0, 0); + --codeblock-error-color: rgba(255, 0, 0, .5); + --codeblock-ignore-hover-color: rgb(255, 142, 0); + --codeblock-ignore-color: rgba(255, 142, 0, .6); + --warning-border-color: #ff8e00; + --type-link-color: #ffa0a5; + --trait-link-color: #39afd7; + --assoc-item-link-color: #39afd7; + --function-link-color: #fdd687; + --macro-link-color: #a37acc; + --keyword-link-color: #39afd7; + --mod-link-color: #39afd7; + --link-color: #39afd7; + --sidebar-link-color: #53b1db; + --sidebar-current-link-background-color: transparent; + --search-result-link-focus-background-color: #3c3c3c; + --search-result-border-color: #aaa3; + --search-color: #fff; + --search-error-code-background-color: #4f4c4c; + --search-results-alias-color: #c5c5c5; + --search-results-grey-color: #999; + --search-tab-title-count-color: #888; + --search-tab-button-not-selected-border-top-color: none; + --search-tab-button-not-selected-background: transparent !important; + --search-tab-button-selected-border-top-color: none; + --search-tab-button-selected-background: #141920 !important; + --stab-background-color: #314559; + --stab-code-color: #e6e1cf; + --code-highlight-kw-color: #ff7733; + --code-highlight-kw-2-color: #ff7733; + --code-highlight-lifetime-color: #ff7733; + --code-highlight-prelude-color: #69f2df; + --code-highlight-prelude-val-color: #ff7733; + --code-highlight-number-color: #b8cc52; + --code-highlight-string-color: #b8cc52; + --code-highlight-literal-color: #ff7733; + --code-highlight-attribute-color: #e6e1cf; + --code-highlight-self-color: #36a3d9; + --code-highlight-macro-color: #a37acc; + --code-highlight-question-mark-color: #ff9011; + --code-highlight-comment-color: #788797; + --code-highlight-doc-comment-color: #a1ac88; + --src-line-numbers-span-color: #5c6773; + --src-line-number-highlighted-background-color: rgba(255, 236, 164, 0.06); + --test-arrow-color: #788797; + --test-arrow-background-color: rgba(57, 175, 215, 0.09); + --test-arrow-hover-color: #c5c5c5; + --test-arrow-hover-background-color: rgba(57, 175, 215, 0.368); + --target-background-color: rgba(255, 236, 164, 0.06); + --target-border-color: rgba(255, 180, 76, 0.85); + --kbd-color: #c5c5c5; + --kbd-background: #314559; + --kbd-box-shadow-color: #5c6773; + --rust-logo-filter: drop-shadow(1px 0 0px #fff) + drop-shadow(0 1px 0 #fff) + drop-shadow(-1px 0 0 #fff) + drop-shadow(0 -1px 0 #fff); + /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */ + --crate-search-div-filter: invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg) + brightness(94%) contrast(94%); + --crate-search-div-hover-filter: invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg) + brightness(113%) contrast(76%); + --crate-search-hover-border: #e0e0e0; + --src-sidebar-background-selected: #14191f; + --src-sidebar-background-hover: #14191f; + --table-alt-row-background-color: #191f26; + --codeblock-link-background: #333; + --scrape-example-toggle-line-background: #999; + --scrape-example-toggle-line-hover-background: #c5c5c5; + --scrape-example-code-line-highlight: #5b3b01; + --scrape-example-code-line-highlight-focus: #7c4b0f; + --scrape-example-help-border-color: #aaa; + --scrape-example-help-color: #eee; + --scrape-example-help-hover-border-color: #fff; + --scrape-example-help-hover-color: #fff; + --scrape-example-code-wrapper-background-start: rgba(15, 20, 25, 1); + --scrape-example-code-wrapper-background-end: rgba(15, 20, 25, 0); +} + +:root[data-theme="ayu"] h1, +:root[data-theme="ayu"] h2, +:root[data-theme="ayu"] h3, +:root[data-theme="ayu"] h4, +:where(:root[data-theme="ayu"]) h1 a, +:root[data-theme="ayu"] .sidebar h2 a, +:root[data-theme="ayu"] .sidebar h3 a, +:root[data-theme="ayu"] #source-sidebar > .title { + color: #fff; +} + +:root[data-theme="ayu"] .docblock code { + color: #ffb454; +} + +:root[data-theme="ayu"] .docblock a > code { + color: #39AFD7 !important; +} + +:root[data-theme="ayu"] .code-header, +:root[data-theme="ayu"] .docblock pre > code, +:root[data-theme="ayu"] pre, +:root[data-theme="ayu"] pre > code, +:root[data-theme="ayu"] .item-info code, +:root[data-theme="ayu"] .rustdoc.source .example-wrap { + color: #e6e1cf; +} + +:root[data-theme="ayu"] .sidebar .current, +:root[data-theme="ayu"] .sidebar a:hover, +:root[data-theme="ayu"] #src-sidebar div.files > a:hover, +:root[data-theme="ayu"] details.dir-entry summary:hover, +:root[data-theme="ayu"] #src-sidebar div.files > a:focus, +:root[data-theme="ayu"] details.dir-entry summary:focus, +:root[data-theme="ayu"] #src-sidebar div.files > a.selected { + color: #ffb44c; +} + +:root[data-theme="ayu"] .sidebar-elems .location { + color: #ff7733; +} + +:root[data-theme="ayu"] .src-line-numbers .line-highlighted { + color: #708090; + padding-right: 7px; + border-right: 1px solid #ffb44c; +} + +:root[data-theme="ayu"] .search-results a:hover, +:root[data-theme="ayu"] .search-results a:focus { + color: #fff !important; + background-color: #3c3c3c; +} + +:root[data-theme="ayu"] .search-results a { + color: #0096cf; +} + +:root[data-theme="ayu"] .search-results a div.desc { + color: #c5c5c5; +} + +:root[data-theme="ayu"] .result-name .primitive > i, +:root[data-theme="ayu"] .result-name .keyword > i { + color: #788797; +} + +:root[data-theme="ayu"] #search-tabs > button.selected { + border-bottom: 1px solid #ffb44c !important; + border-top: none; +} +:root[data-theme="ayu"] #search-tabs > button:not(.selected) { + border: none; + background-color: transparent !important; +} +:root[data-theme="ayu"] #search-tabs > button:hover { + border-bottom: 1px solid rgba(242, 151, 24, 0.3); +} + +:root[data-theme="ayu"] #settings-menu > a img { + filter: invert(100); +} +/* End theme: ayu */ + +/* End: styles for themes */ diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css deleted file mode 100644 index 873a1668f8b..00000000000 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ /dev/null @@ -1,181 +0,0 @@ -/* -Based off of the Ayu theme -Original by Dempfi (https://github.com/dempfi/ayu) -*/ - -:root { - --main-background-color: #0f1419; - --main-color: #c5c5c5; - --settings-input-color: #ffb454; - --settings-input-border-color: #999; - --settings-button-color: #fff; - --settings-button-border-focus: #e0e0e0; - --sidebar-background-color: #14191f; - --sidebar-background-color-hover: rgba(70, 70, 70, 0.33); - --code-block-background-color: #191f26; - --scrollbar-track-background-color: transparent; - --scrollbar-thumb-background-color: #5c6773; - --scrollbar-color: #5c6773 #24292f; - --headings-border-bottom-color: #5c6773; - --border-color: #5c6773; - --button-background-color: #141920; - --right-side-color: grey; - --code-attribute-color: #999; - --toggles-color: #999; - --toggle-filter: invert(100%); - --search-input-focused-border-color: #5c6773; /* Same as `--border-color`. */ - --copy-path-button-color: #fff; - --copy-path-img-filter: invert(70%); - --copy-path-img-hover-filter: invert(100%); - --codeblock-error-hover-color: rgb(255, 0, 0); - --codeblock-error-color: rgba(255, 0, 0, .5); - --codeblock-ignore-hover-color: rgb(255, 142, 0); - --codeblock-ignore-color: rgba(255, 142, 0, .6); - --warning-border-color: #ff8e00; - --type-link-color: #ffa0a5; - --trait-link-color: #39afd7; - --assoc-item-link-color: #39afd7; - --function-link-color: #fdd687; - --macro-link-color: #a37acc; - --keyword-link-color: #39afd7; - --mod-link-color: #39afd7; - --link-color: #39afd7; - --sidebar-link-color: #53b1db; - --sidebar-current-link-background-color: transparent; - --search-result-link-focus-background-color: #3c3c3c; - --search-result-border-color: #aaa3; - --search-color: #fff; - --search-error-code-background-color: #4f4c4c; - --search-results-alias-color: #c5c5c5; - --search-results-grey-color: #999; - --search-tab-title-count-color: #888; - --search-tab-button-not-selected-border-top-color: none; - --search-tab-button-not-selected-background: transparent !important; - --search-tab-button-selected-border-top-color: none; - --search-tab-button-selected-background: #141920 !important; - --stab-background-color: #314559; - --stab-code-color: #e6e1cf; - --code-highlight-kw-color: #ff7733; - --code-highlight-kw-2-color: #ff7733; - --code-highlight-lifetime-color: #ff7733; - --code-highlight-prelude-color: #69f2df; - --code-highlight-prelude-val-color: #ff7733; - --code-highlight-number-color: #b8cc52; - --code-highlight-string-color: #b8cc52; - --code-highlight-literal-color: #ff7733; - --code-highlight-attribute-color: #e6e1cf; - --code-highlight-self-color: #36a3d9; - --code-highlight-macro-color: #a37acc; - --code-highlight-question-mark-color: #ff9011; - --code-highlight-comment-color: #788797; - --code-highlight-doc-comment-color: #a1ac88; - --src-line-numbers-span-color: #5c6773; - --src-line-number-highlighted-background-color: rgba(255, 236, 164, 0.06); - --test-arrow-color: #788797; - --test-arrow-background-color: rgba(57, 175, 215, 0.09); - --test-arrow-hover-color: #c5c5c5; - --test-arrow-hover-background-color: rgba(57, 175, 215, 0.368); - --target-background-color: rgba(255, 236, 164, 0.06); - --target-border-color: rgba(255, 180, 76, 0.85); - --kbd-color: #c5c5c5; - --kbd-background: #314559; - --kbd-box-shadow-color: #5c6773; - --rust-logo-filter: drop-shadow(1px 0 0px #fff) - drop-shadow(0 1px 0 #fff) - drop-shadow(-1px 0 0 #fff) - drop-shadow(0 -1px 0 #fff); - /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */ - --crate-search-div-filter: invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg) - brightness(94%) contrast(94%); - --crate-search-div-hover-filter: invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg) - brightness(113%) contrast(76%); - --crate-search-hover-border: #e0e0e0; - --src-sidebar-background-selected: #14191f; - --src-sidebar-background-hover: #14191f; - --table-alt-row-background-color: #191f26; - --codeblock-link-background: #333; - --scrape-example-toggle-line-background: #999; - --scrape-example-toggle-line-hover-background: #c5c5c5; - --scrape-example-code-line-highlight: #5b3b01; - --scrape-example-code-line-highlight-focus: #7c4b0f; - --scrape-example-help-border-color: #aaa; - --scrape-example-help-color: #eee; - --scrape-example-help-hover-border-color: #fff; - --scrape-example-help-hover-color: #fff; - --scrape-example-code-wrapper-background-start: rgba(15, 20, 25, 1); - --scrape-example-code-wrapper-background-end: rgba(15, 20, 25, 0); -} - -h1, h2, h3, h4, -h1 a, .sidebar h2 a, .sidebar h3 a, -#src-sidebar > .title { - color: #fff; -} -h4 { - border: none; -} - -.docblock code { - color: #ffb454; -} -.docblock a > code { - color: #39AFD7 !important; -} -.code-header, -.docblock pre > code, -pre, pre > code, -.item-info code, -.rustdoc.src .example-wrap { - color: #e6e1cf; -} - -.sidebar .current, -.sidebar a:hover, -#src-sidebar div.files > a:hover, details.dir-entry summary:hover, -#src-sidebar div.files > a:focus, details.dir-entry summary:focus, -#src-sidebar div.files > a.selected { - color: #ffb44c; -} - -.sidebar-elems .location { - color: #ff7733; -} - -.src-line-numbers .line-highlighted { - color: #708090; - padding-right: 7px; - border-right: 1px solid #ffb44c; -} - -.search-results a:hover, -.search-results a:focus { - color: #fff !important; - background-color: #3c3c3c; -} - -.search-results a { - color: #0096cf; -} -.search-results a div.desc { - color: #c5c5c5; -} - -.result-name .primitive > i, .result-name .keyword > i { - color: #788797; -} - -#search-tabs > button.selected { - border-bottom: 1px solid #ffb44c !important; - border-top: none; -} -#search-tabs > button:not(.selected) { - border: none; - background-color: transparent !important; -} -#search-tabs > button:hover { - border-bottom: 1px solid rgba(242, 151, 24, 0.3); -} - -#settings-menu > a img { - filter: invert(100); -} diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css deleted file mode 100644 index 2b6e28d35a5..00000000000 --- a/src/librustdoc/html/static/css/themes/dark.css +++ /dev/null @@ -1,102 +0,0 @@ -:root { - --main-background-color: #353535; - --main-color: #ddd; - --settings-input-color: #2196f3; - --settings-input-border-color: #999; - --settings-button-color: #000; - --settings-button-border-focus: #ffb900; - --sidebar-background-color: #505050; - --sidebar-background-color-hover: #676767; - --code-block-background-color: #2A2A2A; - --scrollbar-track-background-color: #717171; - --scrollbar-thumb-background-color: rgba(32, 34, 37, .6); - --scrollbar-color: rgba(32,34,37,.6) #5a5a5a; - --headings-border-bottom-color: #d2d2d2; - --border-color: #e0e0e0; - --button-background-color: #f0f0f0; - --right-side-color: grey; - --code-attribute-color: #999; - --toggles-color: #999; - --toggle-filter: invert(100%); - --search-input-focused-border-color: #008dfd; - --copy-path-button-color: #999; - --copy-path-img-filter: invert(50%); - --copy-path-img-hover-filter: invert(65%); - --codeblock-error-hover-color: rgb(255, 0, 0); - --codeblock-error-color: rgba(255, 0, 0, .5); - --codeblock-ignore-hover-color: rgb(255, 142, 0); - --codeblock-ignore-color: rgba(255, 142, 0, .6); - --warning-border-color: #ff8e00; - --type-link-color: #2dbfb8; - --trait-link-color: #b78cf2; - --assoc-item-link-color: #d2991d; - --function-link-color: #2bab63; - --macro-link-color: #09bd00; - --keyword-link-color: #d2991d; - --mod-link-color: #d2991d; - --link-color: #d2991d; - --sidebar-link-color: #fdbf35; - --sidebar-current-link-background-color: #444; - --search-result-link-focus-background-color: #616161; - --search-result-border-color: #aaa3; - --search-color: #111; - --search-error-code-background-color: #484848; - --search-results-alias-color: #fff; - --search-results-grey-color: #ccc; - --search-tab-title-count-color: #888; - --search-tab-button-not-selected-border-top-color: #252525; - --search-tab-button-not-selected-background: #252525; - --search-tab-button-selected-border-top-color: #0089ff; - --search-tab-button-selected-background: #353535; - --stab-background-color: #314559; - --stab-code-color: #e6e1cf; - --code-highlight-kw-color: #ab8ac1; - --code-highlight-kw-2-color: #769acb; - --code-highlight-lifetime-color: #d97f26; - --code-highlight-prelude-color: #769acb; - --code-highlight-prelude-val-color: #ee6868; - --code-highlight-number-color: #83a300; - --code-highlight-string-color: #83a300; - --code-highlight-literal-color: #ee6868; - --code-highlight-attribute-color: #ee6868; - --code-highlight-self-color: #ee6868; - --code-highlight-macro-color: #3e999f; - --code-highlight-question-mark-color: #ff9011; - --code-highlight-comment-color: #8d8d8b; - --code-highlight-doc-comment-color: #8ca375; - --src-line-numbers-span-color: #3b91e2; - --src-line-number-highlighted-background-color: #0a042f; - --test-arrow-color: #dedede; - --test-arrow-background-color: rgba(78, 139, 202, 0.2); - --test-arrow-hover-color: #dedede; - --test-arrow-hover-background-color: #4e8bca; - --target-background-color: #494a3d; - --target-border-color: #bb7410; - --kbd-color: #000; - --kbd-background: #fafbfc; - --kbd-box-shadow-color: #c6cbd1; - --rust-logo-filter: drop-shadow(1px 0 0px #fff) - drop-shadow(0 1px 0 #fff) - drop-shadow(-1px 0 0 #fff) - drop-shadow(0 -1px 0 #fff); - /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */ - --crate-search-div-filter: invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) - brightness(90%) contrast(90%); - --crate-search-div-hover-filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) - brightness(100%) contrast(91%); - --crate-search-hover-border: #2196f3; - --src-sidebar-background-selected: #333; - --src-sidebar-background-hover: #444; - --table-alt-row-background-color: #2a2a2a; - --codeblock-link-background: #333; - --scrape-example-toggle-line-background: #999; - --scrape-example-toggle-line-hover-background: #c5c5c5; - --scrape-example-code-line-highlight: #5b3b01; - --scrape-example-code-line-highlight-focus: #7c4b0f; - --scrape-example-help-border-color: #aaa; - --scrape-example-help-color: #eee; - --scrape-example-help-hover-border-color: #fff; - --scrape-example-help-hover-color: #fff; - --scrape-example-code-wrapper-background-start: rgba(53, 53, 53, 1); - --scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0); -} diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css deleted file mode 100644 index 9c016db4502..00000000000 --- a/src/librustdoc/html/static/css/themes/light.css +++ /dev/null @@ -1,99 +0,0 @@ -:root { - --main-background-color: white; - --main-color: black; - --settings-input-color: #2196f3; - --settings-input-border-color: #717171; - --settings-button-color: #000; - --settings-button-border-focus: #717171; - --sidebar-background-color: #f5f5f5; - --sidebar-background-color-hover: #e0e0e0; - --code-block-background-color: #f5f5f5; - --scrollbar-track-background-color: #dcdcdc; - --scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6); - --scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9; - --headings-border-bottom-color: #ddd; - --border-color: #e0e0e0; - --button-background-color: #fff; - --right-side-color: grey; - --code-attribute-color: #999; - --toggles-color: #999; - --toggle-filter: none; - --search-input-focused-border-color: #66afe9; - --copy-path-button-color: #999; - --copy-path-img-filter: invert(50%); - --copy-path-img-hover-filter: invert(35%); - --codeblock-error-hover-color: rgb(255, 0, 0); - --codeblock-error-color: rgba(255, 0, 0, .5); - --codeblock-ignore-hover-color: rgb(255, 142, 0); - --codeblock-ignore-color: rgba(255, 142, 0, .6); - --warning-border-color: #ff8e00; - --type-link-color: #ad378a; - --trait-link-color: #6e4fc9; - --assoc-item-link-color: #3873ad; - --function-link-color: #ad7c37; - --macro-link-color: #068000; - --keyword-link-color: #3873ad; - --mod-link-color: #3873ad; - --link-color: #3873ad; - --sidebar-link-color: #356da4; - --sidebar-current-link-background-color: #fff; - --search-result-link-focus-background-color: #ccc; - --search-result-border-color: #aaa3; - --search-color: #000; - --search-error-code-background-color: #d0cccc; - --search-results-alias-color: #000; - --search-results-grey-color: #999; - --search-tab-title-count-color: #888; - --search-tab-button-not-selected-border-top-color: #e6e6e6; - --search-tab-button-not-selected-background: #e6e6e6; - --search-tab-button-selected-border-top-color: #0089ff; - --search-tab-button-selected-background: #fff; - --stab-background-color: #fff5d6; - --stab-code-color: #000; - --code-highlight-kw-color: #8959a8; - --code-highlight-kw-2-color: #4271ae; - --code-highlight-lifetime-color: #b76514; - --code-highlight-prelude-color: #4271ae; - --code-highlight-prelude-val-color: #c82829; - --code-highlight-number-color: #718c00; - --code-highlight-string-color: #718c00; - --code-highlight-literal-color: #c82829; - --code-highlight-attribute-color: #c82829; - --code-highlight-self-color: #c82829; - --code-highlight-macro-color: #3e999f; - --code-highlight-question-mark-color: #ff9011; - --code-highlight-comment-color: #8e908c; - --code-highlight-doc-comment-color: #4d4d4c; - --src-line-numbers-span-color: #c67e2d; - --src-line-number-highlighted-background-color: #fdffd3; - --test-arrow-color: #f5f5f5; - --test-arrow-background-color: rgba(78, 139, 202, 0.2); - --test-arrow-hover-color: #f5f5f5; - --test-arrow-hover-background-color: rgb(78, 139, 202); - --target-background-color: #fdffd3; - --target-border-color: #ad7c37; - --kbd-color: #000; - --kbd-background: #fafbfc; - --kbd-box-shadow-color: #c6cbd1; - --rust-logo-filter: initial; - /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */ - --crate-search-div-filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) - brightness(114%) contrast(76%); - --crate-search-div-hover-filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) - brightness(96%) contrast(93%); - --crate-search-hover-border: #717171; - --src-sidebar-background-selected: #fff; - --src-sidebar-background-hover: #e0e0e0; - --table-alt-row-background-color: #f5f5f5; - --codeblock-link-background: #eee; - --scrape-example-toggle-line-background: #ccc; - --scrape-example-toggle-line-hover-background: #999; - --scrape-example-code-line-highlight: #fcffd6; - --scrape-example-code-line-highlight-focus: #f6fdb0; - --scrape-example-help-border-color: #555; - --scrape-example-help-color: #333; - --scrape-example-help-hover-border-color: #000; - --scrape-example-help-hover-color: #000; - --scrape-example-code-wrapper-background-start: rgba(255, 255, 255, 1); - --scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0); -} diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 822d22946b4..eb256455b08 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -49,10 +49,12 @@ window.currentCrate = getVar("current-crate"); function setMobileTopbar() { // FIXME: It would be nicer to generate this text content directly in HTML, // but with the current code it's hard to get the right information in the right place. - const mobileLocationTitle = document.querySelector(".mobile-topbar h2"); + const mobileTopbar = document.querySelector(".mobile-topbar"); const locationTitle = document.querySelector(".sidebar h2.location"); - if (mobileLocationTitle && locationTitle) { - mobileLocationTitle.innerHTML = locationTitle.innerHTML; + if (mobileTopbar && locationTitle) { + const mobileTitle = document.createElement("h2"); + mobileTitle.innerHTML = locationTitle.innerHTML; + mobileTopbar.appendChild(mobileTitle); } } @@ -204,9 +206,6 @@ function preLoadCss(cssUrl) { // Sending request for the CSS and the JS files at the same time so it will // hopefully be loaded when the JS will generate the settings content. loadScript(getVar("static-root-path") + getVar("settings-js")); - preLoadCss(getVar("static-root-path") + getVar("theme-light-css")); - preLoadCss(getVar("static-root-path") + getVar("theme-dark-css")); - preLoadCss(getVar("static-root-path") + getVar("theme-ayu-css")); // Pre-load all theme CSS files, so that switching feels seamless. // // When loading settings.html as a standalone page, the equivalent HTML is diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index af3ca42a6c0..c69641092ab 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -5,6 +5,7 @@ // the page, so we don't see major layout changes during the load of the page. "use strict"; +const builtinThemes = ["light", "dark", "ayu"]; const darkThemes = ["dark", "ayu"]; window.currentTheme = document.getElementById("themeStyle"); @@ -119,19 +120,32 @@ function switchTheme(newThemeName, saveTheme) { updateLocalStorage("theme", newThemeName); } - let newHref; + document.documentElement.setAttribute("data-theme", newThemeName); - if (newThemeName === "light" || newThemeName === "dark" || newThemeName === "ayu") { - newHref = getVar("static-root-path") + getVar("theme-" + newThemeName + "-css"); + if (builtinThemes.indexOf(newThemeName) !== -1) { + if (window.currentTheme) { + window.currentTheme.parentNode.removeChild(window.currentTheme); + window.currentTheme = null; + } } else { - newHref = getVar("root-path") + newThemeName + getVar("resource-suffix") + ".css"; - } - - if (!window.currentTheme) { - document.write(``); - window.currentTheme = document.getElementById("themeStyle"); - } else if (newHref !== window.currentTheme.href) { - window.currentTheme.href = newHref; + const newHref = getVar("root-path") + newThemeName + + getVar("resource-suffix") + ".css"; + if (!window.currentTheme) { + // If we're in the middle of loading, document.write blocks + // rendering, but if we are done, it would blank the page. + if (document.readyState === "loading") { + document.write(``); + window.currentTheme = document.getElementById("themeStyle"); + } else { + window.currentTheme = document.createElement("link"); + window.currentTheme.rel = "stylesheet"; + window.currentTheme.id = "themeStyle"; + window.currentTheme.href = newHref; + document.documentElement.appendChild(window.currentTheme); + } + } else if (newHref !== window.currentTheme.href) { + window.currentTheme.href = newHref; + } } } diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index 7742646f81a..ca9a78f51b3 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -108,9 +108,6 @@ static_files! { rust_favicon_svg => "static/images/favicon.svg", rust_favicon_png_16 => "static/images/favicon-16x16.png", rust_favicon_png_32 => "static/images/favicon-32x32.png", - theme_light_css => "static/css/themes/light.css", - theme_dark_css => "static/css/themes/dark.css", - theme_ayu_css => "static/css/themes/ayu.css", fira_sans_regular => "static/fonts/FiraSans-Regular.woff2", fira_sans_medium => "static/fonts/FiraSans-Medium.woff2", fira_sans_license => "static/fonts/FiraSans-LICENSE.txt", diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index ad63571c6d0..579c782be09 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -33,9 +33,6 @@ data-channel="{{rust_channel}}" {#+ #} data-search-js="{{files.search_js}}" {#+ #} data-settings-js="{{files.settings_js}}" {#+ #} - data-theme-light-css="{{files.theme_light_css}}" {#+ #} - data-theme-dark-css="{{files.theme_dark_css}}" {#+ #} - data-theme-ayu-css="{{files.theme_ayu_css}}" {#+ #} > {# #} {# #} {% if page.css_class.contains("crate") %} @@ -51,12 +48,6 @@ {# #} {% endif %} {# #} @@ -93,8 +84,7 @@ {# #} {% endif %}
{# #} -

{# #} - {# #} + {% endif %}