From 255586d6598c0033b50cb0165bf11e10ef125878 Mon Sep 17 00:00:00 2001 From: Vincenzo Palazzo Date: Thu, 29 Aug 2024 18:52:44 +0000 Subject: [PATCH 1/5] test: cross-edition metavar fragment specifiers There's a subtle interaction between macros with metavar expressions and the edition-dependent fragment matching behavior. This test illustrates the current behavior when using macro-generating-macros across crate boundaries with different editions. Co-Authored-By: Vincenzo Palazzo Co-Authored-By: Eric Holk --- tests/ui/macros/auxiliary/metavar_2021.rs | 12 ++++++++ .../ui/macros/expr_2021_with_metavar_expr.rs | 28 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 tests/ui/macros/auxiliary/metavar_2021.rs create mode 100644 tests/ui/macros/expr_2021_with_metavar_expr.rs diff --git a/tests/ui/macros/auxiliary/metavar_2021.rs b/tests/ui/macros/auxiliary/metavar_2021.rs new file mode 100644 index 0000000000000..de5350c616413 --- /dev/null +++ b/tests/ui/macros/auxiliary/metavar_2021.rs @@ -0,0 +1,12 @@ +//@ edition: 2021 +#[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 }; + } + }; +} +make_matcher!(is_expr_from_2021, expr, $); diff --git a/tests/ui/macros/expr_2021_with_metavar_expr.rs b/tests/ui/macros/expr_2021_with_metavar_expr.rs new file mode 100644 index 0000000000000..a3da68cc8dbd7 --- /dev/null +++ b/tests/ui/macros/expr_2021_with_metavar_expr.rs @@ -0,0 +1,28 @@ +//@ compile-flags: --edition=2024 -Z unstable-options +//@ aux-build: metavar_2021.rs +//@ 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_2021; + +use metavar_2021::{is_expr_from_2021, make_matcher}; + +make_matcher!(is_expr_from_2024, expr, $); + +fn main() { + let from_2021 = is_expr_from_2021!(const { 0 }); + dbg!(from_2021); + let from_2024 = is_expr_from_2024!(const { 0 }); + dbg!(from_2024); + + // These capture the current, empirically determined behavior. + // It's not clear whether this is the desired behavior. + assert!(!from_2021); + assert!(!from_2024); +} From 7653811ac502094e6f50589bf0b7b9f80d465de7 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Tue, 17 Sep 2024 10:49:31 -0700 Subject: [PATCH 2/5] Add coverage for pat too In 2021 pat was changed to recognize `|` at the top level, with pat_param added to retain the old behavior. This means pat is subject to the same cross-edition behavior as expr will be in 2024. Co-authored-by: Vincenzo Palazzo --- .../{metavar_2021.rs => metavar_2018.rs} | 6 ++- .../ui/macros/expr_2021_with_metavar_expr.rs | 28 ------------- .../metavar_cross_edition_recursive_macros.rs | 41 +++++++++++++++++++ 3 files changed, 45 insertions(+), 30 deletions(-) rename tests/ui/macros/auxiliary/{metavar_2021.rs => metavar_2018.rs} (65%) delete mode 100644 tests/ui/macros/expr_2021_with_metavar_expr.rs create mode 100644 tests/ui/macros/metavar_cross_edition_recursive_macros.rs diff --git a/tests/ui/macros/auxiliary/metavar_2021.rs b/tests/ui/macros/auxiliary/metavar_2018.rs similarity index 65% rename from tests/ui/macros/auxiliary/metavar_2021.rs rename to tests/ui/macros/auxiliary/metavar_2018.rs index de5350c616413..7e8523a9edf1b 100644 --- a/tests/ui/macros/auxiliary/metavar_2021.rs +++ b/tests/ui/macros/auxiliary/metavar_2018.rs @@ -1,4 +1,4 @@ -//@ edition: 2021 +//@ edition: 2018 #[macro_export] macro_rules! make_matcher { ($name:ident, $fragment_type:ident, $d:tt) => { @@ -6,7 +6,9 @@ macro_rules! make_matcher { macro_rules! $name { ($d _:$fragment_type) => { true }; (const { 0 }) => { false }; + (A | B) => { false }; } }; } -make_matcher!(is_expr_from_2021, expr, $); +make_matcher!(is_expr_from_2018, expr, $); +make_matcher!(is_pat_from_2018, pat, $); diff --git a/tests/ui/macros/expr_2021_with_metavar_expr.rs b/tests/ui/macros/expr_2021_with_metavar_expr.rs deleted file mode 100644 index a3da68cc8dbd7..0000000000000 --- a/tests/ui/macros/expr_2021_with_metavar_expr.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ compile-flags: --edition=2024 -Z unstable-options -//@ aux-build: metavar_2021.rs -//@ 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_2021; - -use metavar_2021::{is_expr_from_2021, make_matcher}; - -make_matcher!(is_expr_from_2024, expr, $); - -fn main() { - let from_2021 = is_expr_from_2021!(const { 0 }); - dbg!(from_2021); - let from_2024 = is_expr_from_2024!(const { 0 }); - dbg!(from_2024); - - // These capture the current, empirically determined behavior. - // It's not clear whether this is the desired behavior. - assert!(!from_2021); - assert!(!from_2024); -} 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..4c4d3cda45e0a --- /dev/null +++ b/tests/ui/macros/metavar_cross_edition_recursive_macros.rs @@ -0,0 +1,41 @@ +//@ compile-flags: --edition=2024 -Z unstable-options +//@ aux-build: metavar_2018.rs +//@ 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); + + // These capture the current, empirically determined behavior. + // It's not clear whether this is the desired behavior. + assert!(!from_2018); + assert!(!from_2024); + + // 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); + + // These capture the current, empirically determined behavior. + // It's not clear whether this is the desired behavior. + assert!(!from_2018); + assert!(!from_2024); +} From 12f2bcde63285bf2b2f9f9ac615d4edf139a3f0e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 18 Sep 2024 16:45:27 -0400 Subject: [PATCH 3/5] Check params for unsafety in THIR --- .../rustc_mir_build/src/check_unsafety.rs | 14 ++++++++++++++ tests/ui/unsafe/union-pat-in-param.rs | 19 +++++++++++++++++++ tests/ui/unsafe/union-pat-in-param.stderr | 19 +++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 tests/ui/unsafe/union-pat-in-param.rs create mode 100644 tests/ui/unsafe/union-pat-in-param.stderr 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/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`. From fb475e47594d089f1b670009ffcd38cea1544fb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Bj=C3=B8rnager=20Jensen?= Date: Tue, 17 Sep 2024 18:20:42 +0200 Subject: [PATCH 4/5] Mark and implement 'char::encode_utf8' as const. --- library/core/src/char/methods.rs | 32 ++++++++++++++------------------ library/core/src/lib.rs | 1 + 2 files changed, 15 insertions(+), 18 deletions(-) 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 058dcf3453279..f25f6922bca20 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)] From dd6460ba9f6c325211c6b2d819fe0653dc94a1ba Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 18 Sep 2024 15:13:07 -0700 Subject: [PATCH 5/5] Add known-bug and update comments to describe correct behavior in light of bug --- .../ui/macros/metavar_cross_edition_recursive_macros.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tests/ui/macros/metavar_cross_edition_recursive_macros.rs b/tests/ui/macros/metavar_cross_edition_recursive_macros.rs index 4c4d3cda45e0a..3eec1208b89ae 100644 --- a/tests/ui/macros/metavar_cross_edition_recursive_macros.rs +++ b/tests/ui/macros/metavar_cross_edition_recursive_macros.rs @@ -1,5 +1,6 @@ //@ 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 @@ -23,10 +24,8 @@ fn main() { let from_2024 = is_expr_from_2024!(const { 0 }); dbg!(from_2024); - // These capture the current, empirically determined behavior. - // It's not clear whether this is the desired behavior. assert!(!from_2018); - assert!(!from_2024); + assert!(!from_2024); // from_2024 will be true once #130484 is fixed // Check pat let from_2018 = is_pat_from_2018!(A | B); @@ -34,8 +33,6 @@ fn main() { let from_2024 = is_pat_from_2024!(A | B); dbg!(from_2024); - // These capture the current, empirically determined behavior. - // It's not clear whether this is the desired behavior. assert!(!from_2018); - assert!(!from_2024); + assert!(!from_2024); // from_2024 will be true once #130484 is fixed }