Skip to content

Commit a6d2ada

Browse files
committed
Auto merge of rust-lang#130541 - workingjubilee:rollup-26jmumi, r=workingjubilee
Rollup of 3 pull requests Successful merges: - rust-lang#129755 (test: cross-edition metavar fragment specifiers) - rust-lang#130511 (Support `char::encode_utf8` in const scenarios.) - rust-lang#130531 (Check params for unsafety in THIR) r? `@ghost` `@rustbot` modify labels: rollup
2 parents df7f778 + 05f8f46 commit a6d2ada

File tree

7 files changed

+119
-18
lines changed

7 files changed

+119
-18
lines changed

compiler/rustc_mir_build/src/check_unsafety.rs

+14
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,13 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
218218
warnings: self.warnings,
219219
suggest_unsafe_block: self.suggest_unsafe_block,
220220
};
221+
// params in THIR may be unsafe, e.g. a union pattern.
222+
for param in &inner_thir.params {
223+
if let Some(param_pat) = param.pat.as_deref() {
224+
inner_visitor.visit_pat(param_pat);
225+
}
226+
}
227+
// Visit the body.
221228
inner_visitor.visit_expr(&inner_thir[expr]);
222229
// Unsafe blocks can be used in the inner body, make sure to take it into account
223230
self.safety_context = inner_visitor.safety_context;
@@ -1032,6 +1039,13 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
10321039
warnings: &mut warnings,
10331040
suggest_unsafe_block: true,
10341041
};
1042+
// params in THIR may be unsafe, e.g. a union pattern.
1043+
for param in &thir.params {
1044+
if let Some(param_pat) = param.pat.as_deref() {
1045+
visitor.visit_pat(param_pat);
1046+
}
1047+
}
1048+
// Visit the body.
10351049
visitor.visit_expr(&thir[expr]);
10361050

10371051
warnings.sort_by_key(|w| w.block_span);

library/core/src/char/methods.rs

