From 90722811c8818b1ce4c7819dac41f22837fa98c6 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 1 Apr 2022 18:51:57 -0700 Subject: [PATCH 01/20] Deprecate the `ptr_to_from_bits` feature The strict provenance APIs are a better version of these, and things like `.addr()` work for the "that cast looks sketchy" case even if the full strict provenance stuff never happens. So I think it's fine to move away from these, and encourage the others instead. --- library/core/src/ptr/const_ptr.rs | 5 +++++ library/core/src/ptr/mut_ptr.rs | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index af64fbc8e9eca..e460a7f3b1e3e 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -119,6 +119,7 @@ impl *const T { /// assert_eq!(p1.to_bits() - p0.to_bits(), 4); /// ``` #[unstable(feature = "ptr_to_from_bits", issue = "91126")] + #[rustc_deprecated(since = "1.62", reason = "replaced by the `addr` method")] pub fn to_bits(self) -> usize where T: Sized, @@ -140,6 +141,10 @@ impl *const T { /// assert_eq!(<*const u8>::from_bits(1), dangling); /// ``` #[unstable(feature = "ptr_to_from_bits", issue = "91126")] + #[rustc_deprecated( + since = "1.62", + reason = "replaced by the `with_addr` method or the `ptr::invalid` function" + )] #[allow(fuzzy_provenance_casts)] // this is an unstable and semi-deprecated cast function pub fn from_bits(bits: usize) -> Self where diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index d6872ba1c20f0..351012e6ffc8f 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -125,6 +125,7 @@ impl *mut T { /// assert_eq!(p1.to_bits() - p0.to_bits(), 4); /// ``` #[unstable(feature = "ptr_to_from_bits", issue = "91126")] + #[rustc_deprecated(since = "1.62", reason = "replaced by the `addr` method")] pub fn to_bits(self) -> usize where T: Sized, @@ -146,6 +147,10 @@ impl *mut T { /// assert_eq!(<*mut u8>::from_bits(1), dangling); /// ``` #[unstable(feature = "ptr_to_from_bits", issue = "91126")] + #[rustc_deprecated( + since = "1.62", + reason = "replaced by the `with_addr` method or the `ptr::invalid_mut` function" + )] #[allow(fuzzy_provenance_casts)] // this is an unstable and semi-deprecated cast function pub fn from_bits(bits: usize) -> Self where From 4d37d1f4226bd92bf6c129977357afd50993cf0a Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 3 Apr 2022 13:19:30 -0700 Subject: [PATCH 02/20] Refer to the `exposed` versions of the methods instead Changing to those doesn't introduce any new unsoundness over the existing ones, so they're the better "if you won't want to think about it" replacement. But also mention the strict provenance APIs, as that's what we'd rather they use instead. --- library/core/src/ptr/const_ptr.rs | 9 +++++++-- library/core/src/ptr/mut_ptr.rs | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index e460a7f3b1e3e..2c371f635ab97 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -119,7 +119,11 @@ impl *const T { /// assert_eq!(p1.to_bits() - p0.to_bits(), 4); /// ``` #[unstable(feature = "ptr_to_from_bits", issue = "91126")] - #[rustc_deprecated(since = "1.62", reason = "replaced by the `addr` method")] + #[rustc_deprecated( + since = "1.62", + reason = "replaced by the `exposed_addr` method, or update your code \ + to follow the strict provenance rules using its APIs" + )] pub fn to_bits(self) -> usize where T: Sized, @@ -143,7 +147,8 @@ impl *const T { #[unstable(feature = "ptr_to_from_bits", issue = "91126")] #[rustc_deprecated( since = "1.62", - reason = "replaced by the `with_addr` method or the `ptr::invalid` function" + reason = "replaced by the `ptr::from_exposed_addr` function, or update \ + your code to follow the strict provenance rules using its APIs" )] #[allow(fuzzy_provenance_casts)] // this is an unstable and semi-deprecated cast function pub fn from_bits(bits: usize) -> Self diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 351012e6ffc8f..7968253156237 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -125,7 +125,11 @@ impl *mut T { /// assert_eq!(p1.to_bits() - p0.to_bits(), 4); /// ``` #[unstable(feature = "ptr_to_from_bits", issue = "91126")] - #[rustc_deprecated(since = "1.62", reason = "replaced by the `addr` method")] + #[rustc_deprecated( + since = "1.62", + reason = "replaced by the `exposed_addr` method, or update your code \ + to follow the strict provenance rules using its APIs" + )] pub fn to_bits(self) -> usize where T: Sized, @@ -149,7 +153,8 @@ impl *mut T { #[unstable(feature = "ptr_to_from_bits", issue = "91126")] #[rustc_deprecated( since = "1.62", - reason = "replaced by the `with_addr` method or the `ptr::invalid_mut` function" + reason = "replaced by the `ptr::from_exposed_addr_mut` function, or \ + update your code to follow the strict provenance rules using its APIs" )] #[allow(fuzzy_provenance_casts)] // this is an unstable and semi-deprecated cast function pub fn from_bits(bits: usize) -> Self From f613bd6d3af8a28f9ea8a499b4524decaf67f198 Mon Sep 17 00:00:00 2001 From: Stefan Schindler Date: Sat, 10 Sep 2022 16:24:05 +0200 Subject: [PATCH 03/20] Make the one-liner more descriptive --- library/alloc/src/boxed.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 65e323c9e00c3..00c922f3ae93f 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1,4 +1,4 @@ -//! The `Box` type for heap allocation. +//! The pointer type for heap allocation for an owned value of type `T`. //! //! [`Box`], casually referred to as a 'box', provides the simplest form of //! heap allocation in Rust. Boxes provide ownership for this allocation, and @@ -187,7 +187,7 @@ pub use thin::ThinBox; mod thin; -/// A pointer type for heap allocation. +/// A pointer type for heap allocation for an owned value of type `T`. /// /// See the [module-level documentation](../../std/boxed/index.html) for more. #[lang = "owned_box"] From df5d035f5199eab85dac327cbbd30a3ddfe29abd Mon Sep 17 00:00:00 2001 From: Krasimir Georgiev Date: Tue, 18 Oct 2022 14:11:02 +0000 Subject: [PATCH 04/20] mark sys_common::once::generic::Once::new const-stable --- library/std/src/sys_common/once/generic.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/sys_common/once/generic.rs b/library/std/src/sys_common/once/generic.rs index acf5f247164a7..d953a67459234 100644 --- a/library/std/src/sys_common/once/generic.rs +++ b/library/std/src/sys_common/once/generic.rs @@ -107,6 +107,7 @@ struct WaiterQueue<'a> { impl Once { #[inline] + #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")] pub const fn new() -> Once { Once { state_and_queue: AtomicPtr::new(ptr::invalid_mut(INCOMPLETE)) } } From cdb6907893da1d025eba2d8cd396db4e84bca98c Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Thu, 17 Nov 2022 22:11:39 -0500 Subject: [PATCH 05/20] Update compiler_builtins to 0.1.84 --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index acffaaff4d3b3..73256018078d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -792,9 +792,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.82" +version = "0.1.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18cd7635fea7bb481ea543b392789844c1ad581299da70184c7175ce3af76603" +checksum = "989b2c1ca6e90ad06fdc69d1d1862fa28d27a977be6d92ae2fa762cf61fe0b10" dependencies = [ "cc", "rustc-std-workspace-core", From eafe61d6bd9d983535a90b29ef5497b0a6e42019 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 20 Nov 2022 00:03:10 +0000 Subject: [PATCH 06/20] dist-various-2: Use clang for the UEFI targets This fixes an issue where the C and asm sources built by compiler_builtins were being compiled as ELF objects instead of PE objects. This wasn't noticed before because it doesn't cause compiler_builtins or rustc to fail to build. You only see a failure when a program is built that references one of the symbols in an ELF object. Compiling with clang fixes this because the `cc` crate converts the UEFI targets into Windows targets that clang understands, causing it to produce PE objects. Note that this requires compiler_builtins >= 0.1.84. Fixes https://github.com/rust-lang/rust/issues/104326 --- src/ci/docker/host-x86_64/dist-various-2/Dockerfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index e1adabaac9b56..93ef7dfcbf549 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -61,6 +61,12 @@ ENV \ AR_i686_unknown_freebsd=i686-unknown-freebsd12-ar \ CC_i686_unknown_freebsd=i686-unknown-freebsd12-clang \ CXX_i686_unknown_freebsd=i686-unknown-freebsd12-clang++ \ + CC_aarch64_unknown_uefi=clang-11 \ + CXX_aarch64_unknown_uefi=clang++-11 \ + CC_i686_unknown_uefi=clang-11 \ + CXX_i686_unknown_uefi=clang++-11 \ + CC_x86_64_unknown_uefi=clang-11 \ + CXX_x86_64_unknown_uefi=clang++-11 \ CC=gcc-8 \ CXX=g++-8 From a1e5fea13610ba651b6eec034b85377ead87eb7c Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 20 Nov 2022 13:06:44 +0100 Subject: [PATCH 07/20] Move macro_rules diagnostics to diagnostics module --- compiler/rustc_expand/src/expand.rs | 2 +- compiler/rustc_expand/src/mbe.rs | 1 + compiler/rustc_expand/src/mbe/diagnostics.rs | 257 +++++++++++++++++++ compiler/rustc_expand/src/mbe/macro_rules.rs | 245 +----------------- 4 files changed, 268 insertions(+), 237 deletions(-) create mode 100644 compiler/rustc_expand/src/mbe/diagnostics.rs diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 3d37e2c656851..f7f3075e19bdd 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1,7 +1,7 @@ use crate::base::*; use crate::config::StripUnconfigured; use crate::hygiene::SyntaxContext; -use crate::mbe::macro_rules::annotate_err_with_kind; +use crate::mbe::diagnostics::annotate_err_with_kind; use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod}; use crate::placeholders::{placeholder, PlaceholderExpander}; diff --git a/compiler/rustc_expand/src/mbe.rs b/compiler/rustc_expand/src/mbe.rs index 63bafd7b046fb..a43b2a001883a 100644 --- a/compiler/rustc_expand/src/mbe.rs +++ b/compiler/rustc_expand/src/mbe.rs @@ -3,6 +3,7 @@ //! why we call this module `mbe`. For external documentation, prefer the //! official terminology: "declarative macros". +pub(crate) mod diagnostics; pub(crate) mod macro_check; pub(crate) mod macro_parser; pub(crate) mod macro_rules; diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs new file mode 100644 index 0000000000000..197f056917f5d --- /dev/null +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -0,0 +1,257 @@ +use std::borrow::Cow; + +use crate::base::{DummyResult, ExtCtxt, MacResult}; +use crate::expand::{parse_ast_fragment, AstFragmentKind}; +use crate::mbe::{ + macro_parser::{MatcherLoc, NamedParseResult, ParseResult::*, TtParser}, + macro_rules::{try_match_macro, Tracker}, +}; +use rustc_ast::token::{self, Token}; +use rustc_ast::tokenstream::TokenStream; +use rustc_ast_pretty::pprust; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage}; +use rustc_parse::parser::{Parser, Recovery}; +use rustc_span::source_map::SourceMap; +use rustc_span::symbol::Ident; +use rustc_span::Span; + +use super::macro_rules::{parser_from_cx, NoopTracker}; + +pub(super) fn failed_to_match_macro<'cx>( + cx: &'cx mut ExtCtxt<'_>, + sp: Span, + def_span: Span, + name: Ident, + arg: TokenStream, + lhses: &[Vec], +) -> Box { + let sess = &cx.sess.parse_sess; + + // An error occurred, try the expansion again, tracking the expansion closely for better diagnostics. + let mut tracker = CollectTrackerAndEmitter::new(cx, sp); + + let try_success_result = try_match_macro(sess, name, &arg, lhses, &mut tracker); + + if try_success_result.is_ok() { + // Nonterminal parser recovery might turn failed matches into successful ones, + // but for that it must have emitted an error already + tracker.cx.sess.delay_span_bug(sp, "Macro matching returned a success on the second try"); + } + + if let Some(result) = tracker.result { + // An irrecoverable error occurred and has been emitted. + return result; + } + + let Some((token, label, remaining_matcher)) = tracker.best_failure else { + return DummyResult::any(sp); + }; + + let span = token.span.substitute_dummy(sp); + + let mut err = cx.struct_span_err(span, &parse_failure_msg(&token)); + err.span_label(span, label); + if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) { + err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro"); + } + + annotate_doc_comment(&mut err, sess.source_map(), span); + + if let Some(span) = remaining_matcher.span() { + err.span_note(span, format!("while trying to match {remaining_matcher}")); + } else { + err.note(format!("while trying to match {remaining_matcher}")); + } + + // Check whether there's a missing comma in this macro call, like `println!("{}" a);` + if let Some((arg, comma_span)) = arg.add_comma() { + for lhs in lhses { + let parser = parser_from_cx(sess, arg.clone(), Recovery::Allowed); + let mut tt_parser = TtParser::new(name); + + if let Success(_) = + tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, &mut NoopTracker) + { + if comma_span.is_dummy() { + err.note("you might be missing a comma"); + } else { + err.span_suggestion_short( + comma_span, + "missing comma here", + ", ", + Applicability::MachineApplicable, + ); + } + } + } + } + err.emit(); + cx.trace_macros_diag(); + DummyResult::any(sp) +} + +/// The tracker used for the slow error path that collects useful info for diagnostics. +struct CollectTrackerAndEmitter<'a, 'cx, 'matcher> { + cx: &'a mut ExtCtxt<'cx>, + remaining_matcher: Option<&'matcher MatcherLoc>, + /// Which arm's failure should we report? (the one furthest along) + best_failure: Option<(Token, &'static str, MatcherLoc)>, + root_span: Span, + result: Option>, +} + +impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, 'matcher> { + fn before_match_loc(&mut self, parser: &TtParser, matcher: &'matcher MatcherLoc) { + if self.remaining_matcher.is_none() + || (parser.has_no_remaining_items_for_step() && *matcher != MatcherLoc::Eof) + { + self.remaining_matcher = Some(matcher); + } + } + + fn after_arm(&mut self, result: &NamedParseResult) { + match result { + Success(_) => { + // Nonterminal parser recovery might turn failed matches into successful ones, + // but for that it must have emitted an error already + self.cx.sess.delay_span_bug( + self.root_span, + "should not collect detailed info for successful macro match", + ); + } + Failure(token, msg) => match self.best_failure { + Some((ref best_token, _, _)) if best_token.span.lo() >= token.span.lo() => {} + _ => { + self.best_failure = Some(( + token.clone(), + msg, + self.remaining_matcher + .expect("must have collected matcher already") + .clone(), + )) + } + }, + Error(err_sp, msg) => { + let span = err_sp.substitute_dummy(self.root_span); + self.cx.struct_span_err(span, msg).emit(); + self.result = Some(DummyResult::any(span)); + } + ErrorReported(_) => self.result = Some(DummyResult::any(self.root_span)), + } + } + + fn description() -> &'static str { + "detailed" + } + + fn recovery() -> Recovery { + Recovery::Allowed + } +} + +impl<'a, 'cx> CollectTrackerAndEmitter<'a, 'cx, '_> { + fn new(cx: &'a mut ExtCtxt<'cx>, root_span: Span) -> Self { + Self { cx, remaining_matcher: None, best_failure: None, root_span, result: None } + } +} + +pub(super) fn emit_frag_parse_err( + mut e: DiagnosticBuilder<'_, rustc_errors::ErrorGuaranteed>, + parser: &Parser<'_>, + orig_parser: &mut Parser<'_>, + site_span: Span, + arm_span: Span, + kind: AstFragmentKind, +) { + // FIXME(davidtwco): avoid depending on the error message text + if parser.token == token::Eof + && let DiagnosticMessage::Str(message) = &e.message[0].0 + && message.ends_with(", found ``") + { + let msg = &e.message[0]; + e.message[0] = ( + DiagnosticMessage::Str(format!( + "macro expansion ends with an incomplete expression: {}", + message.replace(", found ``", ""), + )), + msg.1, + ); + if !e.span.is_dummy() { + // early end of macro arm (#52866) + e.replace_span_with(parser.token.span.shrink_to_hi()); + } + } + if e.span.is_dummy() { + // Get around lack of span in error (#30128) + e.replace_span_with(site_span); + if !parser.sess.source_map().is_imported(arm_span) { + e.span_label(arm_span, "in this macro arm"); + } + } else if parser.sess.source_map().is_imported(parser.token.span) { + e.span_label(site_span, "in this macro invocation"); + } + match kind { + // Try a statement if an expression is wanted but failed and suggest adding `;` to call. + AstFragmentKind::Expr => match parse_ast_fragment(orig_parser, AstFragmentKind::Stmts) { + Err(err) => err.cancel(), + Ok(_) => { + e.note( + "the macro call doesn't expand to an expression, but it can expand to a statement", + ); + e.span_suggestion_verbose( + site_span.shrink_to_hi(), + "add `;` to interpret the expansion as a statement", + ";", + Applicability::MaybeIncorrect, + ); + } + }, + _ => annotate_err_with_kind(&mut e, kind, site_span), + }; + e.emit(); +} + +pub(crate) fn annotate_err_with_kind(err: &mut Diagnostic, kind: AstFragmentKind, span: Span) { + match kind { + AstFragmentKind::Ty => { + err.span_label(span, "this macro call doesn't expand to a type"); + } + AstFragmentKind::Pat => { + err.span_label(span, "this macro call doesn't expand to a pattern"); + } + _ => {} + }; +} + +#[derive(Subdiagnostic)] +enum ExplainDocComment { + #[label(expand_explain_doc_comment_inner)] + Inner { + #[primary_span] + span: Span, + }, + #[label(expand_explain_doc_comment_outer)] + Outer { + #[primary_span] + span: Span, + }, +} + +pub(super) fn annotate_doc_comment(err: &mut Diagnostic, sm: &SourceMap, span: Span) { + if let Ok(src) = sm.span_to_snippet(span) { + if src.starts_with("///") || src.starts_with("/**") { + err.subdiagnostic(ExplainDocComment::Outer { span }); + } else if src.starts_with("//!") || src.starts_with("/*!") { + err.subdiagnostic(ExplainDocComment::Inner { span }); + } + } +} + +/// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For +/// other tokens, this is "unexpected token...". +pub(super) fn parse_failure_msg(tok: &Token) -> String { + match tok.kind { + token::Eof => "unexpected end of macro invocation".to_string(), + _ => format!("no rules expected the token `{}`", pprust::token_to_string(tok),), + } +} diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 6c7063ca28b35..fc33974dd1780 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -2,6 +2,7 @@ use crate::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander}; use crate::base::{SyntaxExtension, SyntaxExtensionKind}; use crate::expand::{ensure_complete_parse, parse_ast_fragment, AstFragment, AstFragmentKind}; use crate::mbe; +use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg}; use crate::mbe::macro_check; use crate::mbe::macro_parser::{Error, ErrorReported, Failure, Success, TtParser}; use crate::mbe::macro_parser::{MatchedSeq, MatchedTokenTree, MatcherLoc}; @@ -14,9 +15,7 @@ use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, TransparencyError}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; -use rustc_errors::{ - Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, -}; +use rustc_errors::{Applicability, ErrorGuaranteed}; use rustc_feature::Features; use rustc_lint_defs::builtin::{ RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, @@ -27,7 +26,6 @@ use rustc_session::parse::ParseSess; use rustc_session::Session; use rustc_span::edition::Edition; use rustc_span::hygiene::Transparency; -use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym, Ident, MacroRulesNormalizedIdent}; use rustc_span::Span; @@ -35,6 +33,7 @@ use std::borrow::Cow; use std::collections::hash_map::Entry; use std::{mem, slice}; +use super::diagnostics; use super::macro_parser::{NamedMatches, NamedParseResult}; pub(crate) struct ParserAnyMacro<'a> { @@ -51,74 +50,6 @@ pub(crate) struct ParserAnyMacro<'a> { is_local: bool, } -pub(crate) fn annotate_err_with_kind(err: &mut Diagnostic, kind: AstFragmentKind, span: Span) { - match kind { - AstFragmentKind::Ty => { - err.span_label(span, "this macro call doesn't expand to a type"); - } - AstFragmentKind::Pat => { - err.span_label(span, "this macro call doesn't expand to a pattern"); - } - _ => {} - }; -} - -fn emit_frag_parse_err( - mut e: DiagnosticBuilder<'_, rustc_errors::ErrorGuaranteed>, - parser: &Parser<'_>, - orig_parser: &mut Parser<'_>, - site_span: Span, - arm_span: Span, - kind: AstFragmentKind, -) { - // FIXME(davidtwco): avoid depending on the error message text - if parser.token == token::Eof - && let DiagnosticMessage::Str(message) = &e.message[0].0 - && message.ends_with(", found ``") - { - let msg = &e.message[0]; - e.message[0] = ( - DiagnosticMessage::Str(format!( - "macro expansion ends with an incomplete expression: {}", - message.replace(", found ``", ""), - )), - msg.1, - ); - if !e.span.is_dummy() { - // early end of macro arm (#52866) - e.replace_span_with(parser.token.span.shrink_to_hi()); - } - } - if e.span.is_dummy() { - // Get around lack of span in error (#30128) - e.replace_span_with(site_span); - if !parser.sess.source_map().is_imported(arm_span) { - e.span_label(arm_span, "in this macro arm"); - } - } else if parser.sess.source_map().is_imported(parser.token.span) { - e.span_label(site_span, "in this macro invocation"); - } - match kind { - // Try a statement if an expression is wanted but failed and suggest adding `;` to call. - AstFragmentKind::Expr => match parse_ast_fragment(orig_parser, AstFragmentKind::Stmts) { - Err(err) => err.cancel(), - Ok(_) => { - e.note( - "the macro call doesn't expand to an expression, but it can expand to a statement", - ); - e.span_suggestion_verbose( - site_span.shrink_to_hi(), - "add `;` to interpret the expansion as a statement", - ";", - Applicability::MaybeIncorrect, - ); - } - }, - _ => annotate_err_with_kind(&mut e, kind, site_span), - }; - e.emit(); -} - impl<'a> ParserAnyMacro<'a> { pub(crate) fn make(mut self: Box>, kind: AstFragmentKind) -> AstFragment { let ParserAnyMacro { @@ -134,7 +65,7 @@ impl<'a> ParserAnyMacro<'a> { let fragment = match parse_ast_fragment(parser, kind) { Ok(f) => f, Err(err) => { - emit_frag_parse_err(err, parser, snapshot, site_span, arm_span, kind); + diagnostics::emit_frag_parse_err(err, parser, snapshot, site_span, arm_span, kind); return kind.dummy(site_span); } }; @@ -224,7 +155,7 @@ pub(super) trait Tracker<'matcher> { } /// A noop tracker that is used in the hot path of the expansion, has zero overhead thanks to monomorphization. -struct NoopTracker; +pub(super) struct NoopTracker; impl<'matcher> Tracker<'matcher> for NoopTracker { fn before_match_loc(&mut self, _: &TtParser, _: &'matcher MatcherLoc) {} @@ -331,135 +262,10 @@ fn expand_macro<'cx>( } } - // An error occurred, try the expansion again, tracking the expansion closely for better diagnostics. - let mut tracker = CollectTrackerAndEmitter::new(cx, sp); - - let try_success_result = try_match_macro(sess, name, &arg, lhses, &mut tracker); - - if try_success_result.is_ok() { - // Nonterminal parser recovery might turn failed matches into successful ones, - // but for that it must have emitted an error already - tracker.cx.sess.delay_span_bug(sp, "Macro matching returned a success on the second try"); - } - - if let Some(result) = tracker.result { - // An irrecoverable error occurred and has been emitted. - return result; - } - - let Some((token, label, remaining_matcher)) = tracker.best_failure else { - return DummyResult::any(sp); - }; - - let span = token.span.substitute_dummy(sp); - - let mut err = cx.struct_span_err(span, &parse_failure_msg(&token)); - err.span_label(span, label); - if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) { - err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro"); - } - - annotate_doc_comment(&mut err, sess.source_map(), span); - - if let Some(span) = remaining_matcher.span() { - err.span_note(span, format!("while trying to match {remaining_matcher}")); - } else { - err.note(format!("while trying to match {remaining_matcher}")); - } - - // Check whether there's a missing comma in this macro call, like `println!("{}" a);` - if let Some((arg, comma_span)) = arg.add_comma() { - for lhs in lhses { - let parser = parser_from_cx(sess, arg.clone(), Recovery::Allowed); - let mut tt_parser = TtParser::new(name); - - if let Success(_) = - tt_parser.parse_tt(&mut Cow::Borrowed(&parser), lhs, &mut NoopTracker) - { - if comma_span.is_dummy() { - err.note("you might be missing a comma"); - } else { - err.span_suggestion_short( - comma_span, - "missing comma here", - ", ", - Applicability::MachineApplicable, - ); - } - } - } - } - err.emit(); - cx.trace_macros_diag(); - DummyResult::any(sp) + diagnostics::failed_to_match_macro(cx, sp, def_span, name, arg, lhses) } -/// The tracker used for the slow error path that collects useful info for diagnostics. -struct CollectTrackerAndEmitter<'a, 'cx, 'matcher> { - cx: &'a mut ExtCtxt<'cx>, - remaining_matcher: Option<&'matcher MatcherLoc>, - /// Which arm's failure should we report? (the one furthest along) - best_failure: Option<(Token, &'static str, MatcherLoc)>, - root_span: Span, - result: Option>, -} - -impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, 'matcher> { - fn before_match_loc(&mut self, parser: &TtParser, matcher: &'matcher MatcherLoc) { - if self.remaining_matcher.is_none() - || (parser.has_no_remaining_items_for_step() && *matcher != MatcherLoc::Eof) - { - self.remaining_matcher = Some(matcher); - } - } - - fn after_arm(&mut self, result: &NamedParseResult) { - match result { - Success(_) => { - // Nonterminal parser recovery might turn failed matches into successful ones, - // but for that it must have emitted an error already - self.cx.sess.delay_span_bug( - self.root_span, - "should not collect detailed info for successful macro match", - ); - } - Failure(token, msg) => match self.best_failure { - Some((ref best_token, _, _)) if best_token.span.lo() >= token.span.lo() => {} - _ => { - self.best_failure = Some(( - token.clone(), - msg, - self.remaining_matcher - .expect("must have collected matcher already") - .clone(), - )) - } - }, - Error(err_sp, msg) => { - let span = err_sp.substitute_dummy(self.root_span); - self.cx.struct_span_err(span, msg).emit(); - self.result = Some(DummyResult::any(span)); - } - ErrorReported(_) => self.result = Some(DummyResult::any(self.root_span)), - } - } - - fn description() -> &'static str { - "detailed" - } - - fn recovery() -> Recovery { - Recovery::Allowed - } -} - -impl<'a, 'cx> CollectTrackerAndEmitter<'a, 'cx, '_> { - fn new(cx: &'a mut ExtCtxt<'cx>, root_span: Span) -> Self { - Self { cx, remaining_matcher: None, best_failure: None, root_span, result: None } - } -} - -enum CanRetry { +pub(super) enum CanRetry { Yes, /// We are not allowed to retry macro expansion as a fatal error has been emitted already. No(ErrorGuaranteed), @@ -469,7 +275,7 @@ enum CanRetry { /// and nothing if it failed. On failure, it's the callers job to use `track` accordingly to record all errors /// correctly. #[instrument(level = "debug", skip(sess, arg, lhses, track), fields(tracking = %T::description()))] -fn try_match_macro<'matcher, T: Tracker<'matcher>>( +pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>( sess: &ParseSess, name: Ident, arg: &TokenStream, @@ -769,30 +575,6 @@ pub fn compile_declarative_macro( (mk_syn_ext(expander), rule_spans) } -#[derive(Subdiagnostic)] -enum ExplainDocComment { - #[label(expand_explain_doc_comment_inner)] - Inner { - #[primary_span] - span: Span, - }, - #[label(expand_explain_doc_comment_outer)] - Outer { - #[primary_span] - span: Span, - }, -} - -fn annotate_doc_comment(err: &mut Diagnostic, sm: &SourceMap, span: Span) { - if let Ok(src) = sm.span_to_snippet(span) { - if src.starts_with("///") || src.starts_with("/**") { - err.subdiagnostic(ExplainDocComment::Outer { span }); - } else if src.starts_with("//!") || src.starts_with("/*!") { - err.subdiagnostic(ExplainDocComment::Inner { span }); - } - } -} - fn check_lhs_nt_follows(sess: &ParseSess, def: &ast::Item, lhs: &mbe::TokenTree) -> bool { // lhs is going to be like TokenTree::Delimited(...), where the // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens. @@ -1577,15 +1359,6 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String { } } -fn parser_from_cx(sess: &ParseSess, tts: TokenStream, recovery: Recovery) -> Parser<'_> { +pub(super) fn parser_from_cx(sess: &ParseSess, tts: TokenStream, recovery: Recovery) -> Parser<'_> { Parser::new(sess, tts, true, rustc_parse::MACRO_ARGUMENTS).recovery(recovery) } - -/// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For -/// other tokens, this is "unexpected token...". -fn parse_failure_msg(tok: &Token) -> String { - match tok.kind { - token::Eof => "unexpected end of macro invocation".to_string(), - _ => format!("no rules expected the token `{}`", pprust::token_to_string(tok),), - } -} From 3fe37b8c6e02daa6a7c33a71bb7f44682e43d08d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20L=C3=B6bel?= Date: Sun, 28 Mar 2021 14:24:49 +0200 Subject: [PATCH 08/20] Add get_many_mut methods to slice --- library/core/src/error.rs | 3 + library/core/src/slice/mod.rs | 136 ++++++++++++++++++++++++++++++++++ library/core/tests/lib.rs | 1 + library/core/tests/slice.rs | 60 +++++++++++++++ library/std/src/lib.rs | 1 + 5 files changed, 201 insertions(+) diff --git a/library/core/src/error.rs b/library/core/src/error.rs index c9c7cdf4defc6..7152300abcbf3 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -506,3 +506,6 @@ impl Error for crate::ffi::FromBytesWithNulError { #[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")] impl Error for crate::ffi::FromBytesUntilNulError {} + +#[unstable(feature = "get_many_mut", issue = "104642")] +impl Error for crate::slice::GetManyMutError {} diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index ad90e00b8a095..04486ed2d14e3 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -7,6 +7,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::cmp::Ordering::{self, Greater, Less}; +use crate::fmt; use crate::intrinsics::{assert_unsafe_precondition, exact_div}; use crate::marker::Copy; use crate::mem::{self, SizedTypeProperties}; @@ -4082,6 +4083,88 @@ impl [T] { *self = rem; Some(last) } + + /// Returns mutable references to many indices at once, without doing any checks. + /// + /// For a safe alternative see [`get_many_mut`]. + /// + /// # Safety + /// + /// Calling this method with overlapping or out-of-bounds indices is *[undefined behavior]* + /// even if the resulting references are not used. + /// + /// # Examples + /// + /// ``` + /// #![feature(get_many_mut)] + /// + /// let x = &mut [1, 2, 4]; + /// + /// unsafe { + /// let [a, b] = x.get_many_unchecked_mut([0, 2]); + /// *a *= 10; + /// *b *= 100; + /// } + /// assert_eq!(x, &[10, 2, 400]); + /// ``` + /// + /// [`get_many_mut`]: slice::get_many_mut + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[unstable(feature = "get_many_mut", issue = "104642")] + #[inline] + pub unsafe fn get_many_unchecked_mut( + &mut self, + indices: [usize; N], + ) -> [&mut T; N] { + // NB: This implementation is written as it is because any variation of + // `indices.map(|i| self.get_unchecked_mut(i))` would make miri unhappy, + // or generate worse code otherwise. This is also why we need to go + // through a raw pointer here. + let slice: *mut [T] = self; + let mut arr: mem::MaybeUninit<[&mut T; N]> = mem::MaybeUninit::uninit(); + let arr_ptr = arr.as_mut_ptr(); + + // SAFETY: We expect `indices` to contain disjunct values that are + // in bounds of `self`. + unsafe { + for i in 0..N { + let idx = *indices.get_unchecked(i); + *(*arr_ptr).get_unchecked_mut(i) = &mut *slice.get_unchecked_mut(idx); + } + arr.assume_init() + } + } + + /// Returns mutable references to many indices at once. + /// + /// Returns an error if any index is out-of-bounds, or if the same index was + /// passed more than once. + /// + /// # Examples + /// + /// ``` + /// #![feature(get_many_mut)] + /// + /// let v = &mut [1, 2, 3]; + /// if let Ok([a, b]) = v.get_many_mut([0, 2]) { + /// *a = 413; + /// *b = 612; + /// } + /// assert_eq!(v, &[413, 2, 612]); + /// ``` + #[unstable(feature = "get_many_mut", issue = "104642")] + #[inline] + pub fn get_many_mut( + &mut self, + indices: [usize; N], + ) -> Result<[&mut T; N], GetManyMutError> { + if !get_many_check_valid(&indices, self.len()) { + return Err(GetManyMutError { _private: () }); + } + // SAFETY: The `get_many_check_valid()` call checked that all indices + // are disjunct and in bounds. + unsafe { Ok(self.get_many_unchecked_mut(indices)) } + } } impl [[T; N]] { @@ -4304,3 +4387,56 @@ impl SlicePattern for [T; N] { self } } + +/// This checks every index against each other, and against `len`. +/// +/// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..` +/// comparison operations. +fn get_many_check_valid(indices: &[usize; N], len: usize) -> bool { + // NB: The optimzer should inline the loops into a sequence + // of instructions without additional branching. + let mut valid = true; + for (i, &idx) in indices.iter().enumerate() { + valid &= idx < len; + for &idx2 in &indices[..i] { + valid &= idx != idx2; + } + } + valid +} + +/// The error type returned by [`get_many_mut`][`slice::get_many_mut`]. +/// +/// It indicates one of two possible errors: +/// - An index is out-of-bounds. +/// - The same index appeared multiple times in the array. +/// +/// # Examples +/// +/// ``` +/// #![feature(get_many_mut)] +/// +/// let v = &mut [1, 2, 3]; +/// assert!(v.get_many_mut([0, 999]).is_err()); +/// assert!(v.get_many_mut([1, 1]).is_err()); +/// ``` +#[unstable(feature = "get_many_mut", issue = "104642")] +// NB: The N here is there to be forward-compatible with adding more details +// to the error type at a later point +pub struct GetManyMutError { + _private: (), +} + +#[unstable(feature = "get_many_mut", issue = "104642")] +impl fmt::Debug for GetManyMutError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("GetManyMutError").finish_non_exhaustive() + } +} + +#[unstable(feature = "get_many_mut", issue = "104642")] +impl fmt::Display for GetManyMutError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt("an index is out of bounds or appeared multiple times in the array", f) + } +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 4c0c0da652f95..abbad96c4da75 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -108,6 +108,7 @@ #![feature(provide_any)] #![feature(utf8_chunks)] #![feature(is_ascii_octdigit)] +#![feature(get_many_mut)] #![deny(unsafe_op_in_unsafe_fn)] extern crate test; diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 9e1fbea79148c..4e06e0f439886 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -2595,3 +2595,63 @@ fn test_flatten_mut_size_overflow() { let x = &mut [[(); usize::MAX]; 2][..]; let _ = x.flatten_mut(); } + +#[test] +fn test_get_many_mut_normal_2() { + let mut v = vec![1, 2, 3, 4, 5]; + let [a, b] = v.get_many_mut([3, 0]).unwrap(); + *a += 10; + *b += 100; + assert_eq!(v, vec![101, 2, 3, 14, 5]); +} + +#[test] +fn test_get_many_mut_normal_3() { + let mut v = vec![1, 2, 3, 4, 5]; + let [a, b, c] = v.get_many_mut([0, 4, 2]).unwrap(); + *a += 10; + *b += 100; + *c += 1000; + assert_eq!(v, vec![11, 2, 1003, 4, 105]); +} + +#[test] +fn test_get_many_mut_empty() { + let mut v = vec![1, 2, 3, 4, 5]; + let [] = v.get_many_mut([]).unwrap(); + assert_eq!(v, vec![1, 2, 3, 4, 5]); +} + +#[test] +fn test_get_many_mut_single_first() { + let mut v = vec![1, 2, 3, 4, 5]; + let [a] = v.get_many_mut([0]).unwrap(); + *a += 10; + assert_eq!(v, vec![11, 2, 3, 4, 5]); +} + +#[test] +fn test_get_many_mut_single_last() { + let mut v = vec![1, 2, 3, 4, 5]; + let [a] = v.get_many_mut([4]).unwrap(); + *a += 10; + assert_eq!(v, vec![1, 2, 3, 4, 15]); +} + +#[test] +fn test_get_many_mut_oob_nonempty() { + let mut v = vec![1, 2, 3, 4, 5]; + assert!(v.get_many_mut([5]).is_err()); +} + +#[test] +fn test_get_many_mut_oob_empty() { + let mut v: Vec = vec![]; + assert!(v.get_many_mut([0]).is_err()); +} + +#[test] +fn test_get_many_mut_duplicate() { + let mut v = vec![1, 2, 3, 4, 5]; + assert!(v.get_many_mut([1, 3, 3, 4]).is_err()); +} diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 9334c833bb650..63ee6c521d793 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -347,6 +347,7 @@ #![feature(stdsimd)] #![feature(test)] #![feature(trace_macros)] +#![feature(get_many_mut)] // // Only used in tests/benchmarks: // From 01a2a546bea08e6b561f99fe09aa94df3f185bbc Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 20 Nov 2022 01:22:40 +0000 Subject: [PATCH 09/20] test-various: Use clang for the UEFI test This syncs it with how the UEFI targets are built in dist-various-2. --- src/ci/docker/host-x86_64/test-various/Dockerfile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile index b0f35bcb9ccf5..0bddffa3436f4 100644 --- a/src/ci/docker/host-x86_64/test-various/Dockerfile +++ b/src/ci/docker/host-x86_64/test-various/Dockerfile @@ -1,6 +1,7 @@ FROM ubuntu:20.04 RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + clang-11 \ g++ \ make \ ninja-build \ @@ -67,7 +68,9 @@ ENV MUSL_TARGETS=x86_64-unknown-linux-musl \ ENV MUSL_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $MUSL_TARGETS COPY host-x86_64/test-various/uefi_qemu_test /uefi_qemu_test -ENV UEFI_TARGETS=x86_64-unknown-uefi +ENV UEFI_TARGETS=x86_64-unknown-uefi \ + CC_x86_64_unknown_uefi=clang-11 \ + CXX_x86_64_unknown_uefi=clang++-11 ENV UEFI_SCRIPT python3 /checkout/x.py --stage 2 build --host='' --target $UEFI_TARGETS && \ python3 -u /uefi_qemu_test/run.py From 9f4b4e46a3ba5602916e96f8a4186eaf63d91682 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Fri, 23 Sep 2022 15:14:34 -0400 Subject: [PATCH 10/20] constify remaining layout methods Remove bad impl for Eq Update Cargo.lock and fix last ValidAlign --- library/core/src/alloc/layout.rs | 33 +++++++++++++++++++++---------- library/core/src/lib.rs | 3 +++ library/core/src/ptr/alignment.rs | 19 +++++++++++++----- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index f50d9a8e1bdf3..2c1911c350efc 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -157,9 +157,10 @@ impl Layout { /// allocate backing structure for `T` (which could be a trait /// or other unsized type like a slice). #[stable(feature = "alloc_layout", since = "1.28.0")] + #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] #[must_use] #[inline] - pub fn for_value(t: &T) -> Self { + pub const fn for_value(t: &T) -> Self { let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); // SAFETY: see rationale in `new` for why this is using the unsafe variant unsafe { Layout::from_size_align_unchecked(size, align) } @@ -191,8 +192,9 @@ impl Layout { /// [trait object]: ../../book/ch17-02-trait-objects.html /// [extern type]: ../../unstable-book/language-features/extern-types.html #[unstable(feature = "layout_for_ptr", issue = "69835")] + #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] #[must_use] - pub unsafe fn for_value_raw(t: *const T) -> Self { + pub const unsafe fn for_value_raw(t: *const T) -> Self { // SAFETY: we pass along the prerequisites of these functions to the caller let (size, align) = unsafe { (mem::size_of_val_raw(t), mem::align_of_val_raw(t)) }; // SAFETY: see rationale in `new` for why this is using the unsafe variant @@ -229,8 +231,9 @@ impl Layout { /// Returns an error if the combination of `self.size()` and the given /// `align` violates the conditions listed in [`Layout::from_size_align`]. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] + #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] #[inline] - pub fn align_to(&self, align: usize) -> Result { + pub const fn align_to(&self, align: usize) -> Result { Layout::from_size_align(self.size(), cmp::max(self.align(), align)) } @@ -287,10 +290,11 @@ impl Layout { /// This is equivalent to adding the result of `padding_needed_for` /// to the layout's current size. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] + #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] #[must_use = "this returns a new `Layout`, \ without modifying the original"] #[inline] - pub fn pad_to_align(&self) -> Layout { + pub const fn pad_to_align(&self) -> Layout { let pad = self.padding_needed_for(self.align()); // This cannot overflow. Quoting from the invariant of Layout: // > `size`, when rounded up to the nearest multiple of `align`, @@ -311,8 +315,9 @@ impl Layout { /// /// On arithmetic overflow, returns `LayoutError`. #[unstable(feature = "alloc_layout_extra", issue = "55724")] + #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] #[inline] - pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutError> { + pub const fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutError> { // This cannot overflow. Quoting from the invariant of Layout: // > `size`, when rounded up to the nearest multiple of `align`, // > must not overflow isize (i.e., the rounded value must be @@ -370,8 +375,9 @@ impl Layout { /// # assert_eq!(repr_c(&[u64, u32, u16, u32]), Ok((s, vec![0, 8, 12, 16]))); /// ``` #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] + #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] #[inline] - pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> { + pub const fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> { let new_align = cmp::max(self.align, next.align); let pad = self.padding_needed_for(next.align()); @@ -396,8 +402,9 @@ impl Layout { /// /// On arithmetic overflow, returns `LayoutError`. #[unstable(feature = "alloc_layout_extra", issue = "55724")] + #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] #[inline] - pub fn repeat_packed(&self, n: usize) -> Result { + pub const fn repeat_packed(&self, n: usize) -> Result { let size = self.size().checked_mul(n).ok_or(LayoutError)?; // The safe constructor is called here to enforce the isize size limit. Layout::from_size_alignment(size, self.align) @@ -410,8 +417,9 @@ impl Layout { /// /// On arithmetic overflow, returns `LayoutError`. #[unstable(feature = "alloc_layout_extra", issue = "55724")] + #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] #[inline] - pub fn extend_packed(&self, next: Self) -> Result { + pub const fn extend_packed(&self, next: Self) -> Result { let new_size = self.size().checked_add(next.size()).ok_or(LayoutError)?; // The safe constructor is called here to enforce the isize size limit. Layout::from_size_alignment(new_size, self.align) @@ -422,13 +430,18 @@ impl Layout { /// On arithmetic overflow or when the total size would exceed /// `isize::MAX`, returns `LayoutError`. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] + #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] #[inline] - pub fn array(n: usize) -> Result { + pub const fn array(n: usize) -> Result { // Reduce the amount of code we need to monomorphize per `T`. return inner(mem::size_of::(), Alignment::of::(), n); #[inline] - fn inner(element_size: usize, align: Alignment, n: usize) -> Result { + const fn inner( + element_size: usize, + align: Alignment, + n: usize, + ) -> Result { // We need to check two things about the size: // - That the total size won't overflow a `usize`, and // - That the total size still fits in an `isize`. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 848eccd7f2908..459489942b19c 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -98,6 +98,8 @@ // Library features: #![feature(const_align_offset)] #![feature(const_align_of_val)] +#![feature(const_align_of_val_raw)] +#![feature(const_alloc_layout)] #![feature(const_arguments_as_str)] #![feature(const_array_into_iter_constructors)] #![feature(const_bigint_helper_methods)] @@ -140,6 +142,7 @@ #![feature(const_ptr_write)] #![feature(const_raw_ptr_comparison)] #![feature(const_size_of_val)] +#![feature(const_size_of_val_raw)] #![feature(const_slice_from_raw_parts_mut)] #![feature(const_slice_ptr_len)] #![feature(const_slice_split_at_mut)] diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index 1390e09dd96ae..61eb23c7bca16 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -9,7 +9,7 @@ use crate::{cmp, fmt, hash, mem, num}; /// Note that particularly large alignments, while representable in this type, /// are likely not to be supported by actual allocators and linkers. #[unstable(feature = "ptr_alignment_type", issue = "102070")] -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, Eq)] #[repr(transparent)] pub struct Alignment(AlignmentEnum); @@ -167,16 +167,25 @@ impl From for usize { } } -#[unstable(feature = "ptr_alignment_type", issue = "102070")] -impl cmp::Ord for Alignment { +#[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] +impl const cmp::PartialEq for Alignment { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.as_nonzero().get() == other.as_nonzero().get() + } +} + +#[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] +impl const cmp::Ord for Alignment { #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { - self.as_nonzero().cmp(&other.as_nonzero()) + self.as_nonzero().get().cmp(&other.as_nonzero().get()) } } +#[rustc_const_unstable(feature = "const_alloc_layout", issue = "87864")] #[unstable(feature = "ptr_alignment_type", issue = "102070")] -impl cmp::PartialOrd for Alignment { +impl const cmp::PartialOrd for Alignment { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) From 414e84a2f742b25f10edcfbf78be6779b4ea842b Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Mon, 17 Oct 2022 12:27:27 -0400 Subject: [PATCH 11/20] Add stability for alignment --- library/core/src/ptr/alignment.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index 61eb23c7bca16..fd3e4326ac3d8 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -168,6 +168,7 @@ impl From for usize { } #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] +#[unstable(feature = "ptr_alignment_type", issue = "102070")] impl const cmp::PartialEq for Alignment { #[inline] fn eq(&self, other: &Self) -> bool { @@ -176,6 +177,7 @@ impl const cmp::PartialEq for Alignment { } #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] +#[unstable(feature = "ptr_alignment_type", issue = "102070")] impl const cmp::Ord for Alignment { #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { From 6f2dcac78b536ba66912346766059e52ff5e94a6 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Sat, 12 Nov 2022 14:21:18 -0500 Subject: [PATCH 12/20] Update with derive_const --- library/core/src/alloc/layout.rs | 5 ++++- library/core/src/ptr/alignment.rs | 23 +++++++++++------------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 2c1911c350efc..bea62779bf81d 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -326,7 +326,10 @@ impl Layout { let alloc_size = padded_size.checked_mul(n).ok_or(LayoutError)?; // The safe constructor is called here to enforce the isize size limit. - Layout::from_size_alignment(alloc_size, self.align).map(|layout| (layout, padded_size)) + match Layout::from_size_alignment(alloc_size, self.align) { + Ok(layout) => Ok((layout, padded_size)), + Err(e) => Err(e), + } } /// Creates a layout describing the record for `self` followed by diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index fd3e4326ac3d8..dea979265e6e8 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -10,6 +10,8 @@ use crate::{cmp, fmt, hash, mem, num}; /// are likely not to be supported by actual allocators and linkers. #[unstable(feature = "ptr_alignment_type", issue = "102070")] #[derive(Copy, Clone, Eq)] +#[cfg_attr(bootstrap, derive(PartialEq))] +#[cfg_attr(not(bootstrap), derive_const(PartialEq))] #[repr(transparent)] pub struct Alignment(AlignmentEnum); @@ -167,15 +169,6 @@ impl From for usize { } } -#[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] -#[unstable(feature = "ptr_alignment_type", issue = "102070")] -impl const cmp::PartialEq for Alignment { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.as_nonzero().get() == other.as_nonzero().get() - } -} - #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] #[unstable(feature = "ptr_alignment_type", issue = "102070")] impl const cmp::Ord for Alignment { @@ -209,7 +202,9 @@ type AlignmentEnum = AlignmentEnum32; #[cfg(target_pointer_width = "64")] type AlignmentEnum = AlignmentEnum64; -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, Eq)] +#[cfg_attr(bootstrap, derive(PartialEq))] +#[cfg_attr(not(bootstrap), derive_const(PartialEq))] #[repr(u16)] enum AlignmentEnum16 { _Align1Shl0 = 1 << 0, @@ -230,7 +225,9 @@ enum AlignmentEnum16 { _Align1Shl15 = 1 << 15, } -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, Eq)] +#[cfg_attr(bootstrap, derive(PartialEq))] +#[cfg_attr(not(bootstrap), derive_const(PartialEq))] #[repr(u32)] enum AlignmentEnum32 { _Align1Shl0 = 1 << 0, @@ -267,7 +264,9 @@ enum AlignmentEnum32 { _Align1Shl31 = 1 << 31, } -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, Eq)] +#[cfg_attr(bootstrap, derive(PartialEq))] +#[cfg_attr(not(bootstrap), derive_const(PartialEq))] #[repr(u64)] enum AlignmentEnum64 { _Align1Shl0 = 1 << 0, From 7972b8aa3733f3d07f1794450fd1e28bf51eece4 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Sat, 12 Nov 2022 20:09:42 -0500 Subject: [PATCH 13/20] Add derive_const feature --- library/core/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 459489942b19c..0d190e8a0d53f 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -157,6 +157,7 @@ #![feature(const_unsafecell_get_mut)] #![feature(const_waker)] #![feature(core_panic)] +#![cfg_attr(not(bootstrap), feature(derive_const))] #![feature(duration_consts_float)] #![feature(maybe_uninit_uninit_array)] #![feature(ptr_alignment_type)] From a5fecc690562f23ffe95a0e167bf0a57eca725ad Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Sat, 12 Nov 2022 20:48:32 -0500 Subject: [PATCH 14/20] Fix issue number --- library/core/src/ptr/alignment.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index dea979265e6e8..64a5290c3a267 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -178,7 +178,7 @@ impl const cmp::Ord for Alignment { } } -#[rustc_const_unstable(feature = "const_alloc_layout", issue = "87864")] +#[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")] #[unstable(feature = "ptr_alignment_type", issue = "102070")] impl const cmp::PartialOrd for Alignment { #[inline] From 07911879d2bea1b28aee16451e4a532462d55b00 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Sun, 13 Nov 2022 11:13:32 -0500 Subject: [PATCH 15/20] Use ? instead of match --- library/core/src/alloc/layout.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index bea62779bf81d..ac3d84718d54e 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -326,10 +326,8 @@ impl Layout { let alloc_size = padded_size.checked_mul(n).ok_or(LayoutError)?; // The safe constructor is called here to enforce the isize size limit. - match Layout::from_size_alignment(alloc_size, self.align) { - Ok(layout) => Ok((layout, padded_size)), - Err(e) => Err(e), - } + let layout = Layout::from_size_alignment(alloc_size, self.align)?; + Ok((layout, padded_size)) } /// Creates a layout describing the record for `self` followed by From 60546088bcfa9ce210a5b0f92079f7642f3b466b Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sun, 20 Nov 2022 19:13:17 +0000 Subject: [PATCH 16/20] dist: Ensure UEFI rlibs are all COFF If clang isn't the C compiler used for the UEFI targets, or if the wrong `--target` is passed to clang, we will get ELF objects in some rlibs. This will cause problems at link time when trying to compile a UEFI program that uses any of those objects. Add a check to the dist step for UEFI targets that reads each rlib with the `object` crate and fails with an error if any non-COFF objects are found. --- src/bootstrap/Cargo.lock | 10 ++++++++++ src/bootstrap/Cargo.toml | 1 + src/bootstrap/dist.rs | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index e1a108cea9574..acac9e7a03c60 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -53,6 +53,7 @@ dependencies = [ "hex", "ignore", "libc", + "object", "once_cell", "opener", "pretty_assertions", @@ -400,6 +401,15 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.12.0" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index f74738437ea3a..4000d6cd477e3 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -42,6 +42,7 @@ getopts = "0.2.19" cc = "1.0.69" libc = "0.2" hex = "0.4" +object = { version = "0.29.0", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] } serde = { version = "1.0.8", features = ["derive"] } serde_json = "1.0.2" sha2 = "0.10" diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index aacd2c7eab981..2fef7f65827dd 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -10,10 +10,14 @@ use std::collections::HashSet; use std::env; +use std::ffi::OsStr; use std::fs; use std::path::{Path, PathBuf}; use std::process::Command; +use object::read::archive::ArchiveFile; +use object::BinaryFormat; + use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; use crate::channel; @@ -555,6 +559,39 @@ fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool { } } +/// Check that all objects in rlibs for UEFI targets are COFF. This +/// ensures that the C compiler isn't producing ELF objects, which would +/// not link correctly with the COFF objects. +fn verify_uefi_rlib_format(builder: &Builder<'_>, target: TargetSelection, stamp: &Path) { + if !target.ends_with("-uefi") { + return; + } + + for (path, _) in builder.read_stamp_file(stamp) { + if path.extension() != Some(OsStr::new("rlib")) { + continue; + } + + let data = t!(fs::read(&path)); + let data = data.as_slice(); + let archive = t!(ArchiveFile::parse(data)); + for member in archive.members() { + let member = t!(member); + let member_data = t!(member.data(data)); + + let is_coff = match object::File::parse(member_data) { + Ok(member_file) => member_file.format() == BinaryFormat::Coff, + Err(_) => false, + }; + + if !is_coff { + let member_name = String::from_utf8_lossy(member.name()); + panic!("member {} in {} is not COFF", member_name, path.display()); + } + } + } +} + /// Copy stamped files into an image's `target/lib` directory. fn copy_target_libs(builder: &Builder<'_>, target: TargetSelection, image: &Path, stamp: &Path) { let dst = image.join("lib/rustlib").join(target.triple).join("lib"); @@ -610,6 +647,7 @@ impl Step for Std { let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); let stamp = compile::libstd_stamp(builder, compiler_to_use, target); + verify_uefi_rlib_format(builder, target, &stamp); copy_target_libs(builder, target, &tarball.image_dir(), &stamp); Some(tarball.generate()) From 8998711d9bbd75aad32ef4ade36fa042da7fde13 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Sun, 20 Nov 2022 17:10:47 -0500 Subject: [PATCH 17/20] Only one feature gate needed --- library/core/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 0d190e8a0d53f..459489942b19c 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -157,7 +157,6 @@ #![feature(const_unsafecell_get_mut)] #![feature(const_waker)] #![feature(core_panic)] -#![cfg_attr(not(bootstrap), feature(derive_const))] #![feature(duration_consts_float)] #![feature(maybe_uninit_uninit_array)] #![feature(ptr_alignment_type)] From a9e92be1f98605f343dfc6684107e236e6606947 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 21 Nov 2022 15:10:59 -0800 Subject: [PATCH 18/20] Bump ptr_to_from_bits deprecation to Rust 1.67 --- library/core/src/ptr/const_ptr.rs | 4 ++-- library/core/src/ptr/mut_ptr.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 2c371f635ab97..e966e1bb46687 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -120,7 +120,7 @@ impl *const T { /// ``` #[unstable(feature = "ptr_to_from_bits", issue = "91126")] #[rustc_deprecated( - since = "1.62", + since = "1.67", reason = "replaced by the `exposed_addr` method, or update your code \ to follow the strict provenance rules using its APIs" )] @@ -146,7 +146,7 @@ impl *const T { /// ``` #[unstable(feature = "ptr_to_from_bits", issue = "91126")] #[rustc_deprecated( - since = "1.62", + since = "1.67", reason = "replaced by the `ptr::from_exposed_addr` function, or update \ your code to follow the strict provenance rules using its APIs" )] diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 7968253156237..9507e8430c78f 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -126,7 +126,7 @@ impl *mut T { /// ``` #[unstable(feature = "ptr_to_from_bits", issue = "91126")] #[rustc_deprecated( - since = "1.62", + since = "1.67", reason = "replaced by the `exposed_addr` method, or update your code \ to follow the strict provenance rules using its APIs" )] @@ -152,7 +152,7 @@ impl *mut T { /// ``` #[unstable(feature = "ptr_to_from_bits", issue = "91126")] #[rustc_deprecated( - since = "1.62", + since = "1.67", reason = "replaced by the `ptr::from_exposed_addr_mut` function, or \ update your code to follow the strict provenance rules using its APIs" )] From 6d943af735a86cd7f77305b5723b9481d9bf1f71 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 21 Nov 2022 15:18:36 -0800 Subject: [PATCH 19/20] Rustc_deprecated attribute superseded by deprecated --- library/core/src/ptr/const_ptr.rs | 8 ++++---- library/core/src/ptr/mut_ptr.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index e966e1bb46687..969029e262e02 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -119,9 +119,9 @@ impl *const T { /// assert_eq!(p1.to_bits() - p0.to_bits(), 4); /// ``` #[unstable(feature = "ptr_to_from_bits", issue = "91126")] - #[rustc_deprecated( + #[deprecated( since = "1.67", - reason = "replaced by the `exposed_addr` method, or update your code \ + note = "replaced by the `exposed_addr` method, or update your code \ to follow the strict provenance rules using its APIs" )] pub fn to_bits(self) -> usize @@ -145,9 +145,9 @@ impl *const T { /// assert_eq!(<*const u8>::from_bits(1), dangling); /// ``` #[unstable(feature = "ptr_to_from_bits", issue = "91126")] - #[rustc_deprecated( + #[deprecated( since = "1.67", - reason = "replaced by the `ptr::from_exposed_addr` function, or update \ + note = "replaced by the `ptr::from_exposed_addr` function, or update \ your code to follow the strict provenance rules using its APIs" )] #[allow(fuzzy_provenance_casts)] // this is an unstable and semi-deprecated cast function diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 9507e8430c78f..d1b3a63443379 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -125,9 +125,9 @@ impl *mut T { /// assert_eq!(p1.to_bits() - p0.to_bits(), 4); /// ``` #[unstable(feature = "ptr_to_from_bits", issue = "91126")] - #[rustc_deprecated( + #[deprecated( since = "1.67", - reason = "replaced by the `exposed_addr` method, or update your code \ + note = "replaced by the `exposed_addr` method, or update your code \ to follow the strict provenance rules using its APIs" )] pub fn to_bits(self) -> usize @@ -151,9 +151,9 @@ impl *mut T { /// assert_eq!(<*mut u8>::from_bits(1), dangling); /// ``` #[unstable(feature = "ptr_to_from_bits", issue = "91126")] - #[rustc_deprecated( + #[deprecated( since = "1.67", - reason = "replaced by the `ptr::from_exposed_addr_mut` function, or \ + note = "replaced by the `ptr::from_exposed_addr_mut` function, or \ update your code to follow the strict provenance rules using its APIs" )] #[allow(fuzzy_provenance_casts)] // this is an unstable and semi-deprecated cast function From 70cee5af4b503948f778a4cf8627bbcb62f5d327 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 21 Nov 2022 15:28:41 -0800 Subject: [PATCH 20/20] Touch up Box one-liner --- library/alloc/src/boxed.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 00c922f3ae93f..fc738cb68c37b 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1,4 +1,4 @@ -//! The pointer type for heap allocation for an owned value of type `T`. +//! The `Box` type for heap allocation. //! //! [`Box`], casually referred to as a 'box', provides the simplest form of //! heap allocation in Rust. Boxes provide ownership for this allocation, and @@ -187,7 +187,7 @@ pub use thin::ThinBox; mod thin; -/// A pointer type for heap allocation for an owned value of type `T`. +/// A pointer type that uniquely owns a heap allocation of type `T`. /// /// See the [module-level documentation](../../std/boxed/index.html) for more. #[lang = "owned_box"]