diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index d34c289887e..284bc74d5c4 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1519,7 +1519,7 @@ extern "C" { #[link(name = "llvm-wrapper", kind = "static")] extern "C" { - pub fn LLVMRustInstallFatalErrorHandler(); + pub fn LLVMRustInstallErrorHandlers(); pub fn LLVMRustDisableSystemDialogsOnCrash(); // Create and destroy contexts. diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index e32c38644aa..c9e62e504ae 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -49,7 +49,7 @@ unsafe fn configure_llvm(sess: &Session) { let mut llvm_c_strs = Vec::with_capacity(n_args + 1); let mut llvm_args = Vec::with_capacity(n_args + 1); - llvm::LLVMRustInstallFatalErrorHandler(); + llvm::LLVMRustInstallErrorHandlers(); // On Windows, an LLVM assertion will open an Abort/Retry/Ignore dialog // box for the purpose of launching a debugger. However, on CI this will // cause it to hang until it times out, which can take several hours. diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index a0be1c09c9a..e2010ab3830 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -5,49 +5,11 @@ use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; use rustc_errors::{add_elided_lifetime_in_path_suggestion, Diag}; use rustc_errors::{Applicability, SuggestionStyle}; use rustc_middle::middle::stability; -use rustc_session::config::ExpectedValues; use rustc_session::lint::BuiltinLintDiag; use rustc_session::Session; -use rustc_span::edit_distance::find_best_match_for_name; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::BytePos; -const MAX_CHECK_CFG_NAMES_OR_VALUES: usize = 35; - -fn check_cfg_expected_note( - sess: &Session, - possibilities: &[Symbol], - type_: &str, - name: Option, - suffix: &str, -) -> String { - use std::fmt::Write; - - let n_possibilities = if sess.opts.unstable_opts.check_cfg_all_expected { - possibilities.len() - } else { - std::cmp::min(possibilities.len(), MAX_CHECK_CFG_NAMES_OR_VALUES) - }; - - let mut possibilities = possibilities.iter().map(Symbol::as_str).collect::>(); - possibilities.sort(); - - let and_more = possibilities.len().saturating_sub(n_possibilities); - let possibilities = possibilities[..n_possibilities].join("`, `"); - - let mut note = String::with_capacity(50 + possibilities.len()); - - write!(&mut note, "expected {type_}").unwrap(); - if let Some(name) = name { - write!(&mut note, " for `{name}`").unwrap(); - } - write!(&mut note, " are: {suffix}`{possibilities}`").unwrap(); - if and_more > 0 { - write!(&mut note, " and {and_more} more").unwrap(); - } - - note -} +mod check_cfg; pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Diag<'_, ()>) { match diagnostic { @@ -219,242 +181,11 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di diag.help(help); diag.note("see the asm section of Rust By Example for more information"); } - BuiltinLintDiag::UnexpectedCfgName((name, name_span), value) => { - #[allow(rustc::potential_query_instability)] - let possibilities: Vec = - sess.psess.check_config.expecteds.keys().copied().collect(); - - let mut names_possibilities: Vec<_> = if value.is_none() { - // We later sort and display all the possibilities, so the order here does not matter. - #[allow(rustc::potential_query_instability)] - sess.psess - .check_config - .expecteds - .iter() - .filter_map(|(k, v)| match v { - ExpectedValues::Some(v) if v.contains(&Some(name)) => Some(k), - _ => None, - }) - .collect() - } else { - Vec::new() - }; - - let is_from_cargo = rustc_session::utils::was_invoked_from_cargo(); - let mut is_feature_cfg = name == sym::feature; - - if is_feature_cfg && is_from_cargo { - diag.help("consider defining some features in `Cargo.toml`"); - // Suggest the most probable if we found one - } else if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) { - if let Some(ExpectedValues::Some(best_match_values)) = - sess.psess.check_config.expecteds.get(&best_match) - { - // We will soon sort, so the initial order does not matter. - #[allow(rustc::potential_query_instability)] - let mut possibilities = - best_match_values.iter().flatten().map(Symbol::as_str).collect::>(); - possibilities.sort(); - - let mut should_print_possibilities = true; - if let Some((value, value_span)) = value { - if best_match_values.contains(&Some(value)) { - diag.span_suggestion( - name_span, - "there is a config with a similar name and value", - best_match, - Applicability::MaybeIncorrect, - ); - should_print_possibilities = false; - } else if best_match_values.contains(&None) { - diag.span_suggestion( - name_span.to(value_span), - "there is a config with a similar name and no value", - best_match, - Applicability::MaybeIncorrect, - ); - should_print_possibilities = false; - } else if let Some(first_value) = possibilities.first() { - diag.span_suggestion( - name_span.to(value_span), - "there is a config with a similar name and different values", - format!("{best_match} = \"{first_value}\""), - Applicability::MaybeIncorrect, - ); - } else { - diag.span_suggestion( - name_span.to(value_span), - "there is a config with a similar name and different values", - best_match, - Applicability::MaybeIncorrect, - ); - }; - } else { - diag.span_suggestion( - name_span, - "there is a config with a similar name", - best_match, - Applicability::MaybeIncorrect, - ); - } - - if !possibilities.is_empty() && should_print_possibilities { - let possibilities = possibilities.join("`, `"); - diag.help(format!( - "expected values for `{best_match}` are: `{possibilities}`" - )); - } - } else { - diag.span_suggestion( - name_span, - "there is a config with a similar name", - best_match, - Applicability::MaybeIncorrect, - ); - } - - is_feature_cfg |= best_match == sym::feature; - } else { - if !names_possibilities.is_empty() && names_possibilities.len() <= 3 { - names_possibilities.sort(); - for cfg_name in names_possibilities.iter() { - diag.span_suggestion( - name_span, - "found config with similar value", - format!("{cfg_name} = \"{name}\""), - Applicability::MaybeIncorrect, - ); - } - } - if !possibilities.is_empty() { - diag.help_once(check_cfg_expected_note( - sess, - &possibilities, - "names", - None, - "", - )); - } - } - - let inst = if let Some((value, _value_span)) = value { - let pre = if is_from_cargo { "\\" } else { "" }; - format!("cfg({name}, values({pre}\"{value}{pre}\"))") - } else { - format!("cfg({name})") - }; - - if is_from_cargo { - if !is_feature_cfg { - diag.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`")); - } - diag.note("see for more information about checking conditional configuration"); - } else { - diag.help(format!("to expect this configuration use `--check-cfg={inst}`")); - diag.note("see for more information about checking conditional configuration"); - } + BuiltinLintDiag::UnexpectedCfgName(name, value) => { + check_cfg::unexpected_cfg_name(sess, diag, name, value) } - BuiltinLintDiag::UnexpectedCfgValue((name, name_span), value) => { - let Some(ExpectedValues::Some(values)) = &sess.psess.check_config.expecteds.get(&name) - else { - bug!( - "it shouldn't be possible to have a diagnostic on a value whose name is not in values" - ); - }; - let mut have_none_possibility = false; - // We later sort possibilities if it is not empty, so the - // order here does not matter. - #[allow(rustc::potential_query_instability)] - let possibilities: Vec = values - .iter() - .inspect(|a| have_none_possibility |= a.is_none()) - .copied() - .flatten() - .collect(); - let is_from_cargo = rustc_session::utils::was_invoked_from_cargo(); - - // Show the full list if all possible values for a given name, but don't do it - // for names as the possibilities could be very long - if !possibilities.is_empty() { - diag.note(check_cfg_expected_note( - sess, - &possibilities, - "values", - Some(name), - if have_none_possibility { "(none), " } else { "" }, - )); - - if let Some((value, value_span)) = value { - // Suggest the most probable if we found one - if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) - { - diag.span_suggestion( - value_span, - "there is a expected value with a similar name", - format!("\"{best_match}\""), - Applicability::MaybeIncorrect, - ); - } - } else if let &[first_possibility] = &possibilities[..] { - diag.span_suggestion( - name_span.shrink_to_hi(), - "specify a config value", - format!(" = \"{first_possibility}\""), - Applicability::MaybeIncorrect, - ); - } - } else if have_none_possibility { - diag.note(format!("no expected value for `{name}`")); - if let Some((_value, value_span)) = value { - diag.span_suggestion( - name_span.shrink_to_hi().to(value_span), - "remove the value", - "", - Applicability::MaybeIncorrect, - ); - } - } else { - diag.note(format!("no expected values for `{name}`")); - - let sp = if let Some((_value, value_span)) = value { - name_span.to(value_span) - } else { - name_span - }; - diag.span_suggestion(sp, "remove the condition", "", Applicability::MaybeIncorrect); - } - - // We don't want to suggest adding values to well known names - // since those are defined by rustc it-self. Users can still - // do it if they want, but should not encourage them. - let is_cfg_a_well_know_name = sess.psess.check_config.well_known_names.contains(&name); - - let inst = if let Some((value, _value_span)) = value { - let pre = if is_from_cargo { "\\" } else { "" }; - format!("cfg({name}, values({pre}\"{value}{pre}\"))") - } else { - format!("cfg({name})") - }; - - if is_from_cargo { - if name == sym::feature { - if let Some((value, _value_span)) = value { - diag.help(format!( - "consider adding `{value}` as a feature in `Cargo.toml`" - )); - } else { - diag.help("consider defining some features in `Cargo.toml`"); - } - } else if !is_cfg_a_well_know_name { - diag.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`")); - } - diag.note("see for more information about checking conditional configuration"); - } else { - if !is_cfg_a_well_know_name { - diag.help(format!("to expect this configuration use `--check-cfg={inst}`")); - } - diag.note("see for more information about checking conditional configuration"); - } + BuiltinLintDiag::UnexpectedCfgValue(name, value) => { + check_cfg::unexpected_cfg_value(sess, diag, name, value) } BuiltinLintDiag::DeprecatedWhereclauseLocation(sugg) => { let left_sp = diag.span.primary_span().unwrap(); diff --git a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs new file mode 100644 index 00000000000..2c9a3a6d1b2 --- /dev/null +++ b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs @@ -0,0 +1,277 @@ +use rustc_errors::{Applicability, Diag}; +use rustc_session::{config::ExpectedValues, Session}; +use rustc_span::edit_distance::find_best_match_for_name; +use rustc_span::{sym, Span, Symbol}; + +const MAX_CHECK_CFG_NAMES_OR_VALUES: usize = 35; + +fn check_cfg_expected_note( + sess: &Session, + possibilities: &[Symbol], + type_: &str, + name: Option, + suffix: &str, +) -> String { + use std::fmt::Write; + + let n_possibilities = if sess.opts.unstable_opts.check_cfg_all_expected { + possibilities.len() + } else { + std::cmp::min(possibilities.len(), MAX_CHECK_CFG_NAMES_OR_VALUES) + }; + + let mut possibilities = possibilities.iter().map(Symbol::as_str).collect::>(); + possibilities.sort(); + + let and_more = possibilities.len().saturating_sub(n_possibilities); + let possibilities = possibilities[..n_possibilities].join("`, `"); + + let mut note = String::with_capacity(50 + possibilities.len()); + + write!(&mut note, "expected {type_}").unwrap(); + if let Some(name) = name { + write!(&mut note, " for `{name}`").unwrap(); + } + write!(&mut note, " are: {suffix}`{possibilities}`").unwrap(); + if and_more > 0 { + write!(&mut note, " and {and_more} more").unwrap(); + } + + note +} + +pub(super) fn unexpected_cfg_name( + sess: &Session, + diag: &mut Diag<'_, ()>, + (name, name_span): (Symbol, Span), + value: Option<(Symbol, Span)>, +) { + #[allow(rustc::potential_query_instability)] + let possibilities: Vec = sess.psess.check_config.expecteds.keys().copied().collect(); + + let mut names_possibilities: Vec<_> = if value.is_none() { + // We later sort and display all the possibilities, so the order here does not matter. + #[allow(rustc::potential_query_instability)] + sess.psess + .check_config + .expecteds + .iter() + .filter_map(|(k, v)| match v { + ExpectedValues::Some(v) if v.contains(&Some(name)) => Some(k), + _ => None, + }) + .collect() + } else { + Vec::new() + }; + + let is_from_cargo = rustc_session::utils::was_invoked_from_cargo(); + let mut is_feature_cfg = name == sym::feature; + + if is_feature_cfg && is_from_cargo { + diag.help("consider defining some features in `Cargo.toml`"); + // Suggest the most probable if we found one + } else if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) { + if let Some(ExpectedValues::Some(best_match_values)) = + sess.psess.check_config.expecteds.get(&best_match) + { + // We will soon sort, so the initial order does not matter. + #[allow(rustc::potential_query_instability)] + let mut possibilities = + best_match_values.iter().flatten().map(Symbol::as_str).collect::>(); + possibilities.sort(); + + let mut should_print_possibilities = true; + if let Some((value, value_span)) = value { + if best_match_values.contains(&Some(value)) { + diag.span_suggestion( + name_span, + "there is a config with a similar name and value", + best_match, + Applicability::MaybeIncorrect, + ); + should_print_possibilities = false; + } else if best_match_values.contains(&None) { + diag.span_suggestion( + name_span.to(value_span), + "there is a config with a similar name and no value", + best_match, + Applicability::MaybeIncorrect, + ); + should_print_possibilities = false; + } else if let Some(first_value) = possibilities.first() { + diag.span_suggestion( + name_span.to(value_span), + "there is a config with a similar name and different values", + format!("{best_match} = \"{first_value}\""), + Applicability::MaybeIncorrect, + ); + } else { + diag.span_suggestion( + name_span.to(value_span), + "there is a config with a similar name and different values", + best_match, + Applicability::MaybeIncorrect, + ); + }; + } else { + diag.span_suggestion( + name_span, + "there is a config with a similar name", + best_match, + Applicability::MaybeIncorrect, + ); + } + + if !possibilities.is_empty() && should_print_possibilities { + let possibilities = possibilities.join("`, `"); + diag.help(format!("expected values for `{best_match}` are: `{possibilities}`")); + } + } else { + diag.span_suggestion( + name_span, + "there is a config with a similar name", + best_match, + Applicability::MaybeIncorrect, + ); + } + + is_feature_cfg |= best_match == sym::feature; + } else { + if !names_possibilities.is_empty() && names_possibilities.len() <= 3 { + names_possibilities.sort(); + for cfg_name in names_possibilities.iter() { + diag.span_suggestion( + name_span, + "found config with similar value", + format!("{cfg_name} = \"{name}\""), + Applicability::MaybeIncorrect, + ); + } + } + if !possibilities.is_empty() { + diag.help_once(check_cfg_expected_note(sess, &possibilities, "names", None, "")); + } + } + + let inst = if let Some((value, _value_span)) = value { + let pre = if is_from_cargo { "\\" } else { "" }; + format!("cfg({name}, values({pre}\"{value}{pre}\"))") + } else { + format!("cfg({name})") + }; + + if is_from_cargo { + if !is_feature_cfg { + diag.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`")); + } + diag.note("see for more information about checking conditional configuration"); + } else { + diag.help(format!("to expect this configuration use `--check-cfg={inst}`")); + diag.note("see for more information about checking conditional configuration"); + } +} + +pub(super) fn unexpected_cfg_value( + sess: &Session, + diag: &mut Diag<'_, ()>, + (name, name_span): (Symbol, Span), + value: Option<(Symbol, Span)>, +) { + let Some(ExpectedValues::Some(values)) = &sess.psess.check_config.expecteds.get(&name) else { + bug!( + "it shouldn't be possible to have a diagnostic on a value whose name is not in values" + ); + }; + let mut have_none_possibility = false; + // We later sort possibilities if it is not empty, so the + // order here does not matter. + #[allow(rustc::potential_query_instability)] + let possibilities: Vec = values + .iter() + .inspect(|a| have_none_possibility |= a.is_none()) + .copied() + .flatten() + .collect(); + let is_from_cargo = rustc_session::utils::was_invoked_from_cargo(); + + // Show the full list if all possible values for a given name, but don't do it + // for names as the possibilities could be very long + if !possibilities.is_empty() { + diag.note(check_cfg_expected_note( + sess, + &possibilities, + "values", + Some(name), + if have_none_possibility { "(none), " } else { "" }, + )); + + if let Some((value, value_span)) = value { + // Suggest the most probable if we found one + if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) { + diag.span_suggestion( + value_span, + "there is a expected value with a similar name", + format!("\"{best_match}\""), + Applicability::MaybeIncorrect, + ); + } + } else if let &[first_possibility] = &possibilities[..] { + diag.span_suggestion( + name_span.shrink_to_hi(), + "specify a config value", + format!(" = \"{first_possibility}\""), + Applicability::MaybeIncorrect, + ); + } + } else if have_none_possibility { + diag.note(format!("no expected value for `{name}`")); + if let Some((_value, value_span)) = value { + diag.span_suggestion( + name_span.shrink_to_hi().to(value_span), + "remove the value", + "", + Applicability::MaybeIncorrect, + ); + } + } else { + diag.note(format!("no expected values for `{name}`")); + + let sp = if let Some((_value, value_span)) = value { + name_span.to(value_span) + } else { + name_span + }; + diag.span_suggestion(sp, "remove the condition", "", Applicability::MaybeIncorrect); + } + + // We don't want to suggest adding values to well known names + // since those are defined by rustc it-self. Users can still + // do it if they want, but should not encourage them. + let is_cfg_a_well_know_name = sess.psess.check_config.well_known_names.contains(&name); + + let inst = if let Some((value, _value_span)) = value { + let pre = if is_from_cargo { "\\" } else { "" }; + format!("cfg({name}, values({pre}\"{value}{pre}\"))") + } else { + format!("cfg({name})") + }; + + if is_from_cargo { + if name == sym::feature { + if let Some((value, _value_span)) = value { + diag.help(format!("consider adding `{value}` as a feature in `Cargo.toml`")); + } else { + diag.help("consider defining some features in `Cargo.toml`"); + } + } else if !is_cfg_a_well_know_name { + diag.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`")); + } + diag.note("see for more information about checking conditional configuration"); + } else { + if !is_cfg_a_well_know_name { + diag.help(format!("to expect this configuration use `--check-cfg={inst}`")); + } + diag.note("see for more information about checking conditional configuration"); + } +} diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 1632b9e1249..91f54da5c12 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -25,6 +25,13 @@ #include +// for raw `write` in the bad-alloc handler +#ifdef _MSC_VER +#include +#else +#include +#endif + //===----------------------------------------------------------------------=== // // This file defines alternate interfaces to core functions that are more @@ -88,8 +95,24 @@ static void FatalErrorHandler(void *UserData, exit(101); } -extern "C" void LLVMRustInstallFatalErrorHandler() { +// Custom error handler for bad-alloc LLVM errors. +// +// It aborts the process without any further allocations, similar to LLVM's +// default except that may be configured to `throw std::bad_alloc()` instead. +static void BadAllocErrorHandler(void *UserData, + const char* Reason, + bool GenCrashDiag) { + const char *OOM = "rustc-LLVM ERROR: out of memory\n"; + (void)!::write(2, OOM, strlen(OOM)); + (void)!::write(2, Reason, strlen(Reason)); + (void)!::write(2, "\n", 1); + abort(); +} + +extern "C" void LLVMRustInstallErrorHandlers() { + install_bad_alloc_error_handler(BadAllocErrorHandler); install_fatal_error_handler(FatalErrorHandler); + install_out_of_memory_new_handler(); } extern "C" void LLVMRustDisableSystemDialogsOnCrash() { diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 9b786feba89..6473f772e30 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -112,6 +112,7 @@ // // Library features: // tidy-alphabetical-start +#![feature(array_ptr_get)] #![feature(char_indices_offset)] #![feature(const_align_of_val)] #![feature(const_align_of_val_raw)] diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index a0c04d3f65d..979fd1e4b4a 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1798,6 +1798,46 @@ impl *const [T] { } } +impl *const [T; N] { + /// Returns a raw pointer to the array's buffer. + /// + /// This is equivalent to casting `self` to `*const T`, but more type-safe. + /// + /// # Examples + /// + /// ```rust + /// #![feature(array_ptr_get)] + /// use std::ptr; + /// + /// let arr: *const [i8; 3] = ptr::null(); + /// assert_eq!(arr.as_ptr(), ptr::null()); + /// ``` + #[inline] + #[unstable(feature = "array_ptr_get", issue = "119834")] + #[rustc_const_unstable(feature = "array_ptr_get", issue = "119834")] + pub const fn as_ptr(self) -> *const T { + self as *const T + } + + /// Returns a raw pointer to a slice containing the entire array. + /// + /// # Examples + /// + /// ``` + /// #![feature(array_ptr_get, slice_ptr_len)] + /// + /// let arr: *const [i32; 3] = &[1, 2, 4] as *const [i32; 3]; + /// let slice: *const [i32] = arr.as_slice(); + /// assert_eq!(slice.len(), 3); + /// ``` + #[inline] + #[unstable(feature = "array_ptr_get", issue = "119834")] + #[rustc_const_unstable(feature = "array_ptr_get", issue = "119834")] + pub const fn as_slice(self) -> *const [T] { + self + } +} + // Equality for pointers #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for *const T { diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 6a9033a144d..bfdd9dba320 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -2209,6 +2209,49 @@ impl *mut [T] { } } +impl *mut [T; N] { + /// Returns a raw pointer to the array's buffer. + /// + /// This is equivalent to casting `self` to `*mut T`, but more type-safe. + /// + /// # Examples + /// + /// ```rust + /// #![feature(array_ptr_get)] + /// use std::ptr; + /// + /// let arr: *mut [i8; 3] = ptr::null_mut(); + /// assert_eq!(arr.as_mut_ptr(), ptr::null_mut()); + /// ``` + #[inline] + #[unstable(feature = "array_ptr_get", issue = "119834")] + #[rustc_const_unstable(feature = "array_ptr_get", issue = "119834")] + pub const fn as_mut_ptr(self) -> *mut T { + self as *mut T + } + + /// Returns a raw pointer to a mutable slice containing the entire array. + /// + /// # Examples + /// + /// ``` + /// #![feature(array_ptr_get)] + /// + /// let mut arr = [1, 2, 5]; + /// let ptr: *mut [i32; 3] = &mut arr; + /// unsafe { + /// (&mut *ptr.as_mut_slice())[..2].copy_from_slice(&[3, 4]); + /// } + /// assert_eq!(arr, [3, 4, 5]); + /// ``` + #[inline] + #[unstable(feature = "array_ptr_get", issue = "119834")] + #[rustc_const_unstable(feature = "array_ptr_get", issue = "119834")] + pub const fn as_mut_slice(self) -> *mut [T] { + self + } +} + // Equality for pointers #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for *mut T { diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index c5a7e87c4aa..421062f5873 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -1,5 +1,6 @@ #![feature(alloc_layout_extra)] #![feature(array_chunks)] +#![feature(array_ptr_get)] #![feature(array_windows)] #![feature(ascii_char)] #![feature(ascii_char_variants)] @@ -52,6 +53,7 @@ #![feature(sort_internals)] #![feature(slice_take)] #![feature(slice_from_ptr_range)] +#![feature(slice_ptr_len)] #![feature(slice_split_once)] #![feature(split_as_slice)] #![feature(maybe_uninit_fill)] diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index 659fbd255c1..5c518e2d593 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -1141,3 +1141,16 @@ fn test_const_copy() { assert!(*ptr2 == 1); }; } + +#[test] +fn test_null_array_as_slice() { + let arr: *mut [u8; 4] = null_mut(); + let ptr: *mut [u8] = arr.as_mut_slice(); + assert!(ptr.is_null()); + assert_eq!(ptr.len(), 4); + + let arr: *const [u8; 4] = null(); + let ptr: *const [u8] = arr.as_slice(); + assert!(ptr.is_null()); + assert_eq!(ptr.len(), 4); +} diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 690e20fb6b9..6d3163b90b1 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1548,6 +1548,10 @@ impl Step for MirOpt { }) }; + run(self.target); + + // Run more targets with `--bless`. But we always run the host target first, since some + // tests use very specific `only` clauses that are not covered by the target set below. if builder.config.cmd.bless() { // All that we really need to do is cover all combinations of 32/64-bit and unwind/abort, // but while we're at it we might as well flex our cross-compilation support. This @@ -1566,8 +1570,6 @@ impl Step for MirOpt { }); run(panic_abort_target); } - } else { - run(self.target); } } } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index f427055728f..83c595ce241 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -3734,36 +3734,42 @@ impl<'test> TestCx<'test> { debug!(?support_lib_deps); debug!(?support_lib_deps_deps); - let res = self.cmd2procres( - Command::new(&self.config.rustc_path) - .arg("-o") - .arg(&recipe_bin) - .arg(format!( - "-Ldependency={}", - &support_lib_path.parent().unwrap().to_string_lossy() - )) - .arg(format!("-Ldependency={}", &support_lib_deps.to_string_lossy())) - .arg(format!("-Ldependency={}", &support_lib_deps_deps.to_string_lossy())) - .arg("--extern") - .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy())) - .arg(&self.testpaths.file.join("rmake.rs")) - .env("TARGET", &self.config.target) - .env("PYTHON", &self.config.python) - .env("S", &src_root) - .env("RUST_BUILD_STAGE", &self.config.stage_id) - .env("RUSTC", cwd.join(&self.config.rustc_path)) - .env("TMPDIR", &tmpdir) - .env("LD_LIB_PATH_ENVVAR", dylib_env_var()) - .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path)) - .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path)) - .env("LLVM_COMPONENTS", &self.config.llvm_components) - // We for sure don't want these tests to run in parallel, so make - // sure they don't have access to these vars if we run via `make` - // at the top level - .env_remove("MAKEFLAGS") - .env_remove("MFLAGS") - .env_remove("CARGO_MAKEFLAGS"), - ); + let mut cmd = Command::new(&self.config.rustc_path); + cmd.arg("-o") + .arg(&recipe_bin) + .arg(format!("-Ldependency={}", &support_lib_path.parent().unwrap().to_string_lossy())) + .arg(format!("-Ldependency={}", &support_lib_deps.to_string_lossy())) + .arg(format!("-Ldependency={}", &support_lib_deps_deps.to_string_lossy())) + .arg("--extern") + .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy())) + .arg(&self.testpaths.file.join("rmake.rs")) + .env("TARGET", &self.config.target) + .env("PYTHON", &self.config.python) + .env("S", &src_root) + .env("RUST_BUILD_STAGE", &self.config.stage_id) + .env("RUSTC", cwd.join(&self.config.rustc_path)) + .env("TMPDIR", &tmpdir) + .env("LD_LIB_PATH_ENVVAR", dylib_env_var()) + .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path)) + .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path)) + .env("LLVM_COMPONENTS", &self.config.llvm_components) + // We for sure don't want these tests to run in parallel, so make + // sure they don't have access to these vars if we run via `make` + // at the top level + .env_remove("MAKEFLAGS") + .env_remove("MFLAGS") + .env_remove("CARGO_MAKEFLAGS"); + + if std::env::var_os("COMPILETEST_FORCE_STAGE0").is_some() { + let mut stage0_sysroot = build_root.clone(); + stage0_sysroot.push("stage0-sysroot"); + debug!(?stage0_sysroot); + debug!(exists = stage0_sysroot.exists()); + + cmd.arg("--sysroot").arg(&stage0_sysroot); + } + + let res = self.cmd2procres(&mut cmd); if !res.status.success() { self.fatal_proc_rec("run-make test failed: could not build `rmake.rs` recipe", &res); } diff --git a/triagebot.toml b/triagebot.toml index 89ffb2f41bb..515600793da 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -515,6 +515,9 @@ cc = ["@Nadrieril"] message = "Some changes occurred in exhaustiveness checking" cc = ["@Nadrieril"] +[mentions."compiler/rustc_lint/src/context/diagnostics/check_cfg.rs"] +cc = ["@Urgau"] + [mentions."library/core/src/intrinsics/simd.rs"] message = """ Some changes occurred to the platform-builtins intrinsics. Make sure the @@ -699,6 +702,9 @@ cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"] [mentions."src/doc/unstable-book/src/language-features/no-sanitize.md"] cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"] +[mentions."src/doc/unstable-book/src/compiler-flags/check-cfg.md"] +cc = ["@Urgau"] + [mentions."tests/codegen/sanitizer"] cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"] @@ -717,6 +723,9 @@ cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"] [mentions."tests/ui/stack-protector"] cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"] +[mentions."tests/ui/check-cfg"] +cc = ["@Urgau"] + [assign] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"