+14-18
Original file line numberDiff line numberDiff line change
@@ -672,8 +672,9 @@ impl char {
672672
/// 'ß'.encode_utf8(&mut b);
673673
/// ```
674674
#[stable(feature = "unicode_encode_char", since = "1.15.0")]
675+
#[rustc_const_unstable(feature = "const_char_encode_utf8", issue = "130512")]
675676
#[inline]
676-
pub fn encode_utf8(self, dst: &mut [u8]) -> &mut str {
677+
pub const fn encode_utf8(self, dst: &mut [u8]) -> &mut str {
677678
// SAFETY: `char` is not a surrogate, so this is valid UTF-8.
678679
unsafe { from_utf8_unchecked_mut(encode_utf8_raw(self as u32, dst)) }
679680
}
@@ -1735,14 +1736,11 @@ impl EscapeDebugExtArgs {
17351736

17361737
#[inline]
17371738
const fn len_utf8(code: u32) -> usize {
1738-
if code < MAX_ONE_B {
1739-
1
1740-
} else if code < MAX_TWO_B {
1741-
2
1742-
} else if code < MAX_THREE_B {
1743-
3
1744-
} else {
1745-
4
1739+
match code {
1740+
..MAX_ONE_B => 1,
1741+
..MAX_TWO_B => 2,
1742+
..MAX_THREE_B => 3,
1743+
_ => 4,
17461744
}
17471745
}
17481746

@@ -1760,11 +1758,12 @@ const fn len_utf8(code: u32) -> usize {
17601758
/// Panics if the buffer is not large enough.
17611759
/// A buffer of length four is large enough to encode any `char`.
17621760
#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
1761+
#[rustc_const_unstable(feature = "const_char_encode_utf8", issue = "130512")]
17631762
#[doc(hidden)]
17641763
#[inline]
1765-
pub fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] {
1764+
pub const fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] {
17661765
let len = len_utf8(code);
1767-
match (len, &mut dst[..]) {
1766+
match (len, &mut *dst) {
17681767
(1, [a, ..]) => {
17691768
*a = code as u8;
17701769
}
@@ -1783,14 +1782,11 @@ pub fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> &mut [u8] {
17831782
*c = (code >> 6 & 0x3F) as u8 | TAG_CONT;
17841783
*d = (code & 0x3F) as u8 | TAG_CONT;
17851784
}
1786-
_ => panic!(
1787-
"encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}",
1788-
len,
1789-
code,
1790-
dst.len(),
1791-
),
1785+
// Note that we cannot format in constant expressions.
1786+
_ => panic!("encode_utf8: buffer does not have enough bytes to encode code point"),
17921787
};
1793-
&mut dst[..len]
1788+
// SAFETY: `<&mut [u8]>::as_mut_ptr` is guaranteed to return a valid pointer and `len` has been tested to be within bounds.
1789+
unsafe { slice::from_raw_parts_mut(dst.as_mut_ptr(), len) }
17941790
}
17951791

17961792
/// Encodes a raw u32 value as UTF-16 into the provided `u16` buffer,

library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
#![feature(const_bigint_helper_methods)]
120120
#![feature(const_black_box)]
121121
#![feature(const_cell_into_inner)]
122+
#![feature(const_char_encode_utf8)]
122123
#![feature(const_eval_select)]
123124
#![feature(const_exact_div)]
124125
#![feature(const_float_classify)]
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//@ edition: 2018
2+
#[macro_export]
3+
macro_rules! make_matcher {
4+
($name:ident, $fragment_type:ident, $d:tt) => {
5+
#[macro_export]
6+
macro_rules! $name {
7+
($d _:$fragment_type) => { true };
8+
(const { 0 }) => { false };
9+
(A | B) => { false };
10+
}
11+
};
12+
}
13+
make_matcher!(is_expr_from_2018, expr, $);
14+
make_matcher!(is_pat_from_2018, pat, $);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//@ compile-flags: --edition=2024 -Z unstable-options
2+
//@ aux-build: metavar_2018.rs
3+
//@ known-bug: #130484
4+
//@ run-pass
5+
6+
// This test captures the behavior of macro-generating-macros with fragment
7+
// specifiers across edition boundaries.
8+
9+
#![feature(expr_fragment_specifier_2024)]
10+
#![feature(macro_metavar_expr)]
11+
#![allow(incomplete_features)]
12+
13+
extern crate metavar_2018;
14+
15+
use metavar_2018::{is_expr_from_2018, is_pat_from_2018, make_matcher};
16+
17+
make_matcher!(is_expr_from_2024, expr, $);
18+
make_matcher!(is_pat_from_2024, pat, $);
19+
20+
fn main() {
21+
// Check expr
22+
let from_2018 = is_expr_from_2018!(const { 0 });
23+
dbg!(from_2018);
24+
let from_2024 = is_expr_from_2024!(const { 0 });
25+
dbg!(from_2024);
26+
27+
assert!(!from_2018);
28+
assert!(!from_2024); // from_2024 will be true once #130484 is fixed
29+
30+
// Check pat
31+
let from_2018 = is_pat_from_2018!(A | B);
32+
dbg!(from_2018);
33+
let from_2024 = is_pat_from_2024!(A | B);
34+
dbg!(from_2024);
35+
36+
assert!(!from_2018);
37+
assert!(!from_2024); // from_2024 will be true once #130484 is fixed
38+
}

tests/ui/unsafe/union-pat-in-param.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
union U {
2+
a: &'static i32,
3+
b: usize,
4+
}
5+
6+
fn fun(U { a }: U) {
7+
//~^ ERROR access to union field is unsafe
8+
dbg!(*a);
9+
}
10+
11+
fn main() {
12+
fun(U { b: 0 });
13+
14+
let closure = |U { a }| {
15+
//~^ ERROR access to union field is unsafe
16+
dbg!(*a);
17+
};
18+
closure(U { b: 0 });
19+
}
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0133]: access to union field is unsafe and requires unsafe function or block
2+
--> $DIR/union-pat-in-param.rs:6:12
3+
|
4+
LL | fn fun(U { a }: U) {
5+
| ^ access to union field
6+
|
7+
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
8+
9+
error[E0133]: access to union field is unsafe and requires unsafe function or block
10+
--> $DIR/union-pat-in-param.rs:14:24
11+
|
12+
LL | let closure = |U { a }| {
13+
| ^ access to union field
14+
|
15+
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
16+
17+
error: aborting due to 2 previous errors
18+
19+
For more information about this error, try `rustc --explain E0133`.

0 commit comments

Comments
 (0)