From e3029abfaec4252ab0ae7010780be0094d8870e0 Mon Sep 17 00:00:00 2001 From: VulnBandit <183613941+VulnBandit@users.noreply.github.com> Date: Wed, 2 Oct 2024 15:11:16 +0200 Subject: [PATCH 01/18] Improve duplicate derive Copy/Clone diagnostics --- .../src/diagnostics/move_errors.rs | 17 ++++++++++++++ ...duplicate-derive-copy-clone-diagnostics.rs | 11 +++++++++ ...icate-derive-copy-clone-diagnostics.stderr | 23 +++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs create mode 100644 tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 3871816777c7f..15cc9c20ab7dc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -10,6 +10,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex}; use rustc_span::{BytePos, ExpnKind, MacroKind, Span}; use rustc_trait_selection::error_reporting::traits::FindExprBySpan; +use rustc_trait_selection::infer::InferCtxtExt; use tracing::debug; use crate::MirBorrowckCtxt; @@ -267,6 +268,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { kind, self.is_upvar_field_projection(original_path.as_ref()) ); + if self.has_ambiguous_copy(original_path.ty(self.body, self.infcx.tcx).ty) { + // If the type may implement Copy, skip the error. + // It's an error with the Copy implementation (e.g. duplicate Copy) rather than borrow check + self.dcx().span_delayed_bug( + span, + "Type may implement copy, but there is no other error.", + ); + return; + } ( match kind { &IllegalMoveOriginKind::BorrowedContent { target_place } => self @@ -291,6 +301,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.buffer_error(err); } + fn has_ambiguous_copy(&mut self, ty: Ty<'tcx>) -> bool { + let Some(copy_trait_def) = self.infcx.tcx.lang_items().copy_trait() else { return false }; + // This is only going to be ambiguous if there are incoherent impls, because otherwise + // ambiguity should never happen in MIR. + self.infcx.type_implements_trait(copy_trait_def, [ty], self.param_env).may_apply() + } + fn report_cannot_move_from_static(&mut self, place: Place<'tcx>, span: Span) -> Diag<'infcx> { let description = if place.projection.len() == 1 { format!("static item {}", self.describe_any_place(place.as_ref())) diff --git a/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs b/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs new file mode 100644 index 0000000000000..c4fb620fea4f3 --- /dev/null +++ b/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.rs @@ -0,0 +1,11 @@ +// Duplicate implementations of Copy/Clone should not trigger +// borrow check warnings +// See #131083 + +#[derive(Copy, Clone)] +#[derive(Copy, Clone)] +//~^ ERROR conflicting implementations of trait `Clone` for type `E` +//~| ERROR conflicting implementations of trait `Copy` for type `E` +enum E {} + +fn main() {} diff --git a/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr b/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr new file mode 100644 index 0000000000000..f8e1db33f5363 --- /dev/null +++ b/tests/ui/derives/duplicate-derive-copy-clone-diagnostics.stderr @@ -0,0 +1,23 @@ +error[E0119]: conflicting implementations of trait `Copy` for type `E` + --> $DIR/duplicate-derive-copy-clone-diagnostics.rs:6:10 + | +LL | #[derive(Copy, Clone)] + | ---- first implementation here +LL | #[derive(Copy, Clone)] + | ^^^^ conflicting implementation for `E` + | + = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0119]: conflicting implementations of trait `Clone` for type `E` + --> $DIR/duplicate-derive-copy-clone-diagnostics.rs:6:16 + | +LL | #[derive(Copy, Clone)] + | ----- first implementation here +LL | #[derive(Copy, Clone)] + | ^^^^^ conflicting implementation for `E` + | + = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0119`. From 10b60eba9bc55449721db912fe75bab11de43c4e Mon Sep 17 00:00:00 2001 From: Duncan Proctor Date: Tue, 22 Oct 2024 01:51:54 -0400 Subject: [PATCH 02/18] add third help hint to diagnostic error E0027 --- compiler/rustc_hir_typeck/src/pat.rs | 19 +++++++++++++++++++ .../struct_destructure_fail.stderr | 4 ++++ tests/ui/error-codes/E0027.stderr | 16 ++++++++++++++++ .../usefulness/doc-hidden-fields.stderr | 12 ++++++++++++ .../usefulness/stable-gated-fields.stderr | 4 ++++ .../usefulness/unstable-gated-fields.stderr | 8 ++++++++ tests/ui/structs/struct-field-cfg.stderr | 4 ++++ .../structs/struct-pat-derived-error.stderr | 4 ++++ .../structs/struct-tuple-field-names.stderr | 4 ++++ ...ing-field-when-specifying-same-type.stderr | 16 ++++++++++++++++ ...-missing-inaccessible-field-pattern.stderr | 4 ++++ 11 files changed, 95 insertions(+) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index e961752b24c2c..5868c4bc1fa51 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -2070,6 +2070,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { s = pluralize!(len), them = if len == 1 { "it" } else { "them" }, ), + format!( + "{}{}{}{}", + prefix, + unmentioned_fields + .iter() + .map(|(_, name)| { + let field_name = name.to_string(); + format!("{field_name}: _") + }) + .collect::>() + .join(", "), + if have_inaccessible_fields { ", .." } else { "" }, + postfix, + ), + Applicability::MachineApplicable, + ); + err.span_suggestion( + sp, + "or always ignore missing fields here", format!("{prefix}..{postfix}"), Applicability::MachineApplicable, ); diff --git a/tests/ui/destructuring-assignment/struct_destructure_fail.stderr b/tests/ui/destructuring-assignment/struct_destructure_fail.stderr index 57851ed417ea8..4c4f0663eeb43 100644 --- a/tests/ui/destructuring-assignment/struct_destructure_fail.stderr +++ b/tests/ui/destructuring-assignment/struct_destructure_fail.stderr @@ -41,6 +41,10 @@ LL | Struct { a, b } = Struct { a: 1, b: 2 }; | ~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | Struct { a, b: _ } = Struct { a: 1, b: 2 }; + | ~~~~~~~~ +help: or always ignore missing fields here + | LL | Struct { a, .. } = Struct { a: 1, b: 2 }; | ~~~~~~ diff --git a/tests/ui/error-codes/E0027.stderr b/tests/ui/error-codes/E0027.stderr index 9ae97e4a994da..7bbafcf0a27ab 100644 --- a/tests/ui/error-codes/E0027.stderr +++ b/tests/ui/error-codes/E0027.stderr @@ -10,6 +10,10 @@ LL | Dog { age: x, name } => {} | ~~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | Dog { age: x, name: _ } => {} + | ~~~~~~~~~~~ +help: or always ignore missing fields here + | LL | Dog { age: x, .. } => {} | ~~~~~~ @@ -25,6 +29,10 @@ LL | Dog { name: x, age } => {} | ~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | Dog { name: x, age: _ } => {} + | ~~~~~~~~~~ +help: or always ignore missing fields here + | LL | Dog { name: x, .. } => {} | ~~~~~~ @@ -40,6 +48,10 @@ LL | Dog { name: x, age } => {} | ~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | Dog { name: x, age: _ } => {} + | ~~~~~~~~~~ +help: or always ignore missing fields here + | LL | Dog { name: x, .. } => {} | ~~~~~~ @@ -55,6 +67,10 @@ LL | Dog { name, age } => {} | ~~~~~~~~~~~~~ help: if you don't care about these missing fields, you can explicitly ignore them | +LL | Dog { name: _, age: _ } => {} + | ~~~~~~~~~~~~~~~~~~~ +help: or always ignore missing fields here + | LL | Dog { .. } => {} | ~~~~~~ diff --git a/tests/ui/pattern/usefulness/doc-hidden-fields.stderr b/tests/ui/pattern/usefulness/doc-hidden-fields.stderr index f277bfbc884fb..158eac9a1bd14 100644 --- a/tests/ui/pattern/usefulness/doc-hidden-fields.stderr +++ b/tests/ui/pattern/usefulness/doc-hidden-fields.stderr @@ -21,6 +21,10 @@ LL | let HiddenStruct { one, two, .. } = HiddenStruct::default(); | ~~~~~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | let HiddenStruct { one, two: _, .. } = HiddenStruct::default(); + | ~~~~~~~~~~~~~~ +help: or always ignore missing fields here + | LL | let HiddenStruct { one, .. } = HiddenStruct::default(); | ~~~~~~ @@ -36,6 +40,10 @@ LL | let HiddenStruct { one, hide, two } = HiddenStruct::default(); | ~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | let HiddenStruct { one, hide, two: _ } = HiddenStruct::default(); + | ~~~~~~~~~~ +help: or always ignore missing fields here + | LL | let HiddenStruct { one, hide, .. } = HiddenStruct::default(); | ~~~~~~ @@ -51,6 +59,10 @@ LL | let InCrate { a, b, im_hidden } = InCrate { a: 0, b: false, im_hidden: | ~~~~~~~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | let InCrate { a, b, im_hidden: _ } = InCrate { a: 0, b: false, im_hidden: 0 }; + | ~~~~~~~~~~~~~~~~ +help: or always ignore missing fields here + | LL | let InCrate { a, b, .. } = InCrate { a: 0, b: false, im_hidden: 0 }; | ~~~~~~ diff --git a/tests/ui/pattern/usefulness/stable-gated-fields.stderr b/tests/ui/pattern/usefulness/stable-gated-fields.stderr index cf98c51a2b41e..d6e9bac7c136b 100644 --- a/tests/ui/pattern/usefulness/stable-gated-fields.stderr +++ b/tests/ui/pattern/usefulness/stable-gated-fields.stderr @@ -10,6 +10,10 @@ LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); | ~~~~~~~~~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | let UnstableStruct { stable, stable2: _, .. } = UnstableStruct::default(); + | ~~~~~~~~~~~~~~~~~~ +help: or always ignore missing fields here + | LL | let UnstableStruct { stable, .. } = UnstableStruct::default(); | ~~~~~~ diff --git a/tests/ui/pattern/usefulness/unstable-gated-fields.stderr b/tests/ui/pattern/usefulness/unstable-gated-fields.stderr index e4f5fa06b3ff5..bb10e439ee23d 100644 --- a/tests/ui/pattern/usefulness/unstable-gated-fields.stderr +++ b/tests/ui/pattern/usefulness/unstable-gated-fields.stderr @@ -10,6 +10,10 @@ LL | let UnstableStruct { stable, stable2, unstable } = UnstableStruct::defa | ~~~~~~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | let UnstableStruct { stable, stable2, unstable: _ } = UnstableStruct::default(); + | ~~~~~~~~~~~~~~~ +help: or always ignore missing fields here + | LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); | ~~~~~~ @@ -25,6 +29,10 @@ LL | let UnstableStruct { stable, unstable, stable2 } = UnstableStruct::defa | ~~~~~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | let UnstableStruct { stable, unstable, stable2: _ } = UnstableStruct::default(); + | ~~~~~~~~~~~~~~ +help: or always ignore missing fields here + | LL | let UnstableStruct { stable, unstable, .. } = UnstableStruct::default(); | ~~~~~~ diff --git a/tests/ui/structs/struct-field-cfg.stderr b/tests/ui/structs/struct-field-cfg.stderr index 2b9ba85ddcb88..f30d343d58287 100644 --- a/tests/ui/structs/struct-field-cfg.stderr +++ b/tests/ui/structs/struct-field-cfg.stderr @@ -24,6 +24,10 @@ LL | let Foo { present } = foo; | ~~~~~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | let Foo { present: _ } = foo; + | ~~~~~~~~~~~~~~ +help: or always ignore missing fields here + | LL | let Foo { .. } = foo; | ~~~~~~ diff --git a/tests/ui/structs/struct-pat-derived-error.stderr b/tests/ui/structs/struct-pat-derived-error.stderr index 78bb018cb4be7..d1d68121cf168 100644 --- a/tests/ui/structs/struct-pat-derived-error.stderr +++ b/tests/ui/structs/struct-pat-derived-error.stderr @@ -27,6 +27,10 @@ LL | let A { x, y, b, c } = self.d; | ~~~~~~~~ help: if you don't care about these missing fields, you can explicitly ignore them | +LL | let A { x, y, b: _, c: _ } = self.d; + | ~~~~~~~~~~~~~~ +help: or always ignore missing fields here + | LL | let A { x, y, .. } = self.d; | ~~~~~~ diff --git a/tests/ui/structs/struct-tuple-field-names.stderr b/tests/ui/structs/struct-tuple-field-names.stderr index 0b837a47a8254..5f1ab2f9d6823 100644 --- a/tests/ui/structs/struct-tuple-field-names.stderr +++ b/tests/ui/structs/struct-tuple-field-names.stderr @@ -32,6 +32,10 @@ LL | if let E::S { 0: a, 1: _ } = x { | ~~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | if let E::S { 0: a, 1: _ } = x { + | ~~~~~~~~ +help: or always ignore missing fields here + | LL | if let E::S { 0: a, .. } = x { | ~~~~~~ diff --git a/tests/ui/structs/suggest-replacing-field-when-specifying-same-type.stderr b/tests/ui/structs/suggest-replacing-field-when-specifying-same-type.stderr index e8503f540c288..af530e2b75931 100644 --- a/tests/ui/structs/suggest-replacing-field-when-specifying-same-type.stderr +++ b/tests/ui/structs/suggest-replacing-field-when-specifying-same-type.stderr @@ -19,6 +19,10 @@ LL | Foo::Bar { a, aa: 1, c, b } => (), | ~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | Foo::Bar { a, aa: 1, c, b: _ } => (), + | ~~~~~~~~ +help: or always ignore missing fields here + | LL | Foo::Bar { a, aa: 1, c, .. } => (), | ~~~~~~ @@ -43,6 +47,10 @@ LL | Foo::Baz { bb: 1.0, a } => (), | ~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | Foo::Baz { bb: 1.0, a: _ } => (), + | ~~~~~~~~ +help: or always ignore missing fields here + | LL | Foo::Baz { bb: 1.0, .. } => (), | ~~~~~~ @@ -64,6 +72,10 @@ LL | Foo::Bar { a, aa: "", c, b } => (), | ~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | Foo::Bar { a, aa: "", c, b: _ } => (), + | ~~~~~~~~ +help: or always ignore missing fields here + | LL | Foo::Bar { a, aa: "", c, .. } => (), | ~~~~~~ @@ -85,6 +97,10 @@ LL | Foo::Baz { bb: "", a } => (), | ~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | Foo::Baz { bb: "", a: _ } => (), + | ~~~~~~~~ +help: or always ignore missing fields here + | LL | Foo::Baz { bb: "", .. } => (), | ~~~~~~ diff --git a/tests/ui/typeck/issue-87872-missing-inaccessible-field-pattern.stderr b/tests/ui/typeck/issue-87872-missing-inaccessible-field-pattern.stderr index 96ac481438f7a..b9bdf6f9a3990 100644 --- a/tests/ui/typeck/issue-87872-missing-inaccessible-field-pattern.stderr +++ b/tests/ui/typeck/issue-87872-missing-inaccessible-field-pattern.stderr @@ -10,6 +10,10 @@ LL | let foo::Foo { visible, .. } = foo::Foo::default(); | ~~~~~~~~~~~~~~~ help: if you don't care about this missing field, you can explicitly ignore it | +LL | let foo::Foo { visible: _, .. } = foo::Foo::default(); + | ~~~~~~~~~~~~~~~~~~ +help: or always ignore missing fields here + | LL | let foo::Foo { .. } = foo::Foo::default(); | ~~~~~~ From a645342720cbfd735325f8ccef7ffbcfe988cec1 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Mon, 28 Oct 2024 22:48:32 -0400 Subject: [PATCH 03/18] More test for non-exhaustive C-like enums in FFI Add a few more possibly false-positive tests for the `improper_ctypes` lint --- .../improper_ctypes/auxiliary/types.rs | 6 ++++++ .../improper_ctypes/extern_crate_improper.rs | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs index 4dc5932feab40..5d9a8cfcac1dd 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/auxiliary/types.rs @@ -38,3 +38,9 @@ pub enum NonExhaustiveCLikeEnum { Four = 4, Five = 5, } + +#[repr(C)] +pub struct NormalStructWithNonExhaustiveCLikeEnum { + one: u8, + two: NonExhaustiveCLikeEnum, +} diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs index c7f470fb787a7..858e3374eacfc 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs @@ -8,7 +8,7 @@ extern crate types; use types::{ NonExhaustiveCLikeEnum, NonExhaustiveEnum, NonExhaustiveVariants, - NormalStruct, TupleStruct, UnitStruct, + NormalStruct, TupleStruct, UnitStruct, NormalStructWithNonExhaustiveCLikeEnum }; extern "C" { @@ -27,6 +27,9 @@ extern "C" { // These should pass without remark, as they're C-compatible, despite being "non-exhaustive". extern "C" { pub fn non_exhaustive_c_compat_enum(_: NonExhaustiveCLikeEnum); + pub fn non_exhaustive_c_compat_enum_ret() -> *mut NonExhaustiveCLikeEnum; + pub fn struct_w_non_exhaustive_c_like_enum(_: NormalStructWithNonExhaustiveCLikeEnum); + pub fn struct_w_non_exhaustive_c_like_enum_ret() -> *mut NormalStructWithNonExhaustiveCLikeEnum; } fn main() {} From 981dc02eaf876a25b95581411e841ba664dc9e97 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 4 Nov 2024 15:41:32 +1100 Subject: [PATCH 04/18] Revert "Avoid nested replacement ranges" from #129346. It caused a test regression in the `cfg_eval.rs` crate. (The bugfix in #129346 was in a different commit; this commit was just a code simplification.) --- .../rustc_parse/src/parser/attr_wrapper.rs | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 8bd615e6d7913..c85d0bd05cbd6 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -136,8 +136,9 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { node_replacements.array_windows() { assert!( - node_range.0.end <= next_node_range.0.start, - "Node ranges should be disjoint: ({:?}, {:?}) ({:?}, {:?})", + node_range.0.end <= next_node_range.0.start + || node_range.0.end >= next_node_range.0.end, + "Node ranges should be disjoint or nested: ({:?}, {:?}) ({:?}, {:?})", node_range, tokens, next_node_range, @@ -145,8 +146,20 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { ); } - // Process the replace ranges. - for (node_range, target) in node_replacements.into_iter() { + // Process the replace ranges, starting from the highest start + // position and working our way back. If have tokens like: + // + // `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }` + // + // Then we will generate replace ranges for both + // the `#[cfg(FALSE)] field: bool` and the entire + // `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }` + // + // By starting processing from the replace range with the greatest + // start position, we ensure that any (outer) replace range which + // encloses another (inner) replace range will fully overwrite the + // inner range's replacement. + for (node_range, target) in node_replacements.into_iter().rev() { assert!( !node_range.0.is_empty(), "Cannot replace an empty node range: {:?}", @@ -383,9 +396,10 @@ impl<'a> Parser<'a> { // from `ParserRange` form to `NodeRange` form. We will perform the actual // replacement only when we convert the `LazyAttrTokenStream` to an // `AttrTokenStream`. - self.capture_state - .parser_replacements - .drain(parser_replacements_start..parser_replacements_end) + self.capture_state.parser_replacements + [parser_replacements_start..parser_replacements_end] + .iter() + .cloned() .chain(inner_attr_parser_replacements) .map(|(parser_range, data)| { (NodeRange::new(parser_range, collect_pos.start_pos), data) From e9161db5b55ee5398e10a6806cb62d67e725278c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 4 Nov 2024 14:28:35 +0100 Subject: [PATCH 05/18] Fix invalid coverage computation when `--output-format=json` is enabled --- src/librustdoc/clean/mod.rs | 4 ++-- src/librustdoc/core.rs | 7 +++++++ src/librustdoc/passes/calculate_doc_coverage.rs | 1 + src/librustdoc/passes/strip_hidden.rs | 2 +- src/librustdoc/passes/strip_priv_imports.rs | 2 +- src/librustdoc/passes/strip_private.rs | 2 +- src/librustdoc/visit_ast.rs | 2 +- 7 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c367eed53e07b..bd4704e8b28ed 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2907,7 +2907,7 @@ fn clean_extern_crate<'tcx>( None => false, } }) - && !cx.output_format.is_json(); + && !cx.is_json(); let krate_owner_def_id = krate.owner_id.def_id; if please_inline { @@ -3000,7 +3000,7 @@ fn clean_use_statement_inner<'tcx>( // forcefully don't inline if this is not public or if the // #[doc(no_inline)] attribute is present. // Don't inline doc(hidden) imports so they can be stripped at a later stage. - let mut denied = cx.output_format.is_json() + let mut denied = cx.is_json() || !(visibility.is_public() || (cx.render_options.document_private && is_visible_from_parent_mod)) || pub_underscore diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 0f7d4d3e8f318..274b61ae1d3c0 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -121,6 +121,13 @@ impl<'tcx> DocContext<'tcx> { _ => None, } } + + /// Returns `true` if the JSON output format is enabled for generating the crate content. + /// + /// If another option like `--show-coverage` is enabled, it will return false. + pub(crate) fn is_json(&self) -> bool { + self.output_format.is_json() && !self.show_coverage + } } /// Creates a new `DiagCtxt` that can be used to emit warnings and errors. diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index d27e737764dcf..9f9a093da8a38 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -132,6 +132,7 @@ impl<'a, 'b> CoverageCalculator<'a, 'b> { fn print_results(&self) { let output_format = self.ctx.output_format; + // In this case we want to ensure that the `OutputFormat` is JSON and NOT the `DocContext`. if output_format.is_json() { println!("{}", self.to_json()); return; diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index aba04283e59dc..2998289fd273a 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -23,7 +23,7 @@ pub(crate) const STRIP_HIDDEN: Pass = Pass { /// Strip items marked `#[doc(hidden)]` pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate { let mut retained = ItemIdSet::default(); - let is_json_output = cx.output_format.is_json() && !cx.show_coverage; + let is_json_output = cx.is_json(); // strip all #[doc(hidden)] items let krate = { diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs index 2e9f06bd0a30c..20659d5e8c69c 100644 --- a/src/librustdoc/passes/strip_priv_imports.rs +++ b/src/librustdoc/passes/strip_priv_imports.rs @@ -13,7 +13,7 @@ pub(crate) const STRIP_PRIV_IMPORTS: Pass = Pass { }; pub(crate) fn strip_priv_imports(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate { - let is_json_output = cx.output_format.is_json() && !cx.show_coverage; + let is_json_output = cx.is_json(); ImportStripper { tcx: cx.tcx, is_json_output, diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index 78f0ad277408b..916c2f0657e47 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -18,7 +18,7 @@ pub(crate) const STRIP_PRIVATE: Pass = Pass { pub(crate) fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate { // This stripper collects all *retained* nodes. let mut retained = ItemIdSet::default(); - let is_json_output = cx.output_format.is_json() && !cx.show_coverage; + let is_json_output = cx.is_json(); // strip all private items { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index f789aca73784d..00f5251596b60 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -235,7 +235,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { return false; } - if self.cx.output_format.is_json() { + if self.cx.is_json() { return false; } From 0eff07ee4ec22e7f83462b4b1a42dc04e9d5570b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 4 Nov 2024 14:46:04 +0100 Subject: [PATCH 06/18] Add UI regressions tests for rustdoc `--show-coverage` option --- tests/rustdoc-ui/show-coverage-json.rs | 13 +++++++++++++ tests/rustdoc-ui/show-coverage-json.stdout | 1 + tests/rustdoc-ui/show-coverage.rs | 13 +++++++++++++ tests/rustdoc-ui/show-coverage.stdout | 7 +++++++ 4 files changed, 34 insertions(+) create mode 100644 tests/rustdoc-ui/show-coverage-json.rs create mode 100644 tests/rustdoc-ui/show-coverage-json.stdout create mode 100644 tests/rustdoc-ui/show-coverage.rs create mode 100644 tests/rustdoc-ui/show-coverage.stdout diff --git a/tests/rustdoc-ui/show-coverage-json.rs b/tests/rustdoc-ui/show-coverage-json.rs new file mode 100644 index 0000000000000..3851e34fe3599 --- /dev/null +++ b/tests/rustdoc-ui/show-coverage-json.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -Z unstable-options --show-coverage --output-format=json +//@ check-pass + +mod bar { + /// a + /// + /// ``` + /// let x = 0; + /// ``` + pub struct Foo; +} + +pub use bar::Foo; diff --git a/tests/rustdoc-ui/show-coverage-json.stdout b/tests/rustdoc-ui/show-coverage-json.stdout new file mode 100644 index 0000000000000..ed5b5a60212eb --- /dev/null +++ b/tests/rustdoc-ui/show-coverage-json.stdout @@ -0,0 +1 @@ +{"$DIR/show-coverage-json.rs":{"total":2,"with_docs":1,"total_examples":2,"with_examples":1}} diff --git a/tests/rustdoc-ui/show-coverage.rs b/tests/rustdoc-ui/show-coverage.rs new file mode 100644 index 0000000000000..00bb1606a82cb --- /dev/null +++ b/tests/rustdoc-ui/show-coverage.rs @@ -0,0 +1,13 @@ +//@ compile-flags: -Z unstable-options --show-coverage +//@ check-pass + +mod bar { + /// a + /// + /// ``` + /// let x = 0; + /// ``` + pub struct Foo; +} + +pub use bar::Foo; diff --git a/tests/rustdoc-ui/show-coverage.stdout b/tests/rustdoc-ui/show-coverage.stdout new file mode 100644 index 0000000000000..b3b7679771f22 --- /dev/null +++ b/tests/rustdoc-ui/show-coverage.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...ests/rustdoc-ui/show-coverage.rs | 1 | 50.0% | 1 | 50.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 1 | 50.0% | 1 | 50.0% | ++-------------------------------------+------------+------------+------------+------------+ From 5dfbc0383d6e7ad27f0bdae5542109dafc9cd4f1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 4 Nov 2024 17:15:28 +0100 Subject: [PATCH 07/18] Rename `DocContext::is_json` into `DocContext::is_json_output` --- src/librustdoc/clean/mod.rs | 4 ++-- src/librustdoc/core.rs | 4 ++-- src/librustdoc/passes/strip_hidden.rs | 2 +- src/librustdoc/passes/strip_priv_imports.rs | 2 +- src/librustdoc/passes/strip_private.rs | 2 +- src/librustdoc/visit_ast.rs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index bd4704e8b28ed..992be651dbe08 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2907,7 +2907,7 @@ fn clean_extern_crate<'tcx>( None => false, } }) - && !cx.is_json(); + && !cx.is_json_output(); let krate_owner_def_id = krate.owner_id.def_id; if please_inline { @@ -3000,7 +3000,7 @@ fn clean_use_statement_inner<'tcx>( // forcefully don't inline if this is not public or if the // #[doc(no_inline)] attribute is present. // Don't inline doc(hidden) imports so they can be stripped at a later stage. - let mut denied = cx.is_json() + let mut denied = cx.is_json_output() || !(visibility.is_public() || (cx.render_options.document_private && is_visible_from_parent_mod)) || pub_underscore diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 274b61ae1d3c0..7ba3cfb66bd23 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -124,8 +124,8 @@ impl<'tcx> DocContext<'tcx> { /// Returns `true` if the JSON output format is enabled for generating the crate content. /// - /// If another option like `--show-coverage` is enabled, it will return false. - pub(crate) fn is_json(&self) -> bool { + /// If another option like `--show-coverage` is enabled, it will return `false`. + pub(crate) fn is_json_output(&self) -> bool { self.output_format.is_json() && !self.show_coverage } } diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 2998289fd273a..4ef5f7f20a917 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -23,7 +23,7 @@ pub(crate) const STRIP_HIDDEN: Pass = Pass { /// Strip items marked `#[doc(hidden)]` pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate { let mut retained = ItemIdSet::default(); - let is_json_output = cx.is_json(); + let is_json_output = cx.is_json_output(); // strip all #[doc(hidden)] items let krate = { diff --git a/src/librustdoc/passes/strip_priv_imports.rs b/src/librustdoc/passes/strip_priv_imports.rs index 20659d5e8c69c..b9b2431f06f2b 100644 --- a/src/librustdoc/passes/strip_priv_imports.rs +++ b/src/librustdoc/passes/strip_priv_imports.rs @@ -13,7 +13,7 @@ pub(crate) const STRIP_PRIV_IMPORTS: Pass = Pass { }; pub(crate) fn strip_priv_imports(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate { - let is_json_output = cx.is_json(); + let is_json_output = cx.is_json_output(); ImportStripper { tcx: cx.tcx, is_json_output, diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index 916c2f0657e47..1bd8a7838ec08 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -18,7 +18,7 @@ pub(crate) const STRIP_PRIVATE: Pass = Pass { pub(crate) fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate { // This stripper collects all *retained* nodes. let mut retained = ItemIdSet::default(); - let is_json_output = cx.is_json(); + let is_json_output = cx.is_json_output(); // strip all private items { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 00f5251596b60..31c33fbf49737 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -235,7 +235,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { return false; } - if self.cx.is_json() { + if self.cx.is_json_output() { return false; } From c88ba28d9a0261f448471255bd913e673858abaa Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Mon, 4 Nov 2024 18:08:30 +0100 Subject: [PATCH 08/18] document `type_implements_trait` --- compiler/rustc_trait_selection/src/infer.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index bacb3b1b1b861..e91574fa1aff2 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -60,6 +60,18 @@ impl<'tcx> InferCtxt<'tcx> { /// /// Invokes `evaluate_obligation`, so in the event that evaluating /// `Ty: Trait` causes overflow, EvaluatedToAmbigStackDependent will be returned. + /// + /// `type_implements_trait` is a convenience function for simple cases like + /// + /// ```ignore (illustrative) + /// let copy_trait = infcx.tcx.require_lang_item(LangItem::Copy, span); + /// let implements_copy = infcx.type_implements_trait(copy_trait, [ty], param_env) + /// .must_apply_modulo_regions(); + /// ``` + /// + /// In most cases you should instead create an [Obligation](traits::Obligation) + /// and check whether it holds, because it properly handles higher ranked traits + /// and it is more convenient and safer when your `params` are inside a `Binder`. #[instrument(level = "debug", skip(self, params), ret)] fn type_implements_trait( &self, From 75c943ed2d9bdddac892fd2a1825954d65d6b7ef Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 4 Nov 2024 12:01:29 -0500 Subject: [PATCH 09/18] Update books --- src/doc/edition-guide | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- src/doc/rustc-dev-guide | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/edition-guide b/src/doc/edition-guide index 1f07c242f8162..2d482e203eb6d 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit 1f07c242f8162a711a5ac5a4ea8fa7ec884ee7a9 +Subproject commit 2d482e203eb6d6e353814cf1415c5f94e590b9e0 diff --git a/src/doc/reference b/src/doc/reference index 23ce619966541..da0f6dad76767 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 23ce619966541bf2c80d45fdfeecf3393e360a13 +Subproject commit da0f6dad767670da0e8cd5af8a7090db3272f626 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 8bede1b919a81..9db78608b17d5 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 8bede1b919a81ab7d0c961f6bbf68d3efa297bd2 +Subproject commit 9db78608b17d5f4a6c033b8a3038466b87d63206 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 59d94ea75a0b1..6a5accdaf1025 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 59d94ea75a0b157e148af14c73c2dd60efb7b60a +Subproject commit 6a5accdaf10255882b1e6c59dfe5f1c79ac95484 From 4872b6bcbd8f2800b370b7e05b1ca1e18054a166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20S=C3=A1nchez=20Mu=C3=B1oz?= Date: Mon, 4 Nov 2024 19:08:28 +0100 Subject: [PATCH 10/18] Improve example of `impl Pattern for &[char]` The previous version used `['l', 'l']` as pattern, which would suggest that it matches the `ll` of `Hello world` as a whole. --- library/core/src/str/pattern.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index 665c9fc67d01e..52e2364893eb1 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -886,8 +886,8 @@ impl<'a, 'b> DoubleEndedSearcher<'a> for CharSliceSearcher<'a, 'b> {} /// # Examples /// /// ``` -/// assert_eq!("Hello world".find(&['l', 'l'] as &[_]), Some(2)); -/// assert_eq!("Hello world".find(&['l', 'l'][..]), Some(2)); +/// assert_eq!("Hello world".find(&['o', 'l'][..]), Some(2)); +/// assert_eq!("Hello world".find(&['h', 'w'][..]), Some(6)); /// ``` impl<'b> Pattern for &'b [char] { pattern_methods!('a, CharSliceSearcher<'a, 'b>, MultiCharEqPattern, CharSliceSearcher); From 107b4fdba21d437e7e36b2a62bc803d6a8f31021 Mon Sep 17 00:00:00 2001 From: NotWearingPants <26556598+NotWearingPants@users.noreply.github.com> Date: Mon, 4 Nov 2024 20:42:21 +0200 Subject: [PATCH 11/18] docs: fix grammar in doc comment at unix/process.rs --- library/std/src/os/unix/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index ef5adaf229088..7c3fa7d6507e7 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -143,7 +143,7 @@ pub trait CommandExt: Sealed { /// /// This function, unlike `spawn`, will **not** `fork` the process to create /// a new child. Like spawn, however, the default behavior for the stdio - /// descriptors will be to inherited from the current process. + /// descriptors will be to inherit them from the current process. /// /// # Notes /// From f4b72dcff01f03b0479b737c007c49c97039d3a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Mon, 4 Nov 2024 14:55:07 +0100 Subject: [PATCH 12/18] Move two attribute lints to be early pass (post expansion) --- .../src/attrs/allow_attributes.rs | 4 +- .../attrs/allow_attributes_without_reason.rs | 4 +- .../attrs/blanket_clippy_restriction_lints.rs | 6 +- .../src/attrs/deprecated_semver.rs | 4 +- .../src/attrs/duplicated_attributes.rs | 8 +- .../src/attrs/mixed_attributes_style.rs | 6 +- .../clippy/clippy_lints/src/attrs/mod.rs | 128 +++++++++++------- .../src/attrs/should_panic_without_expect.rs | 6 +- .../src/attrs/useless_attribute.rs | 8 +- src/tools/clippy/clippy_lints/src/lib.rs | 2 + .../clippy_utils/src/check_proc_macro.rs | 5 +- .../clippy/tests/ui/allow_attributes.stderr | 10 +- .../ui/allow_attributes_without_reason.stderr | 11 +- src/tools/clippy/tests/ui/attrs.stderr | 18 +-- .../blanket_clippy_restriction_lints.stderr | 14 +- 15 files changed, 122 insertions(+), 112 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs index a5a7b9f74a693..1879391ec290b 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes.rs @@ -3,11 +3,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use rustc_ast::{AttrStyle, Attribute}; use rustc_errors::Applicability; -use rustc_lint::{LateContext, LintContext}; +use rustc_lint::{EarlyContext, LintContext}; use rustc_middle::lint::in_external_macro; // Separate each crate's features. -pub fn check<'cx>(cx: &LateContext<'cx>, attr: &'cx Attribute) { +pub fn check<'cx>(cx: &EarlyContext<'cx>, attr: &'cx Attribute) { if !in_external_macro(cx.sess(), attr.span) && let AttrStyle::Outer = attr.style && let Some(ident) = attr.ident() diff --git a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs index 5d4e864b9b0b5..788377fe83ce4 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/allow_attributes_without_reason.rs @@ -2,12 +2,12 @@ use super::{ALLOW_ATTRIBUTES_WITHOUT_REASON, Attribute}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use rustc_ast::{MetaItemInner, MetaItemKind}; -use rustc_lint::{LateContext, LintContext}; +use rustc_lint::{EarlyContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_span::sym; use rustc_span::symbol::Symbol; -pub(super) fn check<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[MetaItemInner], attr: &'cx Attribute) { +pub(super) fn check<'cx>(cx: &EarlyContext<'cx>, name: Symbol, items: &[MetaItemInner], attr: &'cx Attribute) { // Check if the reason is present if let Some(item) = items.last().and_then(MetaItemInner::meta_item) && let MetaItemKind::NameValue(_) = &item.kind diff --git a/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs b/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs index 0baf889faa076..fecf316640636 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs @@ -2,11 +2,11 @@ use super::BLANKET_CLIPPY_RESTRICTION_LINTS; use super::utils::extract_clippy_lint; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use rustc_ast::MetaItemInner; -use rustc_lint::{LateContext, Level, LintContext}; +use rustc_lint::{EarlyContext, Level, LintContext}; use rustc_span::symbol::Symbol; use rustc_span::{DUMMY_SP, sym}; -pub(super) fn check(cx: &LateContext<'_>, name: Symbol, items: &[MetaItemInner]) { +pub(super) fn check(cx: &EarlyContext<'_>, name: Symbol, items: &[MetaItemInner]) { for lint in items { if let Some(lint_name) = extract_clippy_lint(lint) { if lint_name.as_str() == "restriction" && name != sym::allow { @@ -23,7 +23,7 @@ pub(super) fn check(cx: &LateContext<'_>, name: Symbol, items: &[MetaItemInner]) } } -pub(super) fn check_command_line(cx: &LateContext<'_>) { +pub(super) fn check_command_line(cx: &EarlyContext<'_>) { for (name, level) in &cx.sess().opts.lint_opts { if name == "clippy::restriction" && *level > Level::Allow { span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs b/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs index 1898c145c76a9..d3153ec6613b5 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs @@ -1,11 +1,11 @@ use super::DEPRECATED_SEMVER; use clippy_utils::diagnostics::span_lint; use rustc_ast::{LitKind, MetaItemLit}; -use rustc_lint::LateContext; +use rustc_lint::EarlyContext; use rustc_span::Span; use semver::Version; -pub(super) fn check(cx: &LateContext<'_>, span: Span, lit: &MetaItemLit) { +pub(super) fn check(cx: &EarlyContext<'_>, span: Span, lit: &MetaItemLit) { if let LitKind::Str(is, _) = lit.kind { if is.as_str() == "TBD" || Version::parse(is.as_str()).is_ok() { return; diff --git a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs index 55f8e1072db74..2ddbc7a6a76dc 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs @@ -2,12 +2,12 @@ use super::DUPLICATED_ATTRIBUTES; use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::{Attribute, MetaItem}; use rustc_data_structures::fx::FxHashMap; -use rustc_lint::LateContext; +use rustc_lint::EarlyContext; use rustc_span::{Span, sym}; use std::collections::hash_map::Entry; fn emit_if_duplicated( - cx: &LateContext<'_>, + cx: &EarlyContext<'_>, attr: &MetaItem, attr_paths: &mut FxHashMap, complete_path: String, @@ -26,7 +26,7 @@ fn emit_if_duplicated( } fn check_duplicated_attr( - cx: &LateContext<'_>, + cx: &EarlyContext<'_>, attr: &MetaItem, attr_paths: &mut FxHashMap, parent: &mut Vec, @@ -65,7 +65,7 @@ fn check_duplicated_attr( } } -pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) { +pub fn check(cx: &EarlyContext<'_>, attrs: &[Attribute]) { let mut attr_paths = FxHashMap::default(); for attr in attrs { diff --git a/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs b/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs index 5d2ea36b366c1..32c28c09c3602 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mixed_attributes_style.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint; use rustc_ast::{AttrKind, AttrStyle, Attribute}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; -use rustc_lint::{LateContext, LintContext}; +use rustc_lint::{EarlyContext, LintContext}; use rustc_span::source_map::SourceMap; use rustc_span::{SourceFile, Span, Symbol}; @@ -32,7 +32,7 @@ impl From<&AttrKind> for SimpleAttrKind { } } -pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute]) { +pub(super) fn check(cx: &EarlyContext<'_>, item_span: Span, attrs: &[Attribute]) { let mut inner_attr_kind: FxHashSet = FxHashSet::default(); let mut outer_attr_kind: FxHashSet = FxHashSet::default(); @@ -64,7 +64,7 @@ pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute]) } } -fn lint_mixed_attrs(cx: &LateContext<'_>, attrs: &[Attribute]) { +fn lint_mixed_attrs(cx: &EarlyContext<'_>, attrs: &[Attribute]) { let mut attrs_iter = attrs.iter().filter(|attr| !attr.span.from_expansion()); let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.last()) { first.span.with_hi(last.span.hi()) diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs index 1a34ca99fc2b9..684756ce87f1d 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs @@ -14,8 +14,8 @@ mod utils; use clippy_config::Conf; use clippy_config::msrvs::{self, Msrv}; -use rustc_ast::{Attribute, MetaItemInner, MetaItemKind}; -use rustc_hir::{ImplItem, Item, ItemKind, TraitItem}; +use rustc_ast::{Attribute, MetaItemInner, MetaItemKind, self as ast}; +use rustc_hir::{ImplItem, Item, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::sym; @@ -414,15 +414,7 @@ pub struct Attributes { } impl_lint_pass!(Attributes => [ - ALLOW_ATTRIBUTES, - ALLOW_ATTRIBUTES_WITHOUT_REASON, INLINE_ALWAYS, - DEPRECATED_SEMVER, - USELESS_ATTRIBUTE, - BLANKET_CLIPPY_RESTRICTION_LINTS, - SHOULD_PANIC_WITHOUT_EXPECT, - MIXED_ATTRIBUTES_STYLE, - DUPLICATED_ATTRIBUTES, ]); impl Attributes { @@ -434,53 +426,11 @@ impl Attributes { } impl<'tcx> LateLintPass<'tcx> for Attributes { - fn check_crate(&mut self, cx: &LateContext<'tcx>) { - blanket_clippy_restriction_lints::check_command_line(cx); - duplicated_attributes::check(cx, cx.tcx.hir().krate_attrs()); - } - - fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) { - if let Some(items) = &attr.meta_item_list() { - if let Some(ident) = attr.ident() { - if is_lint_level(ident.name, attr.id) { - blanket_clippy_restriction_lints::check(cx, ident.name, items); - } - if matches!(ident.name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { - allow_attributes::check(cx, attr); - } - if matches!(ident.name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) - { - allow_attributes_without_reason::check(cx, ident.name, items, attr); - } - if items.is_empty() || !attr.has_name(sym::deprecated) { - return; - } - for item in items { - if let MetaItemInner::MetaItem(mi) = &item - && let MetaItemKind::NameValue(lit) = &mi.kind - && mi.has_name(sym::since) - { - deprecated_semver::check(cx, item.span(), lit); - } - } - } - } - if attr.has_name(sym::should_panic) { - should_panic_without_expect::check(cx, attr); - } - } - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { let attrs = cx.tcx.hir().attrs(item.hir_id()); if is_relevant_item(cx, item) { inline_always::check(cx, item.span, item.ident.name, attrs); } - match item.kind { - ItemKind::ExternCrate(..) | ItemKind::Use(..) => useless_attribute::check(cx, item, attrs), - _ => {}, - } - mixed_attributes_style::check(cx, item.span, attrs); - duplicated_attributes::check(cx, attrs); } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { @@ -526,3 +476,77 @@ impl EarlyLintPass for EarlyAttributes { extract_msrv_attr!(EarlyContext); } + +pub struct PostExpansionEarlyAttributes { + msrv: Msrv, +} + +impl PostExpansionEarlyAttributes { + pub fn new(conf: &'static Conf) -> Self { + Self { + msrv: conf.msrv.clone(), + } + } +} + +impl_lint_pass!(PostExpansionEarlyAttributes => [ + ALLOW_ATTRIBUTES, + ALLOW_ATTRIBUTES_WITHOUT_REASON, + DEPRECATED_SEMVER, + USELESS_ATTRIBUTE, + BLANKET_CLIPPY_RESTRICTION_LINTS, + SHOULD_PANIC_WITHOUT_EXPECT, + MIXED_ATTRIBUTES_STYLE, + DUPLICATED_ATTRIBUTES, +]); + +impl EarlyLintPass for PostExpansionEarlyAttributes { + fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) { + blanket_clippy_restriction_lints::check_command_line(cx); + duplicated_attributes::check(cx, &krate.attrs); + } + + fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { + if let Some(items) = &attr.meta_item_list() { + if let Some(ident) = attr.ident() { + if matches!(ident.name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) { + allow_attributes::check(cx, attr); + } + if matches!(ident.name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) + { + allow_attributes_without_reason::check(cx, ident.name, items, attr); + } + if is_lint_level(ident.name, attr.id) { + blanket_clippy_restriction_lints::check(cx, ident.name, items); + } + if items.is_empty() || !attr.has_name(sym::deprecated) { + return; + } + for item in items { + if let MetaItemInner::MetaItem(mi) = &item + && let MetaItemKind::NameValue(lit) = &mi.kind + && mi.has_name(sym::since) + { + deprecated_semver::check(cx, item.span(), lit); + } + } + } + } + + if attr.has_name(sym::should_panic) { + should_panic_without_expect::check(cx, attr); + } + } + + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &'_ ast::Item) { + match item.kind { + ast::ItemKind::ExternCrate(..) | ast::ItemKind::Use(..) => useless_attribute::check(cx, item, &item.attrs), + _ => {}, + } + + mixed_attributes_style::check(cx, item.span, &item.attrs); + duplicated_attributes::check(cx, &item.attrs); + } + + extract_msrv_attr!(EarlyContext); +} diff --git a/src/tools/clippy/clippy_lints/src/attrs/should_panic_without_expect.rs b/src/tools/clippy/clippy_lints/src/attrs/should_panic_without_expect.rs index 2d45cbbf621f4..fadd527288028 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/should_panic_without_expect.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/should_panic_without_expect.rs @@ -4,12 +4,12 @@ use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::TokenTree; use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind}; use rustc_errors::Applicability; -use rustc_lint::LateContext; +use rustc_lint::EarlyContext; use rustc_span::sym; -pub(super) fn check(cx: &LateContext<'_>, attr: &Attribute) { +pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) { if let AttrKind::Normal(normal_attr) = &attr.kind { - if let AttrArgs::Eq(_, AttrArgsEq::Hir(_)) = &normal_attr.item.args { + if let AttrArgs::Eq(_, AttrArgsEq::Ast(_)) = &normal_attr.item.args { // `#[should_panic = ".."]` found, good return; } diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs index 72e6ce59d5980..92b9f9cba5251 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs @@ -1,15 +1,15 @@ use super::utils::{extract_clippy_lint, is_lint_level, is_word}; -use super::{Attribute, USELESS_ATTRIBUTE}; +use super::USELESS_ATTRIBUTE; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{SpanRangeExt, first_line_of_span}; use rustc_ast::MetaItemInner; use rustc_errors::Applicability; -use rustc_hir::{Item, ItemKind}; -use rustc_lint::{LateContext, LintContext}; +use rustc_ast::{Item, ItemKind, Attribute}; +use rustc_lint::{EarlyContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_span::sym; -pub(super) fn check(cx: &LateContext<'_>, item: &Item<'_>, attrs: &[Attribute]) { +pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { let skip_unused_imports = attrs.iter().any(|attr| attr.has_name(sym::macro_use)); for attr in attrs { diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 14110539709d6..3fd07ced0e4ae 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -412,6 +412,8 @@ use rustc_lint::{Lint, LintId}; pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { // NOTE: Do not add any more pre-expansion passes. These should be removed eventually. store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes::new(conf))); + + store.register_early_pass(move || Box::new(attrs::PostExpansionEarlyAttributes::new(conf))); } #[derive(Default)] diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index bfb3a76ad251c..c5e2c8c09a277 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -21,7 +21,7 @@ use rustc_hir::{ ImplItem, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, QPath, Safety, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource, }; -use rustc_lint::{LateContext, LintContext}; +use rustc_lint::{LateContext, LintContext, EarlyContext}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::symbol::{Ident, kw}; @@ -429,11 +429,12 @@ impl_with_search_pat!((_cx: LateContext<'tcx>, self: ImplItem<'_>) => impl_item_ impl_with_search_pat!((_cx: LateContext<'tcx>, self: FieldDef<'_>) => field_def_search_pat(self)); impl_with_search_pat!((_cx: LateContext<'tcx>, self: Variant<'_>) => variant_search_pat(self)); impl_with_search_pat!((_cx: LateContext<'tcx>, self: Ty<'_>) => ty_search_pat(self)); -impl_with_search_pat!((_cx: LateContext<'tcx>, self: Attribute) => attr_search_pat(self)); impl_with_search_pat!((_cx: LateContext<'tcx>, self: Ident) => ident_search_pat(*self)); impl_with_search_pat!((_cx: LateContext<'tcx>, self: Lit) => lit_search_pat(&self.node)); impl_with_search_pat!((_cx: LateContext<'tcx>, self: Path<'_>) => path_search_pat(self)); +impl_with_search_pat!((_cx: EarlyContext<'tcx>, self: Attribute) => attr_search_pat(self)); + impl<'cx> WithSearchPat<'cx> for (&FnKind<'cx>, &Body<'cx>, HirId, Span) { type Context = LateContext<'cx>; diff --git a/src/tools/clippy/tests/ui/allow_attributes.stderr b/src/tools/clippy/tests/ui/allow_attributes.stderr index 10dac0bc80808..023b4d7e40439 100644 --- a/src/tools/clippy/tests/ui/allow_attributes.stderr +++ b/src/tools/clippy/tests/ui/allow_attributes.stderr @@ -19,13 +19,5 @@ error: #[allow] attribute found LL | #[allow(unused)] | ^^^^^ help: replace it with: `expect` -error: #[allow] attribute found - --> tests/ui/allow_attributes.rs:52:7 - | -LL | #[allow(unused)] - | ^^^^^ help: replace it with: `expect` - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr b/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr index 86d7845df0416..9c1ac5af91b06 100644 --- a/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr +++ b/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr @@ -43,14 +43,5 @@ LL | #[allow(unused)] | = help: try adding a reason at the end with `, reason = ".."` -error: `allow` attribute without specifying a reason - --> tests/ui/allow_attributes_without_reason.rs:46:5 - | -LL | #[allow(unused)] - | ^^^^^^^^^^^^^^^^ - | - = help: try adding a reason at the end with `, reason = ".."` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/attrs.stderr b/src/tools/clippy/tests/ui/attrs.stderr index cd409fc8701b6..a7fdceaba6f39 100644 --- a/src/tools/clippy/tests/ui/attrs.stderr +++ b/src/tools/clippy/tests/ui/attrs.stderr @@ -1,12 +1,3 @@ -error: you have declared `#[inline(always)]` on `test_attr_lint`. This is usually a bad idea - --> tests/ui/attrs.rs:5:1 - | -LL | #[inline(always)] - | ^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::inline-always` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::inline_always)]` - error: the since field must contain a semver-compliant version --> tests/ui/attrs.rs:27:14 | @@ -22,5 +13,14 @@ error: the since field must contain a semver-compliant version LL | #[deprecated(since = "1")] | ^^^^^^^^^^^ +error: you have declared `#[inline(always)]` on `test_attr_lint`. This is usually a bad idea + --> tests/ui/attrs.rs:5:1 + | +LL | #[inline(always)] + | ^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::inline-always` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::inline_always)]` + error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr index d410f25b2c274..1bad259b09a36 100644 --- a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr +++ b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr @@ -1,3 +1,10 @@ +error: `clippy::restriction` is not meant to be enabled as a group + | + = note: because of the command line `--warn clippy::restriction` + = help: enable the restriction lints you need individually + = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::blanket_clippy_restriction_lints)]` + error: `clippy::restriction` is not meant to be enabled as a group --> tests/ui/blanket_clippy_restriction_lints.rs:6:9 | @@ -5,8 +12,6 @@ LL | #![warn(clippy::restriction)] | ^^^^^^^^^^^^^^^^^^^ | = help: enable the restriction lints you need individually - = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::blanket_clippy_restriction_lints)]` error: `clippy::restriction` is not meant to be enabled as a group --> tests/ui/blanket_clippy_restriction_lints.rs:8:9 @@ -24,10 +29,5 @@ LL | #![forbid(clippy::restriction)] | = help: enable the restriction lints you need individually -error: `clippy::restriction` is not meant to be enabled as a group - | - = note: because of the command line `--warn clippy::restriction` - = help: enable the restriction lints you need individually - error: aborting due to 4 previous errors From 7934f26613980e2dfed24551e816601b8a74879b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Nov 2024 22:09:07 +0100 Subject: [PATCH 13/18] convert all const-callable intrinsics into the new form (without extern block) --- library/core/src/intrinsics.rs | 2080 +++++++++++++++++--------------- 1 file changed, 1111 insertions(+), 969 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index fc09da7bcbc65..55746a8b5856c 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -936,21 +936,31 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn abort() -> !; - /// Informs the optimizer that this point in the code is not reachable, - /// enabling further optimizations. - /// - /// N.B., this is very different from the `unreachable!()` macro: Unlike the - /// macro, which panics when it is executed, it is *undefined behavior* to - /// reach code marked with this function. - /// - /// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`]. - #[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0") - )] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] + /// Executes a breakpoint trap, for inspection by a debugger. + /// + /// This intrinsic does not have a stable counterpart. #[rustc_nounwind] - pub fn unreachable() -> !; + pub fn breakpoint(); +} + +/// Informs the optimizer that this point in the code is not reachable, +/// enabling further optimizations. +/// +/// N.B., this is very different from the `unreachable!()` macro: Unlike the +/// macro, which panics when it is executed, it is *undefined behavior* to +/// reach code marked with this function. +/// +/// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`]. +#[cfg_attr( + bootstrap, + rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0") +)] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unreachable() -> ! { + unreachable!() } /// Informs the optimizer that a condition is always true. @@ -1044,437 +1054,465 @@ pub fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { if b { true_val } else { false_val } } -extern "rust-intrinsic" { - /// Executes a breakpoint trap, for inspection by a debugger. - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_nounwind] - pub fn breakpoint(); +/// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited: +/// This will statically either panic, or do nothing. +/// +/// This intrinsic does not have a stable counterpart. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type", since = "1.59.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn assert_inhabited() { + unreachable!() +} - /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited: - /// This will statically either panic, or do nothing. - /// - /// This intrinsic does not have a stable counterpart. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type", since = "1.59.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn assert_inhabited(); +/// A guard for unsafe functions that cannot ever be executed if `T` does not permit +/// zero-initialization: This will statically either panic, or do nothing. +/// +/// This intrinsic does not have a stable counterpart. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn assert_zero_valid() { + unreachable!() +} - /// A guard for unsafe functions that cannot ever be executed if `T` does not permit - /// zero-initialization: This will statically either panic, or do nothing. - /// - /// This intrinsic does not have a stable counterpart. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn assert_zero_valid(); +/// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing. +/// +/// This intrinsic does not have a stable counterpart. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn assert_mem_uninitialized_valid() { + unreachable!() +} - /// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing. - /// - /// This intrinsic does not have a stable counterpart. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn assert_mem_uninitialized_valid(); +/// Gets a reference to a static `Location` indicating where it was called. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// Consider using [`core::panic::Location::caller`] instead. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_caller_location", since = "1.79.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn caller_location() -> &'static crate::panic::Location<'static> { + unreachable!() +} - /// Gets a reference to a static `Location` indicating where it was called. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// Consider using [`core::panic::Location::caller`] instead. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_caller_location", since = "1.79.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn caller_location() -> &'static crate::panic::Location<'static>; +/// Moves a value out of scope without running drop glue. +/// +/// This exists solely for [`crate::mem::forget_unsized`]; normal `forget` uses +/// `ManuallyDrop` instead. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn forget(_: T) { + unreachable!() +} - /// Moves a value out of scope without running drop glue. - /// - /// This exists solely for [`crate::mem::forget_unsized`]; normal `forget` uses - /// `ManuallyDrop` instead. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn forget(_: T); - - /// Reinterprets the bits of a value of one type as another type. - /// - /// Both types must have the same size. Compilation will fail if this is not guaranteed. - /// - /// `transmute` is semantically equivalent to a bitwise move of one type - /// into another. It copies the bits from the source value into the - /// destination value, then forgets the original. Note that source and destination - /// are passed by-value, which means if `Src` or `Dst` contain padding, that padding - /// is *not* guaranteed to be preserved by `transmute`. - /// - /// Both the argument and the result must be [valid](../../nomicon/what-unsafe-does.html) at - /// their given type. Violating this condition leads to [undefined behavior][ub]. The compiler - /// will generate code *assuming that you, the programmer, ensure that there will never be - /// undefined behavior*. It is therefore your responsibility to guarantee that every value - /// passed to `transmute` is valid at both types `Src` and `Dst`. Failing to uphold this condition - /// may lead to unexpected and unstable compilation results. This makes `transmute` **incredibly - /// unsafe**. `transmute` should be the absolute last resort. - /// - /// Because `transmute` is a by-value operation, alignment of the *transmuted values - /// themselves* is not a concern. As with any other function, the compiler already ensures - /// both `Src` and `Dst` are properly aligned. However, when transmuting values that *point - /// elsewhere* (such as pointers, references, boxes…), the caller has to ensure proper - /// alignment of the pointed-to values. - /// - /// The [nomicon](../../nomicon/transmutes.html) has additional documentation. - /// - /// [ub]: ../../reference/behavior-considered-undefined.html - /// - /// # Transmutation between pointers and integers - /// - /// Special care has to be taken when transmuting between pointers and integers, e.g. - /// transmuting between `*const ()` and `usize`. - /// - /// Transmuting *pointers to integers* in a `const` context is [undefined behavior][ub], unless - /// the pointer was originally created *from* an integer. (That includes this function - /// specifically, integer-to-pointer casts, and helpers like [`dangling`][crate::ptr::dangling], - /// but also semantically-equivalent conversions such as punning through `repr(C)` union - /// fields.) Any attempt to use the resulting value for integer operations will abort - /// const-evaluation. (And even outside `const`, such transmutation is touching on many - /// unspecified aspects of the Rust memory model and should be avoided. See below for - /// alternatives.) - /// - /// Transmuting *integers to pointers* is a largely unspecified operation. It is likely *not* - /// equivalent to an `as` cast. Doing non-zero-sized memory accesses with a pointer constructed - /// this way is currently considered undefined behavior. - /// - /// All this also applies when the integer is nested inside an array, tuple, struct, or enum. - /// However, `MaybeUninit` is not considered an integer type for the purpose of this - /// section. Transmuting `*const ()` to `MaybeUninit` is fine---but then calling - /// `assume_init()` on that result is considered as completing the pointer-to-integer transmute - /// and thus runs into the issues discussed above. - /// - /// In particular, doing a pointer-to-integer-to-pointer roundtrip via `transmute` is *not* a - /// lossless process. If you want to round-trip a pointer through an integer in a way that you - /// can get back the original pointer, you need to use `as` casts, or replace the integer type - /// by `MaybeUninit<$int>` (and never call `assume_init()`). If you are looking for a way to - /// store data of arbitrary type, also use `MaybeUninit` (that will also handle uninitialized - /// memory due to padding). If you specifically need to store something that is "either an - /// integer or a pointer", use `*mut ()`: integers can be converted to pointers and back without - /// any loss (via `as` casts or via `transmute`). - /// - /// # Examples - /// - /// There are a few things that `transmute` is really useful for. - /// - /// Turning a pointer into a function pointer. This is *not* portable to - /// machines where function pointers and data pointers have different sizes. - /// - /// ``` - /// fn foo() -> i32 { - /// 0 - /// } - /// // 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. - /// let pointer = foo as *const (); - /// let function = unsafe { - /// std::mem::transmute::<*const (), fn() -> i32>(pointer) - /// }; - /// assert_eq!(function(), 0); - /// ``` - /// - /// Extending a lifetime, or shortening an invariant lifetime. This is - /// advanced, very unsafe Rust! - /// - /// ``` - /// struct R<'a>(&'a i32); - /// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { - /// std::mem::transmute::, R<'static>>(r) - /// } - /// - /// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) - /// -> &'b mut R<'c> { - /// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r) - /// } - /// ``` - /// - /// # Alternatives - /// - /// Don't despair: many uses of `transmute` can be achieved through other means. - /// Below are common applications of `transmute` which can be replaced with safer - /// constructs. - /// - /// Turning raw bytes (`[u8; SZ]`) into `u32`, `f64`, etc.: - /// - /// ``` - /// let raw_bytes = [0x78, 0x56, 0x34, 0x12]; - /// - /// let num = unsafe { - /// std::mem::transmute::<[u8; 4], u32>(raw_bytes) - /// }; - /// - /// // use `u32::from_ne_bytes` instead - /// let num = u32::from_ne_bytes(raw_bytes); - /// // or use `u32::from_le_bytes` or `u32::from_be_bytes` to specify the endianness - /// let num = u32::from_le_bytes(raw_bytes); - /// assert_eq!(num, 0x12345678); - /// let num = u32::from_be_bytes(raw_bytes); - /// assert_eq!(num, 0x78563412); - /// ``` - /// - /// Turning a pointer into a `usize`: - /// - /// ```no_run - /// let ptr = &0; - /// let ptr_num_transmute = unsafe { - /// std::mem::transmute::<&i32, usize>(ptr) - /// }; - /// - /// // Use an `as` cast instead - /// let ptr_num_cast = ptr as *const i32 as usize; - /// ``` - /// - /// Note that using `transmute` to turn a pointer to a `usize` is (as noted above) [undefined - /// behavior][ub] in `const` contexts. Also outside of consts, this operation might not behave - /// as expected -- this is touching on many unspecified aspects of the Rust memory model. - /// Depending on what the code is doing, the following alternatives are preferable to - /// pointer-to-integer transmutation: - /// - If the code just wants to store data of arbitrary type in some buffer and needs to pick a - /// type for that buffer, it can use [`MaybeUninit`][crate::mem::MaybeUninit]. - /// - If the code actually wants to work on the address the pointer points to, it can use `as` - /// casts or [`ptr.addr()`][pointer::addr]. - /// - /// Turning a `*mut T` into a `&mut T`: - /// - /// ``` - /// let ptr: *mut i32 = &mut 0; - /// let ref_transmuted = unsafe { - /// std::mem::transmute::<*mut i32, &mut i32>(ptr) - /// }; - /// - /// // Use a reborrow instead - /// let ref_casted = unsafe { &mut *ptr }; - /// ``` - /// - /// Turning a `&mut T` into a `&mut U`: - /// - /// ``` - /// let ptr = &mut 0; - /// let val_transmuted = unsafe { - /// std::mem::transmute::<&mut i32, &mut u32>(ptr) - /// }; - /// - /// // Now, put together `as` and reborrowing - note the chaining of `as` - /// // `as` is not transitive - /// let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) }; - /// ``` - /// - /// Turning a `&str` into a `&[u8]`: - /// - /// ``` - /// // this is not a good way to do this. - /// let slice = unsafe { std::mem::transmute::<&str, &[u8]>("Rust") }; - /// assert_eq!(slice, &[82, 117, 115, 116]); - /// - /// // You could use `str::as_bytes` - /// let slice = "Rust".as_bytes(); - /// assert_eq!(slice, &[82, 117, 115, 116]); - /// - /// // Or, just use a byte string, if you have control over the string - /// // literal - /// assert_eq!(b"Rust", &[82, 117, 115, 116]); - /// ``` - /// - /// Turning a `Vec<&T>` into a `Vec>`. - /// - /// To transmute the inner type of the contents of a container, you must make sure to not - /// violate any of the container's invariants. For `Vec`, this means that both the size - /// *and alignment* of the inner types have to match. Other containers might rely on the - /// size of the type, alignment, or even the `TypeId`, in which case transmuting wouldn't - /// be possible at all without violating the container invariants. - /// - /// ``` - /// let store = [0, 1, 2, 3]; - /// let v_orig = store.iter().collect::>(); - /// - /// // clone the vector as we will reuse them later - /// let v_clone = v_orig.clone(); - /// - /// // Using transmute: this relies on the unspecified data layout of `Vec`, which is a - /// // bad idea and could cause Undefined Behavior. - /// // However, it is no-copy. - /// let v_transmuted = unsafe { - /// std::mem::transmute::, Vec>>(v_clone) - /// }; - /// - /// let v_clone = v_orig.clone(); - /// - /// // This is the suggested, safe way. - /// // It may copy the entire vector into a new one though, but also may not. - /// let v_collected = v_clone.into_iter() - /// .map(Some) - /// .collect::>>(); - /// - /// let v_clone = v_orig.clone(); - /// - /// // This is the proper no-copy, unsafe way of "transmuting" a `Vec`, without relying on the - /// // data layout. Instead of literally calling `transmute`, we perform a pointer cast, but - /// // in terms of converting the original inner type (`&i32`) to the new one (`Option<&i32>`), - /// // this has all the same caveats. Besides the information provided above, also consult the - /// // [`from_raw_parts`] documentation. - /// let v_from_raw = unsafe { - // FIXME Update this when vec_into_raw_parts is stabilized - /// // Ensure the original vector is not dropped. - /// let mut v_clone = std::mem::ManuallyDrop::new(v_clone); - /// Vec::from_raw_parts(v_clone.as_mut_ptr() as *mut Option<&i32>, - /// v_clone.len(), - /// v_clone.capacity()) - /// }; - /// ``` - /// - /// [`from_raw_parts`]: ../../std/vec/struct.Vec.html#method.from_raw_parts - /// - /// Implementing `split_at_mut`: - /// - /// ``` - /// use std::{slice, mem}; - /// - /// // There are multiple ways to do this, and there are multiple problems - /// // with the following (transmute) way. - /// fn split_at_mut_transmute(slice: &mut [T], mid: usize) - /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(mid <= len); - /// unsafe { - /// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice); - /// // first: transmute is not type safe; all it checks is that T and - /// // U are of the same size. Second, right here, you have two - /// // mutable references pointing to the same memory. - /// (&mut slice[0..mid], &mut slice2[mid..len]) - /// } - /// } - /// - /// // This gets rid of the type safety problems; `&mut *` will *only* give - /// // you a `&mut T` from a `&mut T` or `*mut T`. - /// fn split_at_mut_casts(slice: &mut [T], mid: usize) - /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(mid <= len); - /// unsafe { - /// let slice2 = &mut *(slice as *mut [T]); - /// // however, you still have two mutable references pointing to - /// // the same memory. - /// (&mut slice[0..mid], &mut slice2[mid..len]) - /// } - /// } - /// - /// // This is how the standard library does it. This is the best method, if - /// // you need to do something like this - /// fn split_at_stdlib(slice: &mut [T], mid: usize) - /// -> (&mut [T], &mut [T]) { - /// let len = slice.len(); - /// assert!(mid <= len); - /// unsafe { - /// let ptr = slice.as_mut_ptr(); - /// // This now has three mutable references pointing at the same - /// // memory. `slice`, the rvalue ret.0, and the rvalue ret.1. - /// // `slice` is never used after `let ptr = ...`, and so one can - /// // treat it as "dead", and therefore, you only have two real - /// // mutable slices. - /// (slice::from_raw_parts_mut(ptr, mid), - /// slice::from_raw_parts_mut(ptr.add(mid), len - mid)) - /// } - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_allowed_through_unstable_modules] - #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] - #[rustc_diagnostic_item = "transmute"] - #[rustc_nounwind] - pub fn transmute(src: Src) -> Dst; - - /// Like [`transmute`], but even less checked at compile-time: rather than - /// giving an error for `size_of::() != size_of::()`, it's - /// **Undefined Behavior** at runtime. - /// - /// Prefer normal `transmute` where possible, for the extra checking, since - /// both do exactly the same thing at runtime, if they both compile. - /// - /// This is not expected to ever be exposed directly to users, rather it - /// may eventually be exposed through some more-constrained API. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_transmute", since = "1.56.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn transmute_unchecked(src: Src) -> Dst; +/// Reinterprets the bits of a value of one type as another type. +/// +/// Both types must have the same size. Compilation will fail if this is not guaranteed. +/// +/// `transmute` is semantically equivalent to a bitwise move of one type +/// into another. It copies the bits from the source value into the +/// destination value, then forgets the original. Note that source and destination +/// are passed by-value, which means if `Src` or `Dst` contain padding, that padding +/// is *not* guaranteed to be preserved by `transmute`. +/// +/// Both the argument and the result must be [valid](../../nomicon/what-unsafe-does.html) at +/// their given type. Violating this condition leads to [undefined behavior][ub]. The compiler +/// will generate code *assuming that you, the programmer, ensure that there will never be +/// undefined behavior*. It is therefore your responsibility to guarantee that every value +/// passed to `transmute` is valid at both types `Src` and `Dst`. Failing to uphold this condition +/// may lead to unexpected and unstable compilation results. This makes `transmute` **incredibly +/// unsafe**. `transmute` should be the absolute last resort. +/// +/// Because `transmute` is a by-value operation, alignment of the *transmuted values +/// themselves* is not a concern. As with any other function, the compiler already ensures +/// both `Src` and `Dst` are properly aligned. However, when transmuting values that *point +/// elsewhere* (such as pointers, references, boxes…), the caller has to ensure proper +/// alignment of the pointed-to values. +/// +/// The [nomicon](../../nomicon/transmutes.html) has additional documentation. +/// +/// [ub]: ../../reference/behavior-considered-undefined.html +/// +/// # Transmutation between pointers and integers +/// +/// Special care has to be taken when transmuting between pointers and integers, e.g. +/// transmuting between `*const ()` and `usize`. +/// +/// Transmuting *pointers to integers* in a `const` context is [undefined behavior][ub], unless +/// the pointer was originally created *from* an integer. (That includes this function +/// specifically, integer-to-pointer casts, and helpers like [`dangling`][crate::ptr::dangling], +/// but also semantically-equivalent conversions such as punning through `repr(C)` union +/// fields.) Any attempt to use the resulting value for integer operations will abort +/// const-evaluation. (And even outside `const`, such transmutation is touching on many +/// unspecified aspects of the Rust memory model and should be avoided. See below for +/// alternatives.) +/// +/// Transmuting *integers to pointers* is a largely unspecified operation. It is likely *not* +/// equivalent to an `as` cast. Doing non-zero-sized memory accesses with a pointer constructed +/// this way is currently considered undefined behavior. +/// +/// All this also applies when the integer is nested inside an array, tuple, struct, or enum. +/// However, `MaybeUninit` is not considered an integer type for the purpose of this +/// section. Transmuting `*const ()` to `MaybeUninit` is fine---but then calling +/// `assume_init()` on that result is considered as completing the pointer-to-integer transmute +/// and thus runs into the issues discussed above. +/// +/// In particular, doing a pointer-to-integer-to-pointer roundtrip via `transmute` is *not* a +/// lossless process. If you want to round-trip a pointer through an integer in a way that you +/// can get back the original pointer, you need to use `as` casts, or replace the integer type +/// by `MaybeUninit<$int>` (and never call `assume_init()`). If you are looking for a way to +/// store data of arbitrary type, also use `MaybeUninit` (that will also handle uninitialized +/// memory due to padding). If you specifically need to store something that is "either an +/// integer or a pointer", use `*mut ()`: integers can be converted to pointers and back without +/// any loss (via `as` casts or via `transmute`). +/// +/// # Examples +/// +/// There are a few things that `transmute` is really useful for. +/// +/// Turning a pointer into a function pointer. This is *not* portable to +/// machines where function pointers and data pointers have different sizes. +/// +/// ``` +/// fn foo() -> i32 { +/// 0 +/// } +/// // 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. +/// let pointer = foo as *const (); +/// let function = unsafe { +/// std::mem::transmute::<*const (), fn() -> i32>(pointer) +/// }; +/// assert_eq!(function(), 0); +/// ``` +/// +/// Extending a lifetime, or shortening an invariant lifetime. This is +/// advanced, very unsafe Rust! +/// +/// ``` +/// struct R<'a>(&'a i32); +/// unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> { +/// std::mem::transmute::, R<'static>>(r) +/// } +/// +/// unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) +/// -> &'b mut R<'c> { +/// std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r) +/// } +/// ``` +/// +/// # Alternatives +/// +/// Don't despair: many uses of `transmute` can be achieved through other means. +/// Below are common applications of `transmute` which can be replaced with safer +/// constructs. +/// +/// Turning raw bytes (`[u8; SZ]`) into `u32`, `f64`, etc.: +/// +/// ``` +/// let raw_bytes = [0x78, 0x56, 0x34, 0x12]; +/// +/// let num = unsafe { +/// std::mem::transmute::<[u8; 4], u32>(raw_bytes) +/// }; +/// +/// // use `u32::from_ne_bytes` instead +/// let num = u32::from_ne_bytes(raw_bytes); +/// // or use `u32::from_le_bytes` or `u32::from_be_bytes` to specify the endianness +/// let num = u32::from_le_bytes(raw_bytes); +/// assert_eq!(num, 0x12345678); +/// let num = u32::from_be_bytes(raw_bytes); +/// assert_eq!(num, 0x78563412); +/// ``` +/// +/// Turning a pointer into a `usize`: +/// +/// ```no_run +/// let ptr = &0; +/// let ptr_num_transmute = unsafe { +/// std::mem::transmute::<&i32, usize>(ptr) +/// }; +/// +/// // Use an `as` cast instead +/// let ptr_num_cast = ptr as *const i32 as usize; +/// ``` +/// +/// Note that using `transmute` to turn a pointer to a `usize` is (as noted above) [undefined +/// behavior][ub] in `const` contexts. Also outside of consts, this operation might not behave +/// as expected -- this is touching on many unspecified aspects of the Rust memory model. +/// Depending on what the code is doing, the following alternatives are preferable to +/// pointer-to-integer transmutation: +/// - If the code just wants to store data of arbitrary type in some buffer and needs to pick a +/// type for that buffer, it can use [`MaybeUninit`][crate::mem::MaybeUninit]. +/// - If the code actually wants to work on the address the pointer points to, it can use `as` +/// casts or [`ptr.addr()`][pointer::addr]. +/// +/// Turning a `*mut T` into a `&mut T`: +/// +/// ``` +/// let ptr: *mut i32 = &mut 0; +/// let ref_transmuted = unsafe { +/// std::mem::transmute::<*mut i32, &mut i32>(ptr) +/// }; +/// +/// // Use a reborrow instead +/// let ref_casted = unsafe { &mut *ptr }; +/// ``` +/// +/// Turning a `&mut T` into a `&mut U`: +/// +/// ``` +/// let ptr = &mut 0; +/// let val_transmuted = unsafe { +/// std::mem::transmute::<&mut i32, &mut u32>(ptr) +/// }; +/// +/// // Now, put together `as` and reborrowing - note the chaining of `as` +/// // `as` is not transitive +/// let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) }; +/// ``` +/// +/// Turning a `&str` into a `&[u8]`: +/// +/// ``` +/// // this is not a good way to do this. +/// let slice = unsafe { std::mem::transmute::<&str, &[u8]>("Rust") }; +/// assert_eq!(slice, &[82, 117, 115, 116]); +/// +/// // You could use `str::as_bytes` +/// let slice = "Rust".as_bytes(); +/// assert_eq!(slice, &[82, 117, 115, 116]); +/// +/// // Or, just use a byte string, if you have control over the string +/// // literal +/// assert_eq!(b"Rust", &[82, 117, 115, 116]); +/// ``` +/// +/// Turning a `Vec<&T>` into a `Vec>`. +/// +/// To transmute the inner type of the contents of a container, you must make sure to not +/// violate any of the container's invariants. For `Vec`, this means that both the size +/// *and alignment* of the inner types have to match. Other containers might rely on the +/// size of the type, alignment, or even the `TypeId`, in which case transmuting wouldn't +/// be possible at all without violating the container invariants. +/// +/// ``` +/// let store = [0, 1, 2, 3]; +/// let v_orig = store.iter().collect::>(); +/// +/// // clone the vector as we will reuse them later +/// let v_clone = v_orig.clone(); +/// +/// // Using transmute: this relies on the unspecified data layout of `Vec`, which is a +/// // bad idea and could cause Undefined Behavior. +/// // However, it is no-copy. +/// let v_transmuted = unsafe { +/// std::mem::transmute::, Vec>>(v_clone) +/// }; +/// +/// let v_clone = v_orig.clone(); +/// +/// // This is the suggested, safe way. +/// // It may copy the entire vector into a new one though, but also may not. +/// let v_collected = v_clone.into_iter() +/// .map(Some) +/// .collect::>>(); +/// +/// let v_clone = v_orig.clone(); +/// +/// // This is the proper no-copy, unsafe way of "transmuting" a `Vec`, without relying on the +/// // data layout. Instead of literally calling `transmute`, we perform a pointer cast, but +/// // in terms of converting the original inner type (`&i32`) to the new one (`Option<&i32>`), +/// // this has all the same caveats. Besides the information provided above, also consult the +/// // [`from_raw_parts`] documentation. +/// let v_from_raw = unsafe { +// FIXME Update this when vec_into_raw_parts is stabilized +/// // Ensure the original vector is not dropped. +/// let mut v_clone = std::mem::ManuallyDrop::new(v_clone); +/// Vec::from_raw_parts(v_clone.as_mut_ptr() as *mut Option<&i32>, +/// v_clone.len(), +/// v_clone.capacity()) +/// }; +/// ``` +/// +/// [`from_raw_parts`]: ../../std/vec/struct.Vec.html#method.from_raw_parts +/// +/// Implementing `split_at_mut`: +/// +/// ``` +/// use std::{slice, mem}; +/// +/// // There are multiple ways to do this, and there are multiple problems +/// // with the following (transmute) way. +/// fn split_at_mut_transmute(slice: &mut [T], mid: usize) +/// -> (&mut [T], &mut [T]) { +/// let len = slice.len(); +/// assert!(mid <= len); +/// unsafe { +/// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice); +/// // first: transmute is not type safe; all it checks is that T and +/// // U are of the same size. Second, right here, you have two +/// // mutable references pointing to the same memory. +/// (&mut slice[0..mid], &mut slice2[mid..len]) +/// } +/// } +/// +/// // This gets rid of the type safety problems; `&mut *` will *only* give +/// // you a `&mut T` from a `&mut T` or `*mut T`. +/// fn split_at_mut_casts(slice: &mut [T], mid: usize) +/// -> (&mut [T], &mut [T]) { +/// let len = slice.len(); +/// assert!(mid <= len); +/// unsafe { +/// let slice2 = &mut *(slice as *mut [T]); +/// // however, you still have two mutable references pointing to +/// // the same memory. +/// (&mut slice[0..mid], &mut slice2[mid..len]) +/// } +/// } +/// +/// // This is how the standard library does it. This is the best method, if +/// // you need to do something like this +/// fn split_at_stdlib(slice: &mut [T], mid: usize) +/// -> (&mut [T], &mut [T]) { +/// let len = slice.len(); +/// assert!(mid <= len); +/// unsafe { +/// let ptr = slice.as_mut_ptr(); +/// // This now has three mutable references pointing at the same +/// // memory. `slice`, the rvalue ret.0, and the rvalue ret.1. +/// // `slice` is never used after `let ptr = ...`, and so one can +/// // treat it as "dead", and therefore, you only have two real +/// // mutable slices. +/// (slice::from_raw_parts_mut(ptr, mid), +/// slice::from_raw_parts_mut(ptr.add(mid), len - mid)) +/// } +/// } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_allowed_through_unstable_modules] +#[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] +#[rustc_diagnostic_item = "transmute"] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn transmute(_src: Src) -> Dst { + unreachable!() +} - /// Returns `true` if the actual type given as `T` requires drop - /// glue; returns `false` if the actual type provided for `T` - /// implements `Copy`. - /// - /// If the actual type neither requires drop glue nor implements - /// `Copy`, then the return value of this function is unspecified. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop). - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_needs_drop", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn needs_drop() -> bool; +/// Like [`transmute`], but even less checked at compile-time: rather than +/// giving an error for `size_of::() != size_of::()`, it's +/// **Undefined Behavior** at runtime. +/// +/// Prefer normal `transmute` where possible, for the extra checking, since +/// both do exactly the same thing at runtime, if they both compile. +/// +/// This is not expected to ever be exposed directly to users, rather it +/// may eventually be exposed through some more-constrained API. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_transmute", since = "1.56.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn transmute_unchecked(_src: Src) -> Dst { + unreachable!() +} - /// Calculates the offset from a pointer. - /// - /// This is implemented as an intrinsic to avoid converting to and from an - /// integer, since the conversion would throw away aliasing information. - /// - /// This can only be used with `Ptr` as a raw pointer type (`*mut` or `*const`) - /// to a `Sized` pointee and with `Delta` as `usize` or `isize`. Any other - /// instantiations may arbitrarily misbehave, and that's *not* a compiler bug. - /// - /// # Safety - /// - /// If the computed offset is non-zero, then both the starting and resulting pointer must be - /// either in bounds or at the end of an allocated object. If either pointer is out - /// of bounds or arithmetic overflow occurs then this operation is undefined behavior. - /// - /// The stabilized version of this intrinsic is [`pointer::offset`]. - #[must_use = "returns a new pointer rather than modifying its argument"] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn offset(dst: Ptr, offset: Delta) -> Ptr; +/// Returns `true` if the actual type given as `T` requires drop +/// glue; returns `false` if the actual type provided for `T` +/// implements `Copy`. +/// +/// If the actual type neither requires drop glue nor implements +/// `Copy`, then the return value of this function is unspecified. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop). +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_needs_drop", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn needs_drop() -> bool { + unreachable!() +} - /// Calculates the offset from a pointer, potentially wrapping. - /// - /// This is implemented as an intrinsic to avoid converting to and from an - /// integer, since the conversion inhibits certain optimizations. - /// - /// # Safety - /// - /// Unlike the `offset` intrinsic, this intrinsic does not restrict the - /// resulting pointer to point into or at the end of an allocated - /// object, and it wraps with two's complement arithmetic. The resulting - /// value is not necessarily valid to be used to actually access memory. - /// - /// The stabilized version of this intrinsic is [`pointer::wrapping_offset`]. - #[must_use = "returns a new pointer rather than modifying its argument"] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn arith_offset(dst: *const T, offset: isize) -> *const T; +/// Calculates the offset from a pointer. +/// +/// This is implemented as an intrinsic to avoid converting to and from an +/// integer, since the conversion would throw away aliasing information. +/// +/// This can only be used with `Ptr` as a raw pointer type (`*mut` or `*const`) +/// to a `Sized` pointee and with `Delta` as `usize` or `isize`. Any other +/// instantiations may arbitrarily misbehave, and that's *not* a compiler bug. +/// +/// # Safety +/// +/// If the computed offset is non-zero, then both the starting and resulting pointer must be +/// either in bounds or at the end of an allocated object. If either pointer is out +/// of bounds or arithmetic overflow occurs then this operation is undefined behavior. +/// +/// The stabilized version of this intrinsic is [`pointer::offset`]. +#[must_use = "returns a new pointer rather than modifying its argument"] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn offset(_dst: Ptr, _offset: Delta) -> Ptr { + unreachable!() +} + +/// Calculates the offset from a pointer, potentially wrapping. +/// +/// This is implemented as an intrinsic to avoid converting to and from an +/// integer, since the conversion inhibits certain optimizations. +/// +/// # Safety +/// +/// Unlike the `offset` intrinsic, this intrinsic does not restrict the +/// resulting pointer to point into or at the end of an allocated +/// object, and it wraps with two's complement arithmetic. The resulting +/// value is not necessarily valid to be used to actually access memory. +/// +/// The stabilized version of this intrinsic is [`pointer::wrapping_offset`]. +#[must_use = "returns a new pointer rather than modifying its argument"] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn arith_offset(_dst: *const T, _offset: isize) -> *const T { + unreachable!() +} +extern "rust-intrinsic" { /// Masks out bits of the pointer according to a mask. /// /// Note that, unlike most intrinsics, this is safe to call; @@ -2143,474 +2181,569 @@ extern "rust-intrinsic" { /// Stabilized as [`f32::to_int_unchecked`] and [`f64::to_int_unchecked`]. #[rustc_nounwind] pub fn float_to_int_unchecked(value: Float) -> Int; +} - /// Returns the number of bits set in an integer type `T` - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `count_ones` method. For example, - /// [`u32::count_ones`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctpop", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn ctpop(x: T) -> u32; - - /// Returns the number of leading unset bits (zeroes) in an integer type `T`. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `leading_zeros` method. For example, - /// [`u32::leading_zeros`] - /// - /// # Examples - /// - /// ``` - /// #![feature(core_intrinsics)] - /// # #![allow(internal_features)] - /// - /// use std::intrinsics::ctlz; - /// - /// let x = 0b0001_1100_u8; - /// let num_leading = ctlz(x); - /// assert_eq!(num_leading, 3); - /// ``` - /// - /// An `x` with value `0` will return the bit width of `T`. - /// - /// ``` - /// #![feature(core_intrinsics)] - /// # #![allow(internal_features)] - /// - /// use std::intrinsics::ctlz; - /// - /// let x = 0u16; - /// let num_leading = ctlz(x); - /// assert_eq!(num_leading, 16); - /// ``` - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctlz", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn ctlz(x: T) -> u32; +/// Returns the number of bits set in an integer type `T` +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `count_ones` method. For example, +/// [`u32::count_ones`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctpop", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn ctpop(_x: T) -> u32 { + unimplemented!() +} - /// Like `ctlz`, but extra-unsafe as it returns `undef` when - /// given an `x` with value `0`. - /// - /// This intrinsic does not have a stable counterpart. - /// - /// # Examples - /// - /// ``` - /// #![feature(core_intrinsics)] - /// # #![allow(internal_features)] - /// - /// use std::intrinsics::ctlz_nonzero; - /// - /// let x = 0b0001_1100_u8; - /// let num_leading = unsafe { ctlz_nonzero(x) }; - /// assert_eq!(num_leading, 3); - /// ``` - #[cfg_attr(bootstrap, rustc_const_stable(feature = "constctlz", since = "1.50.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn ctlz_nonzero(x: T) -> u32; +/// Returns the number of leading unset bits (zeroes) in an integer type `T`. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `leading_zeros` method. For example, +/// [`u32::leading_zeros`] +/// +/// # Examples +/// +/// ``` +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// +/// use std::intrinsics::ctlz; +/// +/// let x = 0b0001_1100_u8; +/// let num_leading = ctlz(x); +/// assert_eq!(num_leading, 3); +/// ``` +/// +/// An `x` with value `0` will return the bit width of `T`. +/// +/// ``` +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// +/// use std::intrinsics::ctlz; +/// +/// let x = 0u16; +/// let num_leading = ctlz(x); +/// assert_eq!(num_leading, 16); +/// ``` +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctlz", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn ctlz(_x: T) -> u32 { + unimplemented!() +} - /// Returns the number of trailing unset bits (zeroes) in an integer type `T`. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `trailing_zeros` method. For example, - /// [`u32::trailing_zeros`] - /// - /// # Examples - /// - /// ``` - /// #![feature(core_intrinsics)] - /// # #![allow(internal_features)] - /// - /// use std::intrinsics::cttz; - /// - /// let x = 0b0011_1000_u8; - /// let num_trailing = cttz(x); - /// assert_eq!(num_trailing, 3); - /// ``` - /// - /// An `x` with value `0` will return the bit width of `T`: - /// - /// ``` - /// #![feature(core_intrinsics)] - /// # #![allow(internal_features)] - /// - /// use std::intrinsics::cttz; - /// - /// let x = 0u16; - /// let num_trailing = cttz(x); - /// assert_eq!(num_trailing, 16); - /// ``` - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn cttz(x: T) -> u32; +/// Like `ctlz`, but extra-unsafe as it returns `undef` when +/// given an `x` with value `0`. +/// +/// This intrinsic does not have a stable counterpart. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// +/// use std::intrinsics::ctlz_nonzero; +/// +/// let x = 0b0001_1100_u8; +/// let num_leading = unsafe { ctlz_nonzero(x) }; +/// assert_eq!(num_leading, 3); +/// ``` +#[cfg_attr(bootstrap, rustc_const_stable(feature = "constctlz", since = "1.50.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn ctlz_nonzero(_x: T) -> u32 { + unimplemented!() +} - /// Like `cttz`, but extra-unsafe as it returns `undef` when - /// given an `x` with value `0`. - /// - /// This intrinsic does not have a stable counterpart. - /// - /// # Examples - /// - /// ``` - /// #![feature(core_intrinsics)] - /// # #![allow(internal_features)] - /// - /// use std::intrinsics::cttz_nonzero; - /// - /// let x = 0b0011_1000_u8; - /// let num_trailing = unsafe { cttz_nonzero(x) }; - /// assert_eq!(num_trailing, 3); - /// ``` - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn cttz_nonzero(x: T) -> u32; +/// Returns the number of trailing unset bits (zeroes) in an integer type `T`. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `trailing_zeros` method. For example, +/// [`u32::trailing_zeros`] +/// +/// # Examples +/// +/// ``` +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// +/// use std::intrinsics::cttz; +/// +/// let x = 0b0011_1000_u8; +/// let num_trailing = cttz(x); +/// assert_eq!(num_trailing, 3); +/// ``` +/// +/// An `x` with value `0` will return the bit width of `T`: +/// +/// ``` +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// +/// use std::intrinsics::cttz; +/// +/// let x = 0u16; +/// let num_trailing = cttz(x); +/// assert_eq!(num_trailing, 16); +/// ``` +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn cttz(_x: T) -> u32 { + unimplemented!() +} - /// Reverses the bytes in an integer type `T`. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `swap_bytes` method. For example, - /// [`u32::swap_bytes`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bswap", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn bswap(x: T) -> T; +/// Like `cttz`, but extra-unsafe as it returns `undef` when +/// given an `x` with value `0`. +/// +/// This intrinsic does not have a stable counterpart. +/// +/// # Examples +/// +/// ``` +/// #![feature(core_intrinsics)] +/// # #![allow(internal_features)] +/// +/// use std::intrinsics::cttz_nonzero; +/// +/// let x = 0b0011_1000_u8; +/// let num_trailing = unsafe { cttz_nonzero(x) }; +/// assert_eq!(num_trailing, 3); +/// ``` +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn cttz_nonzero(_x: T) -> u32 { + unimplemented!() +} - /// Reverses the bits in an integer type `T`. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `reverse_bits` method. For example, - /// [`u32::reverse_bits`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bitreverse", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn bitreverse(x: T) -> T; +/// Reverses the bytes in an integer type `T`. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `swap_bytes` method. For example, +/// [`u32::swap_bytes`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bswap", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn bswap(_x: T) -> T { + unimplemented!() +} - /// Does a three-way comparison between the two integer arguments. - /// - /// This is included as an intrinsic as it's useful to let it be one thing - /// in MIR, rather than the multiple checks and switches that make its IR - /// large and difficult to optimize. - /// - /// The stabilized version of this intrinsic is [`Ord::cmp`]. - #[rustc_const_unstable(feature = "const_three_way_compare", issue = "none")] - #[rustc_safe_intrinsic] - pub fn three_way_compare(lhs: T, rhs: T) -> crate::cmp::Ordering; +/// Reverses the bits in an integer type `T`. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `reverse_bits` method. For example, +/// [`u32::reverse_bits`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bitreverse", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn bitreverse(_x: T) -> T { + unimplemented!() +} - /// Performs checked integer addition. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `overflowing_add` method. For example, - /// [`u32::overflowing_add`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn add_with_overflow(x: T, y: T) -> (T, bool); +/// Does a three-way comparison between the two integer arguments. +/// +/// This is included as an intrinsic as it's useful to let it be one thing +/// in MIR, rather than the multiple checks and switches that make its IR +/// large and difficult to optimize. +/// +/// The stabilized version of this intrinsic is [`Ord::cmp`]. +#[rustc_const_unstable(feature = "const_three_way_compare", issue = "none")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn three_way_compare(_lhs: T, _rhss: T) -> crate::cmp::Ordering { + unimplemented!() +} - /// Performs checked integer subtraction - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `overflowing_sub` method. For example, - /// [`u32::overflowing_sub`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn sub_with_overflow(x: T, y: T) -> (T, bool); +/// Performs checked integer addition. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `overflowing_add` method. For example, +/// [`u32::overflowing_add`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn add_with_overflow(_x: T, _y: T) -> (T, bool) { + unimplemented!() +} - /// Performs checked integer multiplication - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `overflowing_mul` method. For example, - /// [`u32::overflowing_mul`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn mul_with_overflow(x: T, y: T) -> (T, bool); +/// Performs checked integer subtraction +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `overflowing_sub` method. For example, +/// [`u32::overflowing_sub`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn sub_with_overflow(_x: T, _y: T) -> (T, bool) { + unimplemented!() +} - /// Performs an exact division, resulting in undefined behavior where - /// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1` - /// - /// This intrinsic does not have a stable counterpart. - #[rustc_const_unstable(feature = "const_exact_div", issue = "none")] - #[rustc_nounwind] - pub fn exact_div(x: T, y: T) -> T; +/// Performs checked integer multiplication +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `overflowing_mul` method. For example, +/// [`u32::overflowing_mul`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn mul_with_overflow(_x: T, _y: T) -> (T, bool) { + unimplemented!() +} - /// Performs an unchecked division, resulting in undefined behavior - /// where `y == 0` or `x == T::MIN && y == -1` - /// - /// Safe wrappers for this intrinsic are available on the integer - /// primitives via the `checked_div` method. For example, - /// [`u32::checked_div`] - #[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0") - )] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_div(x: T, y: T) -> T; - /// Returns the remainder of an unchecked division, resulting in - /// undefined behavior when `y == 0` or `x == T::MIN && y == -1` - /// - /// Safe wrappers for this intrinsic are available on the integer - /// primitives via the `checked_rem` method. For example, - /// [`u32::checked_rem`] - #[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0") - )] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_rem(x: T, y: T) -> T; +/// Performs an exact division, resulting in undefined behavior where +/// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1` +/// +/// This intrinsic does not have a stable counterpart. +#[rustc_const_unstable(feature = "const_exact_div", issue = "none")] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn exact_div(_x: T, _y: T) -> T { + unimplemented!() +} - /// Performs an unchecked left shift, resulting in undefined behavior when - /// `y < 0` or `y >= N`, where N is the width of T in bits. - /// - /// Safe wrappers for this intrinsic are available on the integer - /// primitives via the `checked_shl` method. For example, - /// [`u32::checked_shl`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_shl(x: T, y: U) -> T; - /// Performs an unchecked right shift, resulting in undefined behavior when - /// `y < 0` or `y >= N`, where N is the width of T in bits. - /// - /// Safe wrappers for this intrinsic are available on the integer - /// primitives via the `checked_shr` method. For example, - /// [`u32::checked_shr`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_shr(x: T, y: U) -> T; +/// Performs an unchecked division, resulting in undefined behavior +/// where `y == 0` or `x == T::MIN && y == -1` +/// +/// Safe wrappers for this intrinsic are available on the integer +/// primitives via the `checked_div` method. For example, +/// [`u32::checked_div`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_div(_x: T, _y: T) -> T { + unimplemented!() +} +/// Returns the remainder of an unchecked division, resulting in +/// undefined behavior when `y == 0` or `x == T::MIN && y == -1` +/// +/// Safe wrappers for this intrinsic are available on the integer +/// primitives via the `checked_rem` method. For example, +/// [`u32::checked_rem`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_rem(_x: T, _y: T) -> T { + unimplemented!() +} - /// Returns the result of an unchecked addition, resulting in - /// undefined behavior when `x + y > T::MAX` or `x + y < T::MIN`. - /// - /// The stable counterpart of this intrinsic is `unchecked_add` on the various - /// integer types, such as [`u16::unchecked_add`] and [`i64::unchecked_add`]. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_add(x: T, y: T) -> T; +/// Performs an unchecked left shift, resulting in undefined behavior when +/// `y < 0` or `y >= N`, where N is the width of T in bits. +/// +/// Safe wrappers for this intrinsic are available on the integer +/// primitives via the `checked_shl` method. For example, +/// [`u32::checked_shl`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_shl(_x: T, _y: U) -> T { + unimplemented!() +} +/// Performs an unchecked right shift, resulting in undefined behavior when +/// `y < 0` or `y >= N`, where N is the width of T in bits. +/// +/// Safe wrappers for this intrinsic are available on the integer +/// primitives via the `checked_shr` method. For example, +/// [`u32::checked_shr`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_shr(_x: T, _y: U) -> T { + unimplemented!() +} - /// Returns the result of an unchecked subtraction, resulting in - /// undefined behavior when `x - y > T::MAX` or `x - y < T::MIN`. - /// - /// The stable counterpart of this intrinsic is `unchecked_sub` on the various - /// integer types, such as [`u16::unchecked_sub`] and [`i64::unchecked_sub`]. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_sub(x: T, y: T) -> T; +/// Returns the result of an unchecked addition, resulting in +/// undefined behavior when `x + y > T::MAX` or `x + y < T::MIN`. +/// +/// The stable counterpart of this intrinsic is `unchecked_add` on the various +/// integer types, such as [`u16::unchecked_add`] and [`i64::unchecked_add`]. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_add(_x: T, _y: T) -> T { + unimplemented!() +} + +/// Returns the result of an unchecked subtraction, resulting in +/// undefined behavior when `x - y > T::MAX` or `x - y < T::MIN`. +/// +/// The stable counterpart of this intrinsic is `unchecked_sub` on the various +/// integer types, such as [`u16::unchecked_sub`] and [`i64::unchecked_sub`]. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_sub(_x: T, _y: T) -> T { + unimplemented!() +} - /// Returns the result of an unchecked multiplication, resulting in - /// undefined behavior when `x * y > T::MAX` or `x * y < T::MIN`. - /// - /// The stable counterpart of this intrinsic is `unchecked_mul` on the various - /// integer types, such as [`u16::unchecked_mul`] and [`i64::unchecked_mul`]. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn unchecked_mul(x: T, y: T) -> T; +/// Returns the result of an unchecked multiplication, resulting in +/// undefined behavior when `x * y > T::MAX` or `x * y < T::MIN`. +/// +/// The stable counterpart of this intrinsic is `unchecked_mul` on the various +/// integer types, such as [`u16::unchecked_mul`] and [`i64::unchecked_mul`]. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn unchecked_mul(_x: T, _y: T) -> T { + unimplemented!() +} - /// Performs rotate left. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `rotate_left` method. For example, - /// [`u32::rotate_left`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn rotate_left(x: T, shift: u32) -> T; +/// Performs rotate left. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `rotate_left` method. For example, +/// [`u32::rotate_left`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn rotate_left(_x: T, _shift: u32) -> T { + unimplemented!() +} - /// Performs rotate right. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `rotate_right` method. For example, - /// [`u32::rotate_right`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn rotate_right(x: T, shift: u32) -> T; +/// Performs rotate right. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `rotate_right` method. For example, +/// [`u32::rotate_right`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn rotate_right(_x: T, _shift: u32) -> T { + unimplemented!() +} - /// Returns (a + b) mod 2N, where N is the width of T in bits. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `wrapping_add` method. For example, - /// [`u32::wrapping_add`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn wrapping_add(a: T, b: T) -> T; - /// Returns (a - b) mod 2N, where N is the width of T in bits. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `wrapping_sub` method. For example, - /// [`u32::wrapping_sub`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn wrapping_sub(a: T, b: T) -> T; - /// Returns (a * b) mod 2N, where N is the width of T in bits. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `wrapping_mul` method. For example, - /// [`u32::wrapping_mul`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn wrapping_mul(a: T, b: T) -> T; +/// Returns (a + b) mod 2N, where N is the width of T in bits. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `wrapping_add` method. For example, +/// [`u32::wrapping_add`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn wrapping_add(_a: T, _b: T) -> T { + unimplemented!() +} +/// Returns (a - b) mod 2N, where N is the width of T in bits. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `wrapping_sub` method. For example, +/// [`u32::wrapping_sub`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn wrapping_sub(_a: T, _b: T) -> T { + unimplemented!() +} +/// Returns (a * b) mod 2N, where N is the width of T in bits. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `wrapping_mul` method. For example, +/// [`u32::wrapping_mul`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn wrapping_mul(_a: T, _b: T) -> T { + unimplemented!() +} - /// Computes `a + b`, saturating at numeric bounds. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `saturating_add` method. For example, - /// [`u32::saturating_add`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn saturating_add(a: T, b: T) -> T; - /// Computes `a - b`, saturating at numeric bounds. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized versions of this intrinsic are available on the integer - /// primitives via the `saturating_sub` method. For example, - /// [`u32::saturating_sub`] - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn saturating_sub(a: T, b: T) -> T; +/// Computes `a + b`, saturating at numeric bounds. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `saturating_add` method. For example, +/// [`u32::saturating_add`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn saturating_add(_a: T, _b: T) -> T { + unimplemented!() +} +/// Computes `a - b`, saturating at numeric bounds. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized versions of this intrinsic are available on the integer +/// primitives via the `saturating_sub` method. For example, +/// [`u32::saturating_sub`] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn saturating_sub(_a: T, _b: T) -> T { + unimplemented!() +} - /// This is an implementation detail of [`crate::ptr::read`] and should - /// not be used anywhere else. See its comments for why this exists. - /// - /// This intrinsic can *only* be called where the pointer is a local without - /// projections (`read_via_copy(ptr)`, not `read_via_copy(*ptr)`) so that it - /// trivially obeys runtime-MIR rules about derefs in operands. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_read", since = "1.71.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn read_via_copy(ptr: *const T) -> T; +/// This is an implementation detail of [`crate::ptr::read`] and should +/// not be used anywhere else. See its comments for why this exists. +/// +/// This intrinsic can *only* be called where the pointer is a local without +/// projections (`read_via_copy(ptr)`, not `read_via_copy(*ptr)`) so that it +/// trivially obeys runtime-MIR rules about derefs in operands. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_read", since = "1.71.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn read_via_copy(_ptr: *const T) -> T { + unimplemented!() +} - /// This is an implementation detail of [`crate::ptr::write`] and should - /// not be used anywhere else. See its comments for why this exists. - /// - /// This intrinsic can *only* be called where the pointer is a local without - /// projections (`write_via_move(ptr, x)`, not `write_via_move(*ptr, x)`) so - /// that it trivially obeys runtime-MIR rules about derefs in operands. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn write_via_move(ptr: *mut T, value: T); +/// This is an implementation detail of [`crate::ptr::write`] and should +/// not be used anywhere else. See its comments for why this exists. +/// +/// This intrinsic can *only* be called where the pointer is a local without +/// projections (`write_via_move(ptr, x)`, not `write_via_move(*ptr, x)`) so +/// that it trivially obeys runtime-MIR rules about derefs in operands. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn write_via_move(_ptr: *mut T, _value: T) { + unimplemented!() +} - /// Returns the value of the discriminant for the variant in 'v'; - /// if `T` has no discriminant, returns `0`. - /// - /// Note that, unlike most intrinsics, this is safe to call; - /// it does not require an `unsafe` block. - /// Therefore, implementations must not require the user to uphold - /// any safety invariants. - /// - /// The stabilized version of this intrinsic is [`core::mem::discriminant`]. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_discriminant", since = "1.75.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn discriminant_value(v: &T) -> ::Discriminant; +/// Returns the value of the discriminant for the variant in 'v'; +/// if `T` has no discriminant, returns `0`. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is [`core::mem::discriminant`]. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_discriminant", since = "1.75.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn discriminant_value(_v: &T) -> ::Discriminant { + unimplemented!() +} +extern "rust-intrinsic" { /// Rust's "try catch" construct for unwinding. Invokes the function pointer `try_fn` with the /// data pointer `data`, and calls `catch_fn` if unwinding occurs while `try_fn` runs. /// @@ -2638,17 +2771,25 @@ extern "rust-intrinsic" { /// in ways that are not allowed for regular writes). #[rustc_nounwind] pub fn nontemporal_store(ptr: *mut T, val: T); +} - /// See documentation of `<*const T>::offset_from` for details. - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn ptr_offset_from(ptr: *const T, base: *const T) -> isize; +/// See documentation of `<*const T>::offset_from` for details. +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0"))] +#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn ptr_offset_from(_ptr: *const T, _base: *const T) -> isize { + unimplemented!() +} - /// See documentation of `<*const T>::sub_ptr` for details. - #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] - #[rustc_nounwind] - pub fn ptr_offset_from_unsigned(ptr: *const T, base: *const T) -> usize; +/// See documentation of `<*const T>::sub_ptr` for details. +#[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn ptr_offset_from_unsigned(_ptr: *const T, _base: *const T) -> usize { + unimplemented!() } /// See documentation of `<*const T>::guaranteed_eq` for details. @@ -2666,59 +2807,68 @@ pub const fn ptr_guaranteed_cmp(ptr: *const T, other: *const T) -> u8 { (ptr == other) as u8 } -extern "rust-intrinsic" { - /// Determines whether the raw bytes of the two values are equal. - /// - /// This is particularly handy for arrays, since it allows things like just - /// comparing `i96`s instead of forcing `alloca`s for `[6 x i16]`. - /// - /// Above some backend-decided threshold this will emit calls to `memcmp`, - /// like slice equality does, instead of causing massive code size. - /// - /// Since this works by comparing the underlying bytes, the actual `T` is - /// not particularly important. It will be used for its size and alignment, - /// but any validity restrictions will be ignored, not enforced. - /// - /// # Safety - /// - /// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized. - /// Note that this is a stricter criterion than just the *values* being - /// fully-initialized: if `T` has padding, it's UB to call this intrinsic. - /// - /// At compile-time, it is furthermore UB to call this if any of the bytes - /// in `*a` or `*b` have provenance. - /// - /// (The implementation is allowed to branch on the results of comparisons, - /// which is UB if any of their inputs are `undef`.) - #[rustc_const_unstable(feature = "const_intrinsic_raw_eq", issue = "none")] - #[rustc_nounwind] - pub fn raw_eq(a: &T, b: &T) -> bool; +/// Determines whether the raw bytes of the two values are equal. +/// +/// This is particularly handy for arrays, since it allows things like just +/// comparing `i96`s instead of forcing `alloca`s for `[6 x i16]`. +/// +/// Above some backend-decided threshold this will emit calls to `memcmp`, +/// like slice equality does, instead of causing massive code size. +/// +/// Since this works by comparing the underlying bytes, the actual `T` is +/// not particularly important. It will be used for its size and alignment, +/// but any validity restrictions will be ignored, not enforced. +/// +/// # Safety +/// +/// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized. +/// Note that this is a stricter criterion than just the *values* being +/// fully-initialized: if `T` has padding, it's UB to call this intrinsic. +/// +/// At compile-time, it is furthermore UB to call this if any of the bytes +/// in `*a` or `*b` have provenance. +/// +/// (The implementation is allowed to branch on the results of comparisons, +/// which is UB if any of their inputs are `undef`.) +#[rustc_const_unstable(feature = "const_intrinsic_raw_eq", issue = "none")] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn raw_eq(_a: &T, _b: &T) -> bool { + unimplemented!() +} - /// Lexicographically compare `[left, left + bytes)` and `[right, right + bytes)` - /// as unsigned bytes, returning negative if `left` is less, zero if all the - /// bytes match, or positive if `left` is greater. - /// - /// This underlies things like `<[u8]>::cmp`, and will usually lower to `memcmp`. - /// - /// # Safety - /// - /// `left` and `right` must each be [valid] for reads of `bytes` bytes. - /// - /// Note that this applies to the whole range, not just until the first byte - /// that differs. That allows optimizations that can read in large chunks. - /// - /// [valid]: crate::ptr#safety - #[rustc_const_unstable(feature = "const_intrinsic_compare_bytes", issue = "none")] - #[rustc_nounwind] - pub fn compare_bytes(left: *const u8, right: *const u8, bytes: usize) -> i32; +/// Lexicographically compare `[left, left + bytes)` and `[right, right + bytes)` +/// as unsigned bytes, returning negative if `left` is less, zero if all the +/// bytes match, or positive if `left` is greater. +/// +/// This underlies things like `<[u8]>::cmp`, and will usually lower to `memcmp`. +/// +/// # Safety +/// +/// `left` and `right` must each be [valid] for reads of `bytes` bytes. +/// +/// Note that this applies to the whole range, not just until the first byte +/// that differs. That allows optimizations that can read in large chunks. +/// +/// [valid]: crate::ptr#safety +#[rustc_const_unstable(feature = "const_intrinsic_compare_bytes", issue = "none")] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn compare_bytes(_left: *const u8, _right: *const u8, _bytes: usize) -> i32 { + unimplemented!() +} - /// See documentation of [`std::hint::black_box`] for details. - /// - /// [`std::hint::black_box`]: crate::hint::black_box - #[rustc_const_unstable(feature = "const_black_box", issue = "none")] - #[rustc_safe_intrinsic] - #[rustc_nounwind] - pub fn black_box(dummy: T) -> T; +/// See documentation of [`std::hint::black_box`] for details. +/// +/// [`std::hint::black_box`]: crate::hint::black_box +#[rustc_const_unstable(feature = "const_black_box", issue = "none")] +#[rustc_nounwind] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const fn black_box(_dummy: T) -> T { + unimplemented!() } /// Selects which function to call depending on the context. @@ -3261,18 +3411,13 @@ pub const fn ptr_metadata + ?Sized, M>(_ptr: *cons #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_diagnostic_item = "ptr_copy_nonoverlapping"] pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { - extern "rust-intrinsic" { - #[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0") - )] - #[cfg_attr( - not(bootstrap), - rustc_const_unstable(feature = "core_intrinsics", issue = "none") - )] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + const unsafe fn copy_nonoverlapping(_src: *const T, _dst: *mut T, _count: usize) { + unreachable!() } ub_checks::assert_unsafe_precondition!( @@ -3373,18 +3518,13 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_diagnostic_item = "ptr_copy"] pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { - extern "rust-intrinsic" { - #[cfg_attr( - bootstrap, - rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0") - )] - #[cfg_attr( - not(bootstrap), - rustc_const_unstable(feature = "core_intrinsics", issue = "none") - )] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - fn copy(src: *const T, dst: *mut T, count: usize); + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + const unsafe fn copy(_src: *const T, _dst: *mut T, _count: usize) { + unreachable!() } // SAFETY: the safety contract for `copy` must be upheld by the caller. @@ -3462,11 +3602,13 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[rustc_diagnostic_item = "ptr_write_bytes"] pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { - extern "rust-intrinsic" { - #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] - #[rustc_nounwind] - fn write_bytes(dst: *mut T, val: u8, count: usize); + #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] + #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] + #[rustc_nounwind] + #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] + const unsafe fn write_bytes(_dst: *mut T, _val: u8, _count: usize) { + unreachable!() } // SAFETY: the safety contract for `write_bytes` must be upheld by the caller. From 10723c28964d582814ea8e07dbd8fa7367e0eaee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Nov 2024 22:19:42 +0100 Subject: [PATCH 14/18] remove support for extern-block const intrinsics --- compiler/rustc_attr/src/builtin.rs | 10 +- .../src/const_eval/fn_queries.rs | 12 +-- compiler/rustc_passes/src/stability.rs | 15 --- tests/rustdoc/const-intrinsic.rs | 28 +++--- .../closures/coerce-unsafe-to-closure.stderr | 4 +- .../ui/consts/auxiliary/unstable_intrinsic.rs | 31 ++---- .../consts/const-eval/simd/insert_extract.rs | 20 ++-- tests/ui/consts/const-unstable-intrinsic.rs | 54 +++------- .../ui/consts/const-unstable-intrinsic.stderr | 99 +++++-------------- tests/ui/consts/copy-intrinsic.rs | 20 ++-- tests/ui/consts/copy-intrinsic.stderr | 8 +- tests/ui/intrinsics/reify-intrinsic.stderr | 4 +- tests/ui/repr/16-bit-repr-c-enum.rs | 11 ++- .../missing-const-stability.rs | 6 -- tests/ui/target-feature/feature-hierarchy.rs | 10 +- tests/ui/target-feature/no-llvm-leaks.rs | 10 +- 16 files changed, 118 insertions(+), 224 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 6af75bc94bb63..2753ac529d12d 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -273,8 +273,7 @@ pub fn find_stability( /// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable` /// attributes in `attrs`. Returns `None` if no stability attributes are found. /// -/// `is_const_fn` indicates whether this is a function marked as `const`. It will always -/// be false for intrinsics in an `extern` block! +/// `is_const_fn` indicates whether this is a function marked as `const`. pub fn find_const_stability( sess: &Session, attrs: &[Attribute], @@ -330,7 +329,7 @@ pub fn find_const_stability( } } - // Merge promotable and not_exposed_on_stable into stability info + // Merge promotable and const_stable_indirect into stability info if promotable { match &mut const_stab { Some((stab, _)) => stab.promotable = promotable, @@ -352,10 +351,7 @@ pub fn find_const_stability( }) } } - _ => { - // We ignore the `#[rustc_const_stable_indirect]` here, it should be picked up by - // the `default_const_unstable` logic. - } + _ => {} } } // Make sure if `const_stable_indirect` is present, that is recorded. Also make sure all `const diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index 037fdcbcf9b4c..beff0cd99fc47 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -25,15 +25,9 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness { hir::Constness::Const } hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.constness, - hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => { - // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other - // foreign items cannot be evaluated at compile-time. - let is_const = if tcx.intrinsic(def_id).is_some() { - tcx.lookup_const_stability(def_id).is_some() - } else { - false - }; - if is_const { hir::Constness::Const } else { hir::Constness::NotConst } + hir::Node::ForeignItem(_) => { + // Foreign items cannot be evaluated at compile-time. + hir::Constness::NotConst } hir::Node::Expr(e) if let hir::ExprKind::Closure(c) = e.kind => c.constness, _ => { diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 737e163efcef1..cd47c8ece6015 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -106,7 +106,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { def_id: LocalDefId, item_sp: Span, fn_sig: Option<&'tcx hir::FnSig<'tcx>>, - is_foreign_item: bool, kind: AnnotationKind, inherit_deprecation: InheritDeprecation, inherit_const_stability: InheritConstStability, @@ -175,11 +174,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // implied), check if the function/method is const or the parent impl block is const. if let Some(fn_sig) = fn_sig && !fn_sig.header.is_const() - // We have to exclude foreign items as they might be intrinsics. Sadly we can't check - // their ABI; `fn_sig.abi` is *not* correct for foreign functions. - && !is_foreign_item && const_stab.is_some() - && (!self.in_trait_impl || !self.tcx.is_const_fn(def_id.to_def_id())) { self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span }); } @@ -398,7 +393,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ctor_def_id, i.span, None, - /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -417,7 +411,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { i.owner_id.def_id, i.span, fn_sig, - /* is_foreign_item */ false, kind, InheritDeprecation::Yes, const_stab_inherit, @@ -437,7 +430,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ti.owner_id.def_id, ti.span, fn_sig, - /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -461,7 +453,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ii.owner_id.def_id, ii.span, fn_sig, - /* is_foreign_item */ false, kind, InheritDeprecation::Yes, InheritConstStability::No, @@ -477,7 +468,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { var.def_id, var.span, None, - /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -488,7 +478,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ctor_def_id, var.span, None, - /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -507,7 +496,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { s.def_id, s.span, None, - /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -527,7 +515,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { i.owner_id.def_id, i.span, fn_sig, - /* is_foreign_item */ true, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -550,7 +537,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { p.def_id, p.span, None, - /* is_foreign_item */ false, kind, InheritDeprecation::No, InheritConstStability::No, @@ -712,7 +698,6 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID), None, - /* is_foreign_item */ false, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, diff --git a/tests/rustdoc/const-intrinsic.rs b/tests/rustdoc/const-intrinsic.rs index 520e253469c63..8444d4a3aa768 100644 --- a/tests/rustdoc/const-intrinsic.rs +++ b/tests/rustdoc/const-intrinsic.rs @@ -1,20 +1,26 @@ -#![feature(intrinsics)] +#![feature(intrinsics, rustc_attrs)] #![feature(staged_api)] #![crate_name = "foo"] #![stable(since="1.0.0", feature="rust1")] -extern "rust-intrinsic" { - //@ has 'foo/fn.transmute.html' - //@ has - '//pre[@class="rust item-decl"]' 'pub const unsafe extern "rust-intrinsic" fn transmute(_: T) -> U' - #[stable(since="1.0.0", feature="rust1")] - #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] - pub fn transmute(_: T) -> U; +//@ has 'foo/fn.transmute.html' +//@ has - '//pre[@class="rust item-decl"]' 'pub const unsafe fn transmute(_: T) -> U' +#[stable(since="1.0.0", feature="rust1")] +#[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn transmute(_: T) -> U { + loop {} +} - //@ has 'foo/fn.unreachable.html' - //@ has - '//pre[@class="rust item-decl"]' 'pub unsafe extern "rust-intrinsic" fn unreachable() -> !' - #[stable(since="1.0.0", feature="rust1")] - pub fn unreachable() -> !; +//@ has 'foo/fn.unreachable.html' +//@ has - '//pre[@class="rust item-decl"]' 'pub unsafe fn unreachable() -> !' +#[stable(since="1.0.0", feature="rust1")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub unsafe fn unreachable() -> ! { + loop {} } extern "C" { diff --git a/tests/ui/closures/coerce-unsafe-to-closure.stderr b/tests/ui/closures/coerce-unsafe-to-closure.stderr index 2538fc0361c37..013b9009da406 100644 --- a/tests/ui/closures/coerce-unsafe-to-closure.stderr +++ b/tests/ui/closures/coerce-unsafe-to-closure.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `FnOnce(&str)` closure, found `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}` +error[E0277]: expected a `FnOnce(&str)` closure, found `unsafe fn(_) -> _ {std::intrinsics::transmute::<_, _>}` --> $DIR/coerce-unsafe-to-closure.rs:2:44 | LL | let x: Option<&[u8]> = Some("foo").map(std::mem::transmute); @@ -6,7 +6,7 @@ LL | let x: Option<&[u8]> = Some("foo").map(std::mem::transmute); | | | required by a bound introduced by this call | - = help: the trait `FnOnce(&str)` is not implemented for fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}` + = help: the trait `FnOnce(&str)` is not implemented for fn item `unsafe fn(_) -> _ {std::intrinsics::transmute::<_, _>}` = note: unsafe function cannot be called generically without an unsafe block note: required by a bound in `Option::::map` --> $SRC_DIR/core/src/option.rs:LL:COL diff --git a/tests/ui/consts/auxiliary/unstable_intrinsic.rs b/tests/ui/consts/auxiliary/unstable_intrinsic.rs index edef499dbb182..0749e7e6df884 100644 --- a/tests/ui/consts/auxiliary/unstable_intrinsic.rs +++ b/tests/ui/consts/auxiliary/unstable_intrinsic.rs @@ -1,26 +1,11 @@ #![feature(staged_api, rustc_attrs, intrinsics)] #![stable(since="1.0.0", feature = "stable")] -#[stable(since="1.0.0", feature = "stable")] -pub mod old_way { - extern "rust-intrinsic" { - #[unstable(feature = "unstable", issue = "42")] - pub fn size_of_val(x: *const T) -> usize; - - #[unstable(feature = "unstable", issue = "42")] - #[rustc_const_unstable(feature = "unstable", issue = "42")] - pub fn min_align_of_val(x: *const T) -> usize; - } -} - -#[stable(since="1.0.0", feature = "stable")] -pub mod new_way { - #[unstable(feature = "unstable", issue = "42")] - #[rustc_intrinsic] - pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } - - #[unstable(feature = "unstable", issue = "42")] - #[rustc_const_unstable(feature = "unstable", issue = "42")] - #[rustc_intrinsic] - pub const unsafe fn min_align_of_val(x: *const T) -> usize { 42 } -} +#[unstable(feature = "unstable", issue = "42")] +#[rustc_intrinsic] +pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } + +#[unstable(feature = "unstable", issue = "42")] +#[rustc_const_unstable(feature = "unstable", issue = "42")] +#[rustc_intrinsic] +pub const unsafe fn min_align_of_val(x: *const T) -> usize { 42 } diff --git a/tests/ui/consts/const-eval/simd/insert_extract.rs b/tests/ui/consts/const-eval/simd/insert_extract.rs index 57d4b4888caa9..e5873ea26e8d8 100644 --- a/tests/ui/consts/const-eval/simd/insert_extract.rs +++ b/tests/ui/consts/const-eval/simd/insert_extract.rs @@ -1,6 +1,6 @@ //@ run-pass #![feature(repr_simd)] -#![feature(intrinsics)] +#![feature(intrinsics, rustc_attrs)] #![feature(staged_api)] #![stable(feature = "foo", since = "1.3.37")] #![allow(non_camel_case_types)] @@ -10,14 +10,18 @@ #[repr(simd)] struct u16x2([u16; 2]); #[repr(simd)] struct f32x4([f32; 4]); -extern "rust-intrinsic" { - #[stable(feature = "foo", since = "1.3.37")] - #[rustc_const_stable(feature = "foo", since = "1.3.37")] - fn simd_insert(x: T, idx: u32, val: U) -> T; +#[stable(feature = "foo", since = "1.3.37")] +#[rustc_const_stable(feature = "foo", since = "1.3.37")] +#[rustc_intrinsic] +const unsafe fn simd_insert(_x: T, _idx: u32, _val: U) -> T { + unimplemented!() +} - #[stable(feature = "foo", since = "1.3.37")] - #[rustc_const_stable(feature = "foo", since = "1.3.37")] - fn simd_extract(x: T, idx: u32) -> U; +#[stable(feature = "foo", since = "1.3.37")] +#[rustc_const_stable(feature = "foo", since = "1.3.37")] +#[rustc_intrinsic] +const unsafe fn simd_extract(_x: T, _idx: u32) -> U { + unimplemented!() } fn main() { diff --git a/tests/ui/consts/const-unstable-intrinsic.rs b/tests/ui/consts/const-unstable-intrinsic.rs index 5d43cdf5da6df..fbe491e067176 100644 --- a/tests/ui/consts/const-unstable-intrinsic.rs +++ b/tests/ui/consts/const-unstable-intrinsic.rs @@ -14,63 +14,39 @@ fn main() { const fn const_main() { let x = 42; unsafe { - unstable_intrinsic::old_way::size_of_val(&x); - //~^ERROR: unstable library feature `unstable` - //~|ERROR: cannot call non-const intrinsic - unstable_intrinsic::old_way::min_align_of_val(&x); - //~^ERROR: unstable library feature `unstable` - //~|ERROR: not yet stable as a const intrinsic - unstable_intrinsic::new_way::size_of_val(&x); + unstable_intrinsic::size_of_val(&x); //~^ERROR: unstable library feature `unstable` //~|ERROR: cannot be (indirectly) exposed to stable - unstable_intrinsic::new_way::min_align_of_val(&x); + unstable_intrinsic::min_align_of_val(&x); //~^ERROR: unstable library feature `unstable` //~|ERROR: not yet stable as a const intrinsic - old_way::size_of_val(&x); - //~^ERROR: cannot call non-const intrinsic - old_way::min_align_of_val(&x); - //~^ERROR: cannot use `#[feature(local)]` - new_way::size_of_val(&x); + size_of_val(&x); //~^ERROR: cannot be (indirectly) exposed to stable - new_way::min_align_of_val(&x); + min_align_of_val(&x); //~^ERROR: cannot use `#[feature(local)]` } } -#[stable(since="1.0.0", feature = "stable")] -pub mod old_way { - extern "rust-intrinsic" { - #[unstable(feature = "local", issue = "42")] - pub fn size_of_val(x: *const T) -> usize; - - #[unstable(feature = "local", issue = "42")] - #[rustc_const_unstable(feature = "local", issue = "42")] - pub fn min_align_of_val(x: *const T) -> usize; - } -} - -#[stable(since="1.0.0", feature = "stable")] -pub mod new_way { - #[unstable(feature = "local", issue = "42")] - #[rustc_intrinsic] - pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } +#[unstable(feature = "local", issue = "42")] +#[rustc_intrinsic] +pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } - #[unstable(feature = "local", issue = "42")] - #[rustc_const_unstable(feature = "local", issue = "42")] - #[rustc_intrinsic] - pub const unsafe fn min_align_of_val(x: *const T) -> usize { 42 } -} +#[unstable(feature = "local", issue = "42")] +#[rustc_const_unstable(feature = "local", issue = "42")] +#[rustc_intrinsic] +pub const unsafe fn min_align_of_val(x: *const T) -> usize { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] #[inline] pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { // Const stability attributes are not inherited from parent items. - extern "rust-intrinsic" { - fn copy(src: *const T, dst: *mut T, count: usize); + #[rustc_intrinsic] + const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { + unimplemented!() } unsafe { copy(src, dst, count) } - //~^ ERROR cannot call non-const intrinsic + //~^ ERROR cannot be (indirectly) exposed to stable } diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr index c2e38f54dc637..a997379663d6e 100644 --- a/tests/ui/consts/const-unstable-intrinsic.stderr +++ b/tests/ui/consts/const-unstable-intrinsic.stderr @@ -1,8 +1,8 @@ error[E0658]: use of unstable library feature `unstable` --> $DIR/const-unstable-intrinsic.rs:17:9 | -LL | unstable_intrinsic::old_way::size_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unstable_intrinsic::size_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #42 for more information = help: add `#![feature(unstable)]` to the crate attributes to enable @@ -11,99 +11,42 @@ LL | unstable_intrinsic::old_way::size_of_val(&x); error[E0658]: use of unstable library feature `unstable` --> $DIR/const-unstable-intrinsic.rs:20:9 | -LL | unstable_intrinsic::old_way::min_align_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #42 for more information - = help: add `#![feature(unstable)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: use of unstable library feature `unstable` - --> $DIR/const-unstable-intrinsic.rs:23:9 - | -LL | unstable_intrinsic::new_way::size_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #42 for more information - = help: add `#![feature(unstable)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: use of unstable library feature `unstable` - --> $DIR/const-unstable-intrinsic.rs:26:9 - | -LL | unstable_intrinsic::new_way::min_align_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unstable_intrinsic::min_align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #42 for more information = help: add `#![feature(unstable)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: cannot call non-const intrinsic `size_of_val` in constant functions +error: intrinsic `unstable_intrinsic::size_of_val` cannot be (indirectly) exposed to stable --> $DIR/const-unstable-intrinsic.rs:17:9 | -LL | unstable_intrinsic::old_way::size_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: `min_align_of_val` is not yet stable as a const intrinsic - --> $DIR/const-unstable-intrinsic.rs:20:9 - | -LL | unstable_intrinsic::old_way::min_align_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(unstable)]` to the crate attributes to enable - -error: intrinsic `unstable_intrinsic::new_way::size_of_val` cannot be (indirectly) exposed to stable - --> $DIR/const-unstable-intrinsic.rs:23:9 - | -LL | unstable_intrinsic::new_way::size_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unstable_intrinsic::size_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval) error: `min_align_of_val` is not yet stable as a const intrinsic - --> $DIR/const-unstable-intrinsic.rs:26:9 + --> $DIR/const-unstable-intrinsic.rs:20:9 | -LL | unstable_intrinsic::new_way::min_align_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unstable_intrinsic::min_align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(unstable)]` to the crate attributes to enable -error: cannot call non-const intrinsic `size_of_val` in constant functions - --> $DIR/const-unstable-intrinsic.rs:30:9 - | -LL | old_way::size_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - -error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]` - --> $DIR/const-unstable-intrinsic.rs:32:9 - | -LL | old_way::min_align_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) +error: intrinsic `size_of_val` cannot be (indirectly) exposed to stable + --> $DIR/const-unstable-intrinsic.rs:24:9 | -LL + #[rustc_const_unstable(feature = "...", issue = "...")] -LL | const fn const_main() { - | -help: otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) - | -LL + #[rustc_allow_const_fn_unstable(local)] -LL | const fn const_main() { - | - -error: intrinsic `new_way::size_of_val` cannot be (indirectly) exposed to stable - --> $DIR/const-unstable-intrinsic.rs:34:9 - | -LL | new_way::size_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | size_of_val(&x); + | ^^^^^^^^^^^^^^^ | = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval) error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]` - --> $DIR/const-unstable-intrinsic.rs:36:9 + --> $DIR/const-unstable-intrinsic.rs:26:9 | -LL | new_way::min_align_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | min_align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^ | help: if the function is not (yet) meant to be exposed to stable, add `#[rustc_const_unstable]` (this is what you probably want to do) | @@ -116,12 +59,14 @@ LL + #[rustc_allow_const_fn_unstable(local)] LL | const fn const_main() { | -error: cannot call non-const intrinsic `copy` in constant functions - --> $DIR/const-unstable-intrinsic.rs:74:14 +error: intrinsic `copy::copy` cannot be (indirectly) exposed to stable + --> $DIR/const-unstable-intrinsic.rs:50:14 | LL | unsafe { copy(src, dst, count) } | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval) -error: aborting due to 13 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/copy-intrinsic.rs b/tests/ui/consts/copy-intrinsic.rs index 62917c0b98b2c..08fbcc107e7ec 100644 --- a/tests/ui/consts/copy-intrinsic.rs +++ b/tests/ui/consts/copy-intrinsic.rs @@ -1,17 +1,21 @@ #![stable(feature = "dummy", since = "1.0.0")] // ignore-tidy-linelength -#![feature(intrinsics, staged_api)] +#![feature(intrinsics, staged_api, rustc_attrs)] use std::mem; -extern "rust-intrinsic" { - #[stable(feature = "dummy", since = "1.0.0")] - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] - fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); +#[stable(feature = "dummy", since = "1.0.0")] +#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] +#[rustc_intrinsic] +const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { + unimplemented!() +} - #[stable(feature = "dummy", since = "1.0.0")] - #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] - fn copy(src: *const T, dst: *mut T, count: usize); +#[stable(feature = "dummy", since = "1.0.0")] +#[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] +#[rustc_intrinsic] +const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { + unimplemented!() } const COPY_ZERO: () = unsafe { diff --git a/tests/ui/consts/copy-intrinsic.stderr b/tests/ui/consts/copy-intrinsic.stderr index 29a88f6270bc6..41af3a2cd2dc2 100644 --- a/tests/ui/consts/copy-intrinsic.stderr +++ b/tests/ui/consts/copy-intrinsic.stderr @@ -1,23 +1,23 @@ error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:30:5 + --> $DIR/copy-intrinsic.rs:34:5 | LL | copy_nonoverlapping(0x100 as *const i32, dangle, 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x100[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:39:5 + --> $DIR/copy-intrinsic.rs:43:5 | LL | copy_nonoverlapping(dangle, 0x100 as *mut i32, 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:46:5 + --> $DIR/copy-intrinsic.rs:50:5 | LL | copy(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy` error[E0080]: evaluation of constant value failed - --> $DIR/copy-intrinsic.rs:52:5 + --> $DIR/copy-intrinsic.rs:56:5 | LL | copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::() * 8 - 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy_nonoverlapping` diff --git a/tests/ui/intrinsics/reify-intrinsic.stderr b/tests/ui/intrinsics/reify-intrinsic.stderr index 21b7bf4e1cb83..7af17147f28f0 100644 --- a/tests/ui/intrinsics/reify-intrinsic.stderr +++ b/tests/ui/intrinsics/reify-intrinsic.stderr @@ -7,9 +7,9 @@ LL | let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::tr | expected due to this | = note: expected fn pointer `unsafe extern "rust-intrinsic" fn(isize) -> usize` - found fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}` + found fn item `unsafe fn(_) -> _ {std::intrinsics::transmute::<_, _>}` -error[E0606]: casting `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}` as `unsafe extern "rust-intrinsic" fn(isize) -> usize` is invalid +error[E0606]: casting `unsafe fn(_) -> _ {std::intrinsics::transmute::<_, _>}` as `unsafe extern "rust-intrinsic" fn(isize) -> usize` is invalid --> $DIR/reify-intrinsic.rs:11:13 | LL | let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) -> usize; diff --git a/tests/ui/repr/16-bit-repr-c-enum.rs b/tests/ui/repr/16-bit-repr-c-enum.rs index 2509416ad87d4..2b6bbf1265083 100644 --- a/tests/ui/repr/16-bit-repr-c-enum.rs +++ b/tests/ui/repr/16-bit-repr-c-enum.rs @@ -21,11 +21,12 @@ enum Foo { Bar, } -extern "rust-intrinsic" { - #[stable(feature = "intrinsics_for_test", since = "3.3.3")] - #[rustc_const_stable(feature = "intrinsics_for_test", since = "3.3.3")] - #[rustc_safe_intrinsic] - fn size_of() -> usize; +#[stable(feature = "intrinsics_for_test", since = "3.3.3")] +#[rustc_const_stable(feature = "intrinsics_for_test", since = "3.3.3")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +const fn size_of() -> usize { + loop {} } #[lang="sized"] diff --git a/tests/ui/stability-attribute/missing-const-stability.rs b/tests/ui/stability-attribute/missing-const-stability.rs index 6d49996c3b5e9..10c31d7943866 100644 --- a/tests/ui/stability-attribute/missing-const-stability.rs +++ b/tests/ui/stability-attribute/missing-const-stability.rs @@ -36,10 +36,4 @@ impl const Bar for Foo { pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } //~^ ERROR function has missing const stability attribute -extern "rust-intrinsic" { - #[stable(feature = "stable", since = "1.0.0")] - #[rustc_const_stable_indirect] - pub fn min_align_of_val(x: *const T) -> usize; -} - fn main() {} diff --git a/tests/ui/target-feature/feature-hierarchy.rs b/tests/ui/target-feature/feature-hierarchy.rs index 7f14d700ecba6..d62b86693c2ce 100644 --- a/tests/ui/target-feature/feature-hierarchy.rs +++ b/tests/ui/target-feature/feature-hierarchy.rs @@ -18,10 +18,12 @@ trait Sized {} trait Copy {} impl Copy for bool {} -extern "rust-intrinsic" { - #[stable(feature = "test", since = "1.0.0")] - #[rustc_const_stable(feature = "test", since = "1.0.0")] - fn unreachable() -> !; +#[stable(feature = "test", since = "1.0.0")] +#[rustc_const_stable(feature = "test", since = "1.0.0")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +const unsafe fn unreachable() -> ! { + loop {} } #[rustc_builtin_macro] diff --git a/tests/ui/target-feature/no-llvm-leaks.rs b/tests/ui/target-feature/no-llvm-leaks.rs index f0c887bc1e0ff..102686864050a 100644 --- a/tests/ui/target-feature/no-llvm-leaks.rs +++ b/tests/ui/target-feature/no-llvm-leaks.rs @@ -16,10 +16,12 @@ trait Sized {} trait Copy {} impl Copy for bool {} -extern "rust-intrinsic" { - #[stable(feature = "test", since = "1.0.0")] - #[rustc_const_stable(feature = "test", since = "1.0.0")] - fn unreachable() -> !; +#[stable(feature = "test", since = "1.0.0")] +#[rustc_const_stable(feature = "test", since = "1.0.0")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +const unsafe fn unreachable() -> ! { + loop {} } #[rustc_builtin_macro] From 1f0ed2b0f54aff2dbc63ff72261b8acb2c186404 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Nov 2024 22:53:59 +0100 Subject: [PATCH 15/18] add new rustc_const_stable_intrinsic attribute for const-stable intrinsics --- compiler/rustc_const_eval/messages.ftl | 2 +- .../src/check_consts/check.rs | 13 +- .../rustc_const_eval/src/check_consts/ops.rs | 4 +- compiler/rustc_feature/src/builtin_attrs.rs | 4 + compiler/rustc_middle/src/ty/intrinsic.rs | 2 + compiler/rustc_middle/src/ty/util.rs | 2 + compiler/rustc_span/src/symbol.rs | 1 + library/core/src/intrinsics.rs | 114 +++++++++--------- .../ui/consts/const-unstable-intrinsic.stderr | 6 +- 9 files changed, 80 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 2bc5adb2dce60..826e34930eae7 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -399,7 +399,7 @@ const_eval_uninhabited_enum_variant_written = const_eval_unmarked_const_fn_exposed = `{$def_path}` cannot be (indirectly) exposed to stable .help = either mark the callee as `#[rustc_const_stable_indirect]`, or the caller as `#[rustc_const_unstable]` const_eval_unmarked_intrinsic_exposed = intrinsic `{$def_path}` cannot be (indirectly) exposed to stable - .help = mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval) + .help = mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval) const_eval_unreachable = entering unreachable code const_eval_unreachable_unwind = diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 8cb7e02036fd8..1c17421e78218 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -736,16 +736,19 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // Intrinsics are language primitives, not regular calls, so treat them separately. if let Some(intrinsic) = tcx.intrinsic(callee) { + // We use `intrinsic.const_stable` to determine if this can be safely exposed to + // stable code, rather than `const_stable_indirect`. This is to make + // `#[rustc_const_stable_indirect]` an attribute that is always safe to add. match tcx.lookup_const_stability(callee) { None => { // Non-const intrinsic. self.check_op(ops::IntrinsicNonConst { name: intrinsic.name }); } - Some(ConstStability { feature: None, const_stable_indirect, .. }) => { + Some(ConstStability { feature: None, .. }) => { // Intrinsic does not need a separate feature gate (we rely on the // regular stability checker). However, we have to worry about recursive // const stability. - if !const_stable_indirect && self.enforce_recursive_const_stability() { + if !intrinsic.const_stable && self.enforce_recursive_const_stability() { self.dcx().emit_err(errors::UnmarkedIntrinsicExposed { span: self.span, def_path: self.tcx.def_path_str(callee), @@ -755,17 +758,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Some(ConstStability { feature: Some(feature), level: StabilityLevel::Unstable { .. }, - const_stable_indirect, .. }) => { self.check_op(ops::IntrinsicUnstable { name: intrinsic.name, feature, - const_stable_indirect, + const_stable: intrinsic.const_stable, }); } Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => { - // All good. + // All good. But ensure this is indeed a const-stable intrinsic. + assert!(intrinsic.const_stable); } } // This completes the checks for intrinsics. diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index d264cab1511b9..2931159842f95 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -354,14 +354,14 @@ impl<'tcx> NonConstOp<'tcx> for IntrinsicNonConst { pub(crate) struct IntrinsicUnstable { pub name: Symbol, pub feature: Symbol, - pub const_stable_indirect: bool, + pub const_stable: bool, } impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable { fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status { Status::Unstable { gate: self.feature, - safe_to_expose_on_stable: self.const_stable_indirect, + safe_to_expose_on_stable: self.const_stable, // We do *not* want to suggest to mark the intrinsic as `const_stable_indirect`, // that's not a trivial change! is_function_call: false, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 0069b07ad6259..cc0bdec701929 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -837,6 +837,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_const_stable_indirect, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL, ), + rustc_attr!( + rustc_const_stable_intrinsic, Normal, + template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL, + ), gated!( rustc_allow_const_fn_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, EncodeCrossCrate::No, diff --git a/compiler/rustc_middle/src/ty/intrinsic.rs b/compiler/rustc_middle/src/ty/intrinsic.rs index ed0fb37d3b897..6a3ddacb424e8 100644 --- a/compiler/rustc_middle/src/ty/intrinsic.rs +++ b/compiler/rustc_middle/src/ty/intrinsic.rs @@ -9,6 +9,8 @@ pub struct IntrinsicDef { pub name: Symbol, /// Whether the intrinsic has no meaningful body and all backends need to shim all calls to it. pub must_be_overridden: bool, + /// Whether the intrinsic can be invoked from stable const fn + pub const_stable: bool, } impl TyCtxt<'_> { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 83276808a28e6..b5811824683a8 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1789,6 +1789,8 @@ pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option to -//! and add a -//! `#[rustc_const_unstable(feature = "const_such_and_such", issue = "01234")]` to the intrinsic declaration. +//! In order to make an intrinsic usable at compile-time, it needs to be declared in the "new" +//! style, i.e. as a `#[rustc_intrinsic]` function, not inside an `extern` block. Then copy the +//! implementation from to +//! +//! and make the intrinsic declaration a `const fn`. //! //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute, -//! `#[rustc_const_stable_indirect]` needs to be added to the intrinsic (`#[rustc_const_unstable]` -//! can be removed then). Such a change should not be done without T-lang consultation, because it -//! may bake a feature into the language that cannot be replicated in user code without compiler -//! support. +//! `#[rustc_const_stable_intrinsic]` needs to be added to the intrinsic. Such a change requires +//! T-lang approval, because it may bake a feature into the language that cannot be replicated in +//! user code without compiler support. //! //! # Volatiles //! @@ -955,7 +955,7 @@ extern "rust-intrinsic" { bootstrap, rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0") )] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -974,7 +974,7 @@ pub const unsafe fn unreachable() -> ! { /// /// The stabilized version of this intrinsic is [`core::hint::assert_unchecked`]. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assume", since = "1.77.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] @@ -1000,7 +1000,7 @@ pub const unsafe fn assume(b: bool) { bootstrap, rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION") )] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] #[rustc_nounwind] @@ -1024,7 +1024,7 @@ pub const fn likely(b: bool) -> bool { bootstrap, rustc_const_stable(feature = "const_likely", since = "CURRENT_RUSTC_VERSION") )] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] #[rustc_nounwind] @@ -1059,7 +1059,7 @@ pub fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { /// /// This intrinsic does not have a stable counterpart. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type", since = "1.59.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1072,7 +1072,7 @@ pub const fn assert_inhabited() { /// /// This intrinsic does not have a stable counterpart. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1084,7 +1084,7 @@ pub const fn assert_zero_valid() { /// /// This intrinsic does not have a stable counterpart. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_assert_type2", since = "1.75.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1101,7 +1101,7 @@ pub const fn assert_mem_uninitialized_valid() { /// /// Consider using [`core::panic::Location::caller`] instead. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_caller_location", since = "1.79.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1119,7 +1119,7 @@ pub const fn caller_location() -> &'static crate::panic::Location<'static> { /// Therefore, implementations must not require the user to uphold /// any safety invariants. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_forget", since = "1.83.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1433,7 +1433,7 @@ pub const unsafe fn transmute(_src: Src) -> Dst { /// This is not expected to ever be exposed directly to users, rather it /// may eventually be exposed through some more-constrained API. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_transmute", since = "1.56.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1455,7 +1455,7 @@ pub const unsafe fn transmute_unchecked(_src: Src) -> Dst { /// /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop). #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_needs_drop", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1481,7 +1481,7 @@ pub const fn needs_drop() -> bool { /// The stabilized version of this intrinsic is [`pointer::offset`]. #[must_use = "returns a new pointer rather than modifying its argument"] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -1504,7 +1504,7 @@ pub const unsafe fn offset(_dst: Ptr, _offset: Delta) -> Ptr { /// The stabilized version of this intrinsic is [`pointer::wrapping_offset`]. #[must_use = "returns a new pointer rather than modifying its argument"] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2194,7 +2194,7 @@ extern "rust-intrinsic" { /// primitives via the `count_ones` method. For example, /// [`u32::count_ones`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctpop", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2239,7 +2239,7 @@ pub const fn ctpop(_x: T) -> u32 { /// assert_eq!(num_leading, 16); /// ``` #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ctlz", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2265,7 +2265,7 @@ pub const fn ctlz(_x: T) -> u32 { /// assert_eq!(num_leading, 3); /// ``` #[cfg_attr(bootstrap, rustc_const_stable(feature = "constctlz", since = "1.50.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2310,7 +2310,7 @@ pub const unsafe fn ctlz_nonzero(_x: T) -> u32 { /// assert_eq!(num_trailing, 16); /// ``` #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2336,7 +2336,7 @@ pub const fn cttz(_x: T) -> u32 { /// assert_eq!(num_trailing, 3); /// ``` #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_cttz_nonzero", since = "1.53.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2355,7 +2355,7 @@ pub const unsafe fn cttz_nonzero(_x: T) -> u32 { /// primitives via the `swap_bytes` method. For example, /// [`u32::swap_bytes`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bswap", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2374,7 +2374,7 @@ pub const fn bswap(_x: T) -> T { /// primitives via the `reverse_bits` method. For example, /// [`u32::reverse_bits`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_bitreverse", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2407,7 +2407,7 @@ pub const fn three_way_compare(_lhs: T, _rhss: T) -> crate::cmp::Orderi /// primitives via the `overflowing_add` method. For example, /// [`u32::overflowing_add`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2426,7 +2426,7 @@ pub const fn add_with_overflow(_x: T, _y: T) -> (T, bool) { /// primitives via the `overflowing_sub` method. For example, /// [`u32::overflowing_sub`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2445,7 +2445,7 @@ pub const fn sub_with_overflow(_x: T, _y: T) -> (T, bool) { /// primitives via the `overflowing_mul` method. For example, /// [`u32::overflowing_mul`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_overflow", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2472,7 +2472,7 @@ pub const unsafe fn exact_div(_x: T, _y: T) -> T { /// primitives via the `checked_div` method. For example, /// [`u32::checked_div`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked_div", since = "1.52.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2486,7 +2486,7 @@ pub const unsafe fn unchecked_div(_x: T, _y: T) -> T { /// primitives via the `checked_rem` method. For example, /// [`u32::checked_rem`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked_rem", since = "1.52.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2501,7 +2501,7 @@ pub const unsafe fn unchecked_rem(_x: T, _y: T) -> T { /// primitives via the `checked_shl` method. For example, /// [`u32::checked_shl`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2515,7 +2515,7 @@ pub const unsafe fn unchecked_shl(_x: T, _y: U) -> T { /// primitives via the `checked_shr` method. For example, /// [`u32::checked_shr`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_unchecked", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2529,7 +2529,7 @@ pub const unsafe fn unchecked_shr(_x: T, _y: U) -> T { /// The stable counterpart of this intrinsic is `unchecked_add` on the various /// integer types, such as [`u16::unchecked_add`] and [`i64::unchecked_add`]. #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2543,7 +2543,7 @@ pub const unsafe fn unchecked_add(_x: T, _y: T) -> T { /// The stable counterpart of this intrinsic is `unchecked_sub` on the various /// integer types, such as [`u16::unchecked_sub`] and [`i64::unchecked_sub`]. #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2557,7 +2557,7 @@ pub const unsafe fn unchecked_sub(_x: T, _y: T) -> T { /// The stable counterpart of this intrinsic is `unchecked_mul` on the various /// integer types, such as [`u16::unchecked_mul`] and [`i64::unchecked_mul`]. #[cfg_attr(bootstrap, rustc_const_stable(feature = "unchecked_math", since = "1.79.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2576,7 +2576,7 @@ pub const unsafe fn unchecked_mul(_x: T, _y: T) -> T { /// primitives via the `rotate_left` method. For example, /// [`u32::rotate_left`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2595,7 +2595,7 @@ pub const fn rotate_left(_x: T, _shift: u32) -> T { /// primitives via the `rotate_right` method. For example, /// [`u32::rotate_right`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_rotate", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2614,7 +2614,7 @@ pub const fn rotate_right(_x: T, _shift: u32) -> T { /// primitives via the `wrapping_add` method. For example, /// [`u32::wrapping_add`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2632,7 +2632,7 @@ pub const fn wrapping_add(_a: T, _b: T) -> T { /// primitives via the `wrapping_sub` method. For example, /// [`u32::wrapping_sub`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2650,7 +2650,7 @@ pub const fn wrapping_sub(_a: T, _b: T) -> T { /// primitives via the `wrapping_mul` method. For example, /// [`u32::wrapping_mul`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_wrapping", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2669,7 +2669,7 @@ pub const fn wrapping_mul(_a: T, _b: T) -> T { /// primitives via the `saturating_add` method. For example, /// [`u32::saturating_add`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2687,7 +2687,7 @@ pub const fn saturating_add(_a: T, _b: T) -> T { /// primitives via the `saturating_sub` method. For example, /// [`u32::saturating_sub`] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_int_saturating", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2702,7 +2702,7 @@ pub const fn saturating_sub(_a: T, _b: T) -> T { /// projections (`read_via_copy(ptr)`, not `read_via_copy(*ptr)`) so that it /// trivially obeys runtime-MIR rules about derefs in operands. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_read", since = "1.71.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2717,7 +2717,7 @@ pub const unsafe fn read_via_copy(_ptr: *const T) -> T { /// projections (`write_via_move(ptr, x)`, not `write_via_move(*ptr, x)`) so /// that it trivially obeys runtime-MIR rules about derefs in operands. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2735,7 +2735,7 @@ pub const unsafe fn write_via_move(_ptr: *mut T, _value: T) { /// /// The stabilized version of this intrinsic is [`core::mem::discriminant`]. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_discriminant", since = "1.75.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2775,7 +2775,7 @@ extern "rust-intrinsic" { /// See documentation of `<*const T>::offset_from` for details. #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_offset_from", since = "1.65.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3058,7 +3058,7 @@ pub const unsafe fn typed_swap(x: *mut T, y: *mut T) { /// user has UB checks disabled, the checks will still get optimized out. This intrinsic is /// primarily used by [`ub_checks::assert_unsafe_precondition`]. #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] // just for UB checks +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] // just for UB checks #[unstable(feature = "core_intrinsics", issue = "none")] #[inline(always)] #[rustc_intrinsic] @@ -3144,7 +3144,7 @@ pub unsafe fn vtable_align(_ptr: *const ()) -> usize { #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_size_of", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn size_of() -> usize { @@ -3162,7 +3162,7 @@ pub const fn size_of() -> usize { #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_min_align_of", since = "1.40.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn min_align_of() -> usize { @@ -3276,7 +3276,7 @@ pub const fn type_id() -> u128 { #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0"))] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn aggregate_raw_ptr, D, M>(_data: D, _meta: M) -> P { @@ -3305,7 +3305,7 @@ impl AggregateRawPtr<*mut T> for *mut P { bootstrap, cfg_attr(bootstrap, rustc_const_stable(feature = "ptr_metadata_const", since = "1.83.0")) )] -#[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] +#[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn ptr_metadata + ?Sized, M>(_ptr: *const P) -> M { @@ -3412,7 +3412,7 @@ pub const fn ptr_metadata + ?Sized, M>(_ptr: *cons #[rustc_diagnostic_item = "ptr_copy_nonoverlapping"] pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] + #[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3519,7 +3519,7 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us #[rustc_diagnostic_item = "ptr_copy"] pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] + #[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3603,7 +3603,7 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { #[rustc_diagnostic_item = "ptr_write_bytes"] pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_ptr_write", since = "1.83.0"))] - #[cfg_attr(not(bootstrap), rustc_const_stable_indirect)] + #[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr index a997379663d6e..2cf76732cf2cc 100644 --- a/tests/ui/consts/const-unstable-intrinsic.stderr +++ b/tests/ui/consts/const-unstable-intrinsic.stderr @@ -24,7 +24,7 @@ error: intrinsic `unstable_intrinsic::size_of_val` cannot be (indirectly) expose LL | unstable_intrinsic::size_of_val(&x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval) + = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval) error: `min_align_of_val` is not yet stable as a const intrinsic --> $DIR/const-unstable-intrinsic.rs:20:9 @@ -40,7 +40,7 @@ error: intrinsic `size_of_val` cannot be (indirectly) exposed to stable LL | size_of_val(&x); | ^^^^^^^^^^^^^^^ | - = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval) + = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval) error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]` --> $DIR/const-unstable-intrinsic.rs:26:9 @@ -65,7 +65,7 @@ error: intrinsic `copy::copy` cannot be (indirectly) exposed to stable LL | unsafe { copy(src, dst, count) } | ^^^^^^^^^^^^^^^^^^^^^ | - = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_indirect]` (but this requires team approval) + = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval) error: aborting due to 7 previous errors From 5069434c816aa13ffd2807cf95133ade5a9306df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Nov 2024 08:25:30 +0100 Subject: [PATCH 16/18] most const intrinsics don't need an explicit rustc_const_unstable any more --- library/core/src/intrinsics.rs | 74 +++++++++---------- library/core/src/lib.rs | 2 +- library/core/tests/lib.rs | 2 +- tests/ui/consts/const-compare-bytes-ub.rs | 1 - tests/ui/consts/const-compare-bytes-ub.stderr | 16 ++-- tests/ui/consts/const-compare-bytes.rs | 1 - .../intrinsics/intrinsic-raw_eq-const-bad.rs | 1 - .../intrinsic-raw_eq-const-bad.stderr | 6 +- tests/ui/intrinsics/intrinsic-raw_eq-const.rs | 1 - 9 files changed, 46 insertions(+), 58 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 4458a822d733e..c0d4a1eb34dcb 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2389,7 +2389,7 @@ pub const fn bitreverse(_x: T) -> T { /// large and difficult to optimize. /// /// The stabilized version of this intrinsic is [`Ord::cmp`]. -#[rustc_const_unstable(feature = "const_three_way_compare", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_three_way_compare", issue = "none"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn three_way_compare(_lhs: T, _rhss: T) -> crate::cmp::Ordering { @@ -2457,7 +2457,7 @@ pub const fn mul_with_overflow(_x: T, _y: T) -> (T, bool) { /// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1` /// /// This intrinsic does not have a stable counterpart. -#[rustc_const_unstable(feature = "const_exact_div", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_exact_div", issue = "none"))] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2784,7 +2784,7 @@ pub const unsafe fn ptr_offset_from(_ptr: *const T, _base: *const T) -> isize } /// See documentation of `<*const T>::sub_ptr` for details. -#[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892"))] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2796,8 +2796,7 @@ pub const unsafe fn ptr_offset_from_unsigned(_ptr: *const T, _base: *const T) /// Returns `2` if the result is unknown. /// Returns `1` if the pointers are guaranteed equal /// Returns `0` if the pointers are guaranteed inequal -#[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] -#[unstable(feature = "core_intrinsics", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020"))] #[rustc_intrinsic] #[rustc_nounwind] #[rustc_do_not_const_check] @@ -2830,7 +2829,7 @@ pub const fn ptr_guaranteed_cmp(ptr: *const T, other: *const T) -> u8 { /// /// (The implementation is allowed to branch on the results of comparisons, /// which is UB if any of their inputs are `undef`.) -#[rustc_const_unstable(feature = "const_intrinsic_raw_eq", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_intrinsic_raw_eq", issue = "none"))] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2852,7 +2851,10 @@ pub const unsafe fn raw_eq(_a: &T, _b: &T) -> bool { /// that differs. That allows optimizations that can read in large chunks. /// /// [valid]: crate::ptr#safety -#[rustc_const_unstable(feature = "const_intrinsic_compare_bytes", issue = "none")] +#[cfg_attr( + bootstrap, + rustc_const_unstable(feature = "const_intrinsic_compare_bytes", issue = "none") +)] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -2863,7 +2865,7 @@ pub const unsafe fn compare_bytes(_left: *const u8, _right: *const u8, _bytes: u /// See documentation of [`std::hint::black_box`] for details. /// /// [`std::hint::black_box`]: crate::hint::black_box -#[rustc_const_unstable(feature = "const_black_box", issue = "none")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_black_box", issue = "none"))] #[rustc_nounwind] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] @@ -3036,7 +3038,7 @@ pub const fn is_val_statically_known(_arg: T) -> bool { #[rustc_nounwind] #[inline] #[rustc_intrinsic] -// This has fallback `const fn` MIR, so shouldn't need stability, see #122652 +// Const-unstable because `swap_nonoverlapping` is const-unstable. #[rustc_const_unstable(feature = "const_typed_swap", issue = "none")] pub const unsafe fn typed_swap(x: *mut T, y: *mut T) { // SAFETY: The caller provided single non-overlapping items behind @@ -3059,7 +3061,6 @@ pub const unsafe fn typed_swap(x: *mut T, y: *mut T) { /// primarily used by [`ub_checks::assert_unsafe_precondition`]. #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ub_checks", issue = "none"))] #[cfg_attr(not(bootstrap), rustc_const_stable_intrinsic)] // just for UB checks -#[unstable(feature = "core_intrinsics", issue = "none")] #[inline(always)] #[rustc_intrinsic] pub const fn ub_checks() -> bool { @@ -3075,7 +3076,6 @@ pub const fn ub_checks() -> bool { /// - At compile time, a compile error occurs if this constraint is violated. /// - At runtime, it is not checked. #[rustc_const_unstable(feature = "const_heap", issue = "79597")] -#[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_nounwind] #[rustc_intrinsic] #[miri::intrinsic_fallback_is_spec] @@ -3175,7 +3175,7 @@ pub const fn min_align_of() -> usize { /// It's "tracking issue" is [#91971](https://github.com/rust-lang/rust/issues/91971). #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "const_pref_align_of", issue = "91971")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_pref_align_of", issue = "91971"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn pref_align_of() -> usize { @@ -3193,7 +3193,7 @@ pub const unsafe fn pref_align_of() -> usize { /// The to-be-stabilized version of this intrinsic is [`crate::mem::variant_count`]. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "variant_count", issue = "73662")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "variant_count", issue = "73662"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn variant_count() -> usize { @@ -3209,7 +3209,7 @@ pub const fn variant_count() -> usize { /// See [`crate::mem::size_of_val_raw`] for safety conditions. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_size_of_val", issue = "46571"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn size_of_val(_ptr: *const T) -> usize { @@ -3225,7 +3225,7 @@ pub const unsafe fn size_of_val(_ptr: *const T) -> usize { /// See [`crate::mem::align_of_val_raw`] for safety conditions. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "const_align_of_val", issue = "46571")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_align_of_val", issue = "46571"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn min_align_of_val(_ptr: *const T) -> usize { @@ -3242,7 +3242,7 @@ pub const unsafe fn min_align_of_val(_ptr: *const T) -> usize { /// The stabilized version of this intrinsic is [`core::any::type_name`]. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "const_type_name", issue = "63084")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_type_name", issue = "63084"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn type_name() -> &'static str { @@ -3261,7 +3261,7 @@ pub const fn type_name() -> &'static str { /// The stabilized version of this intrinsic is [`core::any::TypeId::of`]. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "const_type_id", issue = "77125")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_type_id", issue = "77125"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn type_id() -> u128 { @@ -3636,8 +3636,7 @@ pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { /// The stabilized version of this intrinsic is /// [`f16::min`] #[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f16", issue = "116909")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f16", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn minnumf16(_x: f16, _y: f16) -> f16 { @@ -3654,7 +3653,7 @@ pub const fn minnumf16(_x: f16, _y: f16) -> f16 { /// The stabilized version of this intrinsic is /// [`f32::min`] #[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_float_methods", issue = "130843"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn minnumf32(_x: f32, _y: f32) -> f32 { @@ -3671,7 +3670,7 @@ pub const fn minnumf32(_x: f32, _y: f32) -> f32 { /// The stabilized version of this intrinsic is /// [`f64::min`] #[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_float_methods", issue = "130843"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn minnumf64(_x: f64, _y: f64) -> f64 { @@ -3688,8 +3687,7 @@ pub const fn minnumf64(_x: f64, _y: f64) -> f64 { /// The stabilized version of this intrinsic is /// [`f128::min`] #[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f128", issue = "116909")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f128", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn minnumf128(_x: f128, _y: f128) -> f128 { @@ -3706,8 +3704,7 @@ pub const fn minnumf128(_x: f128, _y: f128) -> f128 { /// The stabilized version of this intrinsic is /// [`f16::max`] #[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f16", issue = "116909")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f16", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn maxnumf16(_x: f16, _y: f16) -> f16 { @@ -3724,7 +3721,7 @@ pub const fn maxnumf16(_x: f16, _y: f16) -> f16 { /// The stabilized version of this intrinsic is /// [`f32::max`] #[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_float_methods", issue = "130843"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn maxnumf32(_x: f32, _y: f32) -> f32 { @@ -3741,7 +3738,7 @@ pub const fn maxnumf32(_x: f32, _y: f32) -> f32 { /// The stabilized version of this intrinsic is /// [`f64::max`] #[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_float_methods", issue = "130843"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn maxnumf64(_x: f64, _y: f64) -> f64 { @@ -3758,8 +3755,7 @@ pub const fn maxnumf64(_x: f64, _y: f64) -> f64 { /// The stabilized version of this intrinsic is /// [`f128::max`] #[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f128", issue = "116909")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f128", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn maxnumf128(_x: f128, _y: f128) -> f128 { @@ -3771,8 +3767,7 @@ pub const fn maxnumf128(_x: f128, _y: f128) -> f128 { /// The stabilized version of this intrinsic is /// [`f16::abs`](../../std/primitive.f16.html#method.abs) #[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f16", issue = "116909")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f16", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn fabsf16(_x: f16) -> f16 { @@ -3784,7 +3779,7 @@ pub const unsafe fn fabsf16(_x: f16) -> f16 { /// The stabilized version of this intrinsic is /// [`f32::abs`](../../std/primitive.f32.html#method.abs) #[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_float_methods", issue = "130843"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn fabsf32(_x: f32) -> f32 { @@ -3796,7 +3791,7 @@ pub const unsafe fn fabsf32(_x: f32) -> f32 { /// The stabilized version of this intrinsic is /// [`f64::abs`](../../std/primitive.f64.html#method.abs) #[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_float_methods", issue = "130843"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn fabsf64(_x: f64) -> f64 { @@ -3808,8 +3803,7 @@ pub const unsafe fn fabsf64(_x: f64) -> f64 { /// The stabilized version of this intrinsic is /// [`f128::abs`](../../std/primitive.f128.html#method.abs) #[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f128", issue = "116909")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f128", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn fabsf128(_x: f128) -> f128 { @@ -3821,8 +3815,7 @@ pub const unsafe fn fabsf128(_x: f128) -> f128 { /// The stabilized version of this intrinsic is /// [`f16::copysign`](../../std/primitive.f16.html#method.copysign) #[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f16", issue = "116909")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f16", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn copysignf16(_x: f16, _y: f16) -> f16 { @@ -3834,7 +3827,7 @@ pub const unsafe fn copysignf16(_x: f16, _y: f16) -> f16 { /// The stabilized version of this intrinsic is /// [`f32::copysign`](../../std/primitive.f32.html#method.copysign) #[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_float_methods", issue = "130843"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn copysignf32(_x: f32, _y: f32) -> f32 { @@ -3845,7 +3838,7 @@ pub const unsafe fn copysignf32(_x: f32, _y: f32) -> f32 { /// The stabilized version of this intrinsic is /// [`f64::copysign`](../../std/primitive.f64.html#method.copysign) #[rustc_nounwind] -#[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_float_methods", issue = "130843"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn copysignf64(_x: f64, _y: f64) -> f64 { @@ -3857,8 +3850,7 @@ pub const unsafe fn copysignf64(_x: f64, _y: f64) -> f64 { /// The stabilized version of this intrinsic is /// [`f128::copysign`](../../std/primitive.f128.html#method.copysign) #[rustc_nounwind] -// #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")] -#[rustc_const_unstable(feature = "f128", issue = "116909")] +#[cfg_attr(bootstrap, rustc_const_unstable(feature = "f128", issue = "116909"))] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const unsafe fn copysignf128(_x: f128, _y: f128) -> f128 { diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 12f6997dbeae7..444f733adff00 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -107,6 +107,7 @@ // // Library features: // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(const_exact_div))] #![cfg_attr(bootstrap, feature(const_fmt_arguments_new))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] @@ -116,7 +117,6 @@ #![feature(const_black_box)] #![feature(const_char_encode_utf16)] #![feature(const_eval_select)] -#![feature(const_exact_div)] #![feature(const_float_methods)] #![feature(const_heap)] #![feature(const_nonnull_new)] diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 0c5bf58564781..b9706ea2a9e35 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -1,4 +1,5 @@ // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(const_three_way_compare))] #![cfg_attr(bootstrap, feature(strict_provenance))] #![cfg_attr(not(bootstrap), feature(strict_provenance_lints))] #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] @@ -22,7 +23,6 @@ #![feature(const_nonnull_new)] #![feature(const_option_ext)] #![feature(const_pin_2)] -#![feature(const_three_way_compare)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] diff --git a/tests/ui/consts/const-compare-bytes-ub.rs b/tests/ui/consts/const-compare-bytes-ub.rs index 903ba15e62291..9dafae1efd1a6 100644 --- a/tests/ui/consts/const-compare-bytes-ub.rs +++ b/tests/ui/consts/const-compare-bytes-ub.rs @@ -1,7 +1,6 @@ //@ check-fail #![feature(core_intrinsics)] -#![feature(const_intrinsic_compare_bytes)] use std::intrinsics::compare_bytes; use std::mem::MaybeUninit; diff --git a/tests/ui/consts/const-compare-bytes-ub.stderr b/tests/ui/consts/const-compare-bytes-ub.stderr index 7f83dee640969..9ef5c8ad43a1c 100644 --- a/tests/ui/consts/const-compare-bytes-ub.stderr +++ b/tests/ui/consts/const-compare-bytes-ub.stderr @@ -1,47 +1,47 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const-compare-bytes-ub.rs:10:9 + --> $DIR/const-compare-bytes-ub.rs:9:9 | LL | compare_bytes(0 as *const u8, 2 as *const u8, 1) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got a null pointer error[E0080]: evaluation of constant value failed - --> $DIR/const-compare-bytes-ub.rs:14:9 + --> $DIR/const-compare-bytes-ub.rs:13:9 | LL | compare_bytes(1 as *const u8, 0 as *const u8, 1) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed - --> $DIR/const-compare-bytes-ub.rs:18:9 + --> $DIR/const-compare-bytes-ub.rs:17:9 | LL | compare_bytes(1 as *const u8, 2 as *const u8, 1) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed - --> $DIR/const-compare-bytes-ub.rs:22:9 + --> $DIR/const-compare-bytes-ub.rs:21:9 | LL | compare_bytes([1, 2, 3].as_ptr(), [1, 2, 3, 4].as_ptr(), 4) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0 which is only 3 bytes from the end of the allocation error[E0080]: evaluation of constant value failed - --> $DIR/const-compare-bytes-ub.rs:26:9 + --> $DIR/const-compare-bytes-ub.rs:25:9 | LL | compare_bytes([1, 2, 3, 4].as_ptr(), [1, 2, 3].as_ptr(), 4) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC1 which is only 3 bytes from the end of the allocation error[E0080]: evaluation of constant value failed - --> $DIR/const-compare-bytes-ub.rs:30:9 + --> $DIR/const-compare-bytes-ub.rs:29:9 | LL | compare_bytes(MaybeUninit::uninit().as_ptr(), [1].as_ptr(), 1) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC2[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory error[E0080]: evaluation of constant value failed - --> $DIR/const-compare-bytes-ub.rs:34:9 + --> $DIR/const-compare-bytes-ub.rs:33:9 | LL | compare_bytes([1].as_ptr(), MaybeUninit::uninit().as_ptr(), 1) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC3[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory error[E0080]: evaluation of constant value failed - --> $DIR/const-compare-bytes-ub.rs:38:9 + --> $DIR/const-compare-bytes-ub.rs:37:9 | LL | compare_bytes([&1].as_ptr().cast(), [&2].as_ptr().cast(), std::mem::size_of::()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer diff --git a/tests/ui/consts/const-compare-bytes.rs b/tests/ui/consts/const-compare-bytes.rs index 8596a2d9df910..cd5cdfd0400ec 100644 --- a/tests/ui/consts/const-compare-bytes.rs +++ b/tests/ui/consts/const-compare-bytes.rs @@ -1,7 +1,6 @@ //@ run-pass #![feature(core_intrinsics)] -#![feature(const_intrinsic_compare_bytes)] use std::intrinsics::compare_bytes; fn main() { diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs index 99f98c3f27ada..76b6a8c8395cc 100644 --- a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs +++ b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.rs @@ -1,5 +1,4 @@ #![feature(core_intrinsics)] -#![feature(const_intrinsic_raw_eq)] const RAW_EQ_PADDING: bool = unsafe { std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr index bedfc8283ea45..b8fdfe7bef35a 100644 --- a/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr +++ b/tests/ui/intrinsics/intrinsic-raw_eq-const-bad.stderr @@ -1,11 +1,11 @@ error[E0080]: evaluation of constant value failed - --> $DIR/intrinsic-raw_eq-const-bad.rs:5:5 + --> $DIR/intrinsic-raw_eq-const-bad.rs:4:5 | LL | std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory error[E0080]: evaluation of constant value failed - --> $DIR/intrinsic-raw_eq-const-bad.rs:11:5 + --> $DIR/intrinsic-raw_eq-const-bad.rs:10:5 | LL | std::intrinsics::raw_eq(&(&0), &(&1)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into integer @@ -14,7 +14,7 @@ LL | std::intrinsics::raw_eq(&(&0), &(&1)) = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: evaluation of constant value failed - --> $DIR/intrinsic-raw_eq-const-bad.rs:19:5 + --> $DIR/intrinsic-raw_eq-const-bad.rs:18:5 | LL | std::intrinsics::raw_eq(aref, aref) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment 1, but alignment 4 is required diff --git a/tests/ui/intrinsics/intrinsic-raw_eq-const.rs b/tests/ui/intrinsics/intrinsic-raw_eq-const.rs index 47b4e20dfbb7e..b37def85bb7c2 100644 --- a/tests/ui/intrinsics/intrinsic-raw_eq-const.rs +++ b/tests/ui/intrinsics/intrinsic-raw_eq-const.rs @@ -1,7 +1,6 @@ //@ run-pass #![feature(core_intrinsics)] -#![feature(const_intrinsic_raw_eq)] pub fn main() { use std::intrinsics::raw_eq; From a741b33c145a5f1fa3e7f42a4488750ce8719d4f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Nov 2024 08:49:49 +0100 Subject: [PATCH 17/18] when an intrinsic has a const-stable fallback body, we can easily expose it on stable --- .../rustc_const_eval/src/check_consts/check.rs | 16 ++++++++++++---- compiler/rustc_middle/src/ty/util.rs | 3 +-- tests/ui/consts/auxiliary/unstable_intrinsic.rs | 2 ++ tests/ui/consts/const-unstable-intrinsic.rs | 12 ++++++++++++ tests/ui/consts/const-unstable-intrinsic.stderr | 12 ++++++++++-- 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 1c17421e78218..aea3d5bd3e70f 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -739,6 +739,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // We use `intrinsic.const_stable` to determine if this can be safely exposed to // stable code, rather than `const_stable_indirect`. This is to make // `#[rustc_const_stable_indirect]` an attribute that is always safe to add. + // We also ask is_safe_to_expose_on_stable_const_fn; this determines whether the intrinsic + // fallback body is safe to expose on stable. + let is_const_stable = intrinsic.const_stable + || (!intrinsic.must_be_overridden + && tcx.is_const_fn(callee) + && is_safe_to_expose_on_stable_const_fn(tcx, callee)); match tcx.lookup_const_stability(callee) { None => { // Non-const intrinsic. @@ -748,7 +754,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // Intrinsic does not need a separate feature gate (we rely on the // regular stability checker). However, we have to worry about recursive // const stability. - if !intrinsic.const_stable && self.enforce_recursive_const_stability() { + if !is_const_stable && self.enforce_recursive_const_stability() { self.dcx().emit_err(errors::UnmarkedIntrinsicExposed { span: self.span, def_path: self.tcx.def_path_str(callee), @@ -763,12 +769,14 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { self.check_op(ops::IntrinsicUnstable { name: intrinsic.name, feature, - const_stable: intrinsic.const_stable, + const_stable: is_const_stable, }); } Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => { - // All good. But ensure this is indeed a const-stable intrinsic. - assert!(intrinsic.const_stable); + // All good. Note that a `#[rustc_const_stable]` intrinsic (meaning it + // can be *directly* invoked from stable const code) does not always + // have the `#[rustc_const_stable_intrinsic]` attribute (which controls + // exposing an intrinsic indirectly); we accept this call anyway. } } // This completes the checks for intrinsics. diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index b5811824683a8..6ffd149ef1475 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1789,8 +1789,7 @@ pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option(x: *const T) -> usize { 42 } #[unstable(feature = "unstable", issue = "42")] #[rustc_const_unstable(feature = "unstable", issue = "42")] #[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] pub const unsafe fn min_align_of_val(x: *const T) -> usize { 42 } diff --git a/tests/ui/consts/const-unstable-intrinsic.rs b/tests/ui/consts/const-unstable-intrinsic.rs index fbe491e067176..56b552b6a3f35 100644 --- a/tests/ui/consts/const-unstable-intrinsic.rs +++ b/tests/ui/consts/const-unstable-intrinsic.rs @@ -30,11 +30,13 @@ const fn const_main() { #[unstable(feature = "local", issue = "42")] #[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } #[unstable(feature = "local", issue = "42")] #[rustc_const_unstable(feature = "local", issue = "42")] #[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] pub const unsafe fn min_align_of_val(x: *const T) -> usize { 42 } #[stable(feature = "rust1", since = "1.0.0")] @@ -43,6 +45,7 @@ pub const unsafe fn min_align_of_val(x: *const T) -> usize { 42 } pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { // Const stability attributes are not inherited from parent items. #[rustc_intrinsic] + #[rustc_intrinsic_must_be_overridden] const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { unimplemented!() } @@ -50,3 +53,12 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { unsafe { copy(src, dst, count) } //~^ ERROR cannot be (indirectly) exposed to stable } + +// Ensure that a fallback body is recursively-const-checked. +mod fallback { + #[rustc_intrinsic] + const unsafe fn copy(src: *const T, _dst: *mut T, _count: usize) { + super::size_of_val(src); + //~^ ERROR cannot be (indirectly) exposed to stable + } +} diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr index 2cf76732cf2cc..3e605f3d0037e 100644 --- a/tests/ui/consts/const-unstable-intrinsic.stderr +++ b/tests/ui/consts/const-unstable-intrinsic.stderr @@ -60,13 +60,21 @@ LL | const fn const_main() { | error: intrinsic `copy::copy` cannot be (indirectly) exposed to stable - --> $DIR/const-unstable-intrinsic.rs:50:14 + --> $DIR/const-unstable-intrinsic.rs:53:14 | LL | unsafe { copy(src, dst, count) } | ^^^^^^^^^^^^^^^^^^^^^ | = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval) -error: aborting due to 7 previous errors +error: intrinsic `size_of_val` cannot be (indirectly) exposed to stable + --> $DIR/const-unstable-intrinsic.rs:61:9 + | +LL | super::size_of_val(src); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: mark the caller as `#[rustc_const_unstable]`, or mark the intrinsic `#[rustc_const_stable_intrinsic]` (but this requires team approval) + +error: aborting due to 8 previous errors For more information about this error, try `rustc --explain E0658`. From e37a3a85e44f2c43442acf41e5d9d704738ee84c Mon Sep 17 00:00:00 2001 From: mejrs <59372212+mejrs@users.noreply.github.com> Date: Tue, 5 Nov 2024 01:08:20 +0100 Subject: [PATCH 18/18] Explain how to evaluate an obligation --- compiler/rustc_trait_selection/src/infer.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index e91574fa1aff2..8f1c8a296630c 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -69,9 +69,15 @@ impl<'tcx> InferCtxt<'tcx> { /// .must_apply_modulo_regions(); /// ``` /// - /// In most cases you should instead create an [Obligation](traits::Obligation) - /// and check whether it holds, because it properly handles higher ranked traits - /// and it is more convenient and safer when your `params` are inside a `Binder`. + /// In most cases you should instead create an [Obligation] and check whether + /// it holds via [`evaluate_obligation`] or one of its helper functions like + /// [`predicate_must_hold_modulo_regions`], because it properly handles higher ranked traits + /// and it is more convenient and safer when your `params` are inside a [`Binder`]. + /// + /// [Obligation]: traits::Obligation + /// [`evaluate_obligation`]: crate::traits::query::evaluate_obligation::InferCtxtExt::evaluate_obligation + /// [`predicate_must_hold_modulo_regions`]: crate::traits::query::evaluate_obligation::InferCtxtExt::predicate_must_hold_modulo_regions + /// [`Binder`]: ty::Binder #[instrument(level = "debug", skip(self, params), ret)] fn type_implements_trait( &self,