diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index c7fcfe3ce2aa0..57390dd58f4d9 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -218,6 +218,13 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { warnings: self.warnings, suggest_unsafe_block: self.suggest_unsafe_block, }; + // params in THIR may be unsafe, e.g. a union pattern. + for param in &inner_thir.params { + if let Some(param_pat) = param.pat.as_deref() { + inner_visitor.visit_pat(param_pat); + } + } + // Visit the body. inner_visitor.visit_expr(&inner_thir[expr]); // Unsafe blocks can be used in the inner body, make sure to take it into account self.safety_context = inner_visitor.safety_context; @@ -1032,6 +1039,13 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { warnings: &mut warnings, suggest_unsafe_block: true, }; + // params in THIR may be unsafe, e.g. a union pattern. + for param in &thir.params { + if let Some(param_pat) = param.pat.as_deref() { + visitor.visit_pat(param_pat); + } + } + // Visit the body. visitor.visit_expr(&thir[expr]); warnings.sort_by_key(|w| w.block_span); diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index bc5c7c32490ef..fcaa91184d3e1 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -672,8 +672,9 @@ impl char { /// 'ß'.encode_utf8(&mut b); /// ``` #[stable(feature = "unicode_encode_char", since = "1.15.0")] + #[rustc_const_unstable(feature = "const_char_encode_utf8", issue = "130512")] #[inline] - pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str { + pub const fn encode_utf8(self, dst: &mut [u8]) -> &mut str { // SAFETY: `char` is not a surrogate, so this is valid UTF-8. unsafe { from_utf8_unchecked_mut(encode_utf8_raw(self as u32, dst)) } } @@ -1735,14 +1736,11 @@ impl EscapeDebugExtArgs { #[inline] const fn len_utf8(code: u32) -> usize { - if code < MAX_ONE_B { - 1 - } else if code < MAX_TWO_B { - 2 - } else if code < MAX_THREE_B { - 3 - } else { - 4 + match code { + ..MAX_ONE_B => 1, + ..MAX_TWO_B => 2, + ..MAX_THREE_B => 3, + _ => 4, } } @@ -1760,11 +1758,12 @@ const fn len_utf8(code: u32) -> usize { /// Panics if the buffer is not large enough. /// A buffer of length four is large enough to encode any `char`. #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] +#[rustc_const_unstable(feature = "const_char_encode_utf8", issue = "130512")] #[doc(hidden)] #[inline] -pub fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] { +pub const fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] { let len = len_utf8(code); - match (len, &mut dst[..]) { + match (len, &mut *dst) { (1, [a, ..]) => { *a = code as u8; } @@ -1783,14 +1782,11 @@ pub fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] { *c = (code >> 6 & 0x3F) as u8 | TAG_CONT; *d = (code & 0x3F) as u8 | TAG_CONT; } - _ => panic!( - "encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}", - len, - code, - dst.len(), - ), + // Note that we cannot format in constant expressions. + _ => panic!("encode_utf8: buffer does not have enough bytes to encode code point"), }; - &mut dst[..len] + // SAFETY: `<&mut [u8]>::as_mut_ptr` is guaranteed to return a valid pointer and `len` has been tested to be within bounds. + unsafe { slice::from_raw_parts_mut(dst.as_mut_ptr(), len) } } /// Encodes a raw u32 value as UTF-16 into the provided `u16` buffer, diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 348ccebea3b84..759d017eb2fcc 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -119,6 +119,7 @@ #![feature(const_bigint_helper_methods)] #![feature(const_black_box)] #![feature(const_cell_into_inner)] +#![feature(const_char_encode_utf8)] #![feature(const_eval_select)] #![feature(const_exact_div)] #![feature(const_float_classify)] diff --git a/tests/ui/macros/auxiliary/metavar_2018.rs b/tests/ui/macros/auxiliary/metavar_2018.rs new file mode 100644 index 0000000000000..7e8523a9edf1b --- /dev/null +++ b/tests/ui/macros/auxiliary/metavar_2018.rs @@ -0,0 +1,14 @@ +//@ edition: 2018 +#[macro_export] +macro_rules! make_matcher { + ($name:ident, $fragment_type:ident, $d:tt) => { + #[macro_export] + macro_rules! $name { + ($d _:$fragment_type) => { true }; + (const { 0 }) => { false }; + (A | B) => { false }; + } + }; +} +make_matcher!(is_expr_from_2018, expr, $); +make_matcher!(is_pat_from_2018, pat, $); diff --git a/tests/ui/macros/metavar_cross_edition_recursive_macros.rs b/tests/ui/macros/metavar_cross_edition_recursive_macros.rs new file mode 100644 index 0000000000000..3eec1208b89ae --- /dev/null +++ b/tests/ui/macros/metavar_cross_edition_recursive_macros.rs @@ -0,0 +1,38 @@ +//@ compile-flags: --edition=2024 -Z unstable-options +//@ aux-build: metavar_2018.rs +//@ known-bug: #130484 +//@ run-pass + +// This test captures the behavior of macro-generating-macros with fragment +// specifiers across edition boundaries. + +#![feature(expr_fragment_specifier_2024)] +#![feature(macro_metavar_expr)] +#![allow(incomplete_features)] + +extern crate metavar_2018; + +use metavar_2018::{is_expr_from_2018, is_pat_from_2018, make_matcher}; + +make_matcher!(is_expr_from_2024, expr, $); +make_matcher!(is_pat_from_2024, pat, $); + +fn main() { + // Check expr + let from_2018 = is_expr_from_2018!(const { 0 }); + dbg!(from_2018); + let from_2024 = is_expr_from_2024!(const { 0 }); + dbg!(from_2024); + + assert!(!from_2018); + assert!(!from_2024); // from_2024 will be true once #130484 is fixed + + // Check pat + let from_2018 = is_pat_from_2018!(A | B); + dbg!(from_2018); + let from_2024 = is_pat_from_2024!(A | B); + dbg!(from_2024); + + assert!(!from_2018); + assert!(!from_2024); // from_2024 will be true once #130484 is fixed +} diff --git a/tests/ui/unsafe/union-pat-in-param.rs b/tests/ui/unsafe/union-pat-in-param.rs new file mode 100644 index 0000000000000..8454bfb20dcb8 --- /dev/null +++ b/tests/ui/unsafe/union-pat-in-param.rs @@ -0,0 +1,19 @@ +union U { + a: &'static i32, + b: usize, +} + +fn fun(U { a }: U) { + //~^ ERROR access to union field is unsafe + dbg!(*a); +} + +fn main() { + fun(U { b: 0 }); + + let closure = |U { a }| { + //~^ ERROR access to union field is unsafe + dbg!(*a); + }; + closure(U { b: 0 }); +} diff --git a/tests/ui/unsafe/union-pat-in-param.stderr b/tests/ui/unsafe/union-pat-in-param.stderr new file mode 100644 index 0000000000000..b9709b7cc9bf1 --- /dev/null +++ b/tests/ui/unsafe/union-pat-in-param.stderr @@ -0,0 +1,19 @@ +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-pat-in-param.rs:6:12 + | +LL | fn fun(U { a }: U) { + | ^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error[E0133]: access to union field is unsafe and requires unsafe function or block + --> $DIR/union-pat-in-param.rs:14:24 + | +LL | let closure = |U { a }| { + | ^ access to union field + | + = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`.