From 413ca98d9110404d745471e54af10fc950292417 Mon Sep 17 00:00:00 2001 From: Eugene Talagrand Date: Sat, 16 Oct 2021 18:23:42 -1000 Subject: [PATCH 1/6] Update std::env::temp_dir to use GetTempPath2 on Windows when available. As a security measure, Windows 11 introduces a new temporary directory API, GetTempPath2. When the calling process is running as SYSTEM, a separate temporary directory will be returned inaccessible to non-SYSTEM processes. For non-SYSTEM processes the behavior will be the same as before. --- library/std/src/env.rs | 21 +++++++++------------ library/std/src/sys/windows/c.rs | 6 ++++++ library/std/src/sys/windows/os.rs | 2 +- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 40b46878cd8ba..6b5801850933e 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -578,28 +578,25 @@ pub fn home_dir() -> Option { /// may result in "insecure temporary file" security vulnerabilities. Consider /// using a crate that securely creates temporary files or directories. /// -/// # Unix +/// # Platform-specific behavior /// -/// Returns the value of the `TMPDIR` environment variable if it is +/// On Unix, returns the value of the `TMPDIR` environment variable if it is /// set, otherwise for non-Android it returns `/tmp`. If Android, since there /// is no global temporary folder (it is usually allocated per-app), it returns /// `/data/local/tmp`. +/// On Windows, the behavior is equivalent to that of [`GetTempPath2`][GetTempPath2] / +/// [`GetTempPath`][GetTempPath], which this function uses internally. +/// Note that, this [may change in the future][changes]. /// -/// # Windows -/// -/// Returns the value of, in order, the `TMP`, `TEMP`, -/// `USERPROFILE` environment variable if any are set and not the empty -/// string. Otherwise, `temp_dir` returns the path of the Windows directory. -/// This behavior is identical to that of [`GetTempPath`][msdn], which this -/// function uses internally. -/// -/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha +/// [changes]: io#platform-specific-behavior +/// [GetTempPath2]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppath2a +/// [GetTempPath]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha /// /// ```no_run /// use std::env; /// /// fn main() { -/// let mut dir = env::temp_dir(); +/// let dir = env::temp_dir(); /// println!("Temporary directory: {}", dir.display()); /// } /// ``` diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index e5c550802a7ab..87add8b08749b 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -1102,6 +1102,12 @@ compat_fn! { -> () { GetSystemTimeAsFileTime(lpSystemTimeAsFileTime) } + + // >= Win11 + // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppath2a + pub fn GetTempPath2W(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD { + GetTempPathW(nBufferLength, lpBuffer) + } } compat_fn! { diff --git a/library/std/src/sys/windows/os.rs b/library/std/src/sys/windows/os.rs index 883690c483167..0c26321c47d08 100644 --- a/library/std/src/sys/windows/os.rs +++ b/library/std/src/sys/windows/os.rs @@ -275,7 +275,7 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> { } pub fn temp_dir() -> PathBuf { - super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPathW(sz, buf) }, super::os2path).unwrap() + super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPath2W(sz, buf) }, super::os2path).unwrap() } #[cfg(not(target_vendor = "uwp"))] From 1d26e413de7a026ae2e99dad82edd2b8affcf5f3 Mon Sep 17 00:00:00 2001 From: Eugene Talagrand Date: Tue, 26 Oct 2021 17:49:55 -0700 Subject: [PATCH 2/6] Clarify platform availability of GetTempPath2 Windows Server 2022 is a different version from Win11, breaking precent --- library/std/src/sys/windows/c.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index 87add8b08749b..b9f49fed76957 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -1103,7 +1103,7 @@ compat_fn! { GetSystemTimeAsFileTime(lpSystemTimeAsFileTime) } - // >= Win11 + // >= Win11 / Server 2022 // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppath2a pub fn GetTempPath2W(nBufferLength: DWORD, lpBuffer: LPCWSTR) -> DWORD { GetTempPathW(nBufferLength, lpBuffer) From eb56693a370df5bb60f58f73586cded6a641b0cc Mon Sep 17 00:00:00 2001 From: Smitty Date: Thu, 29 Jul 2021 13:00:55 -0400 Subject: [PATCH 3/6] Implement concat_bytes! The tracking issue for this is #87555. --- .../rustc_builtin_macros/src/concat_bytes.rs | 167 ++++++++++++++++++ compiler/rustc_builtin_macros/src/lib.rs | 2 + compiler/rustc_span/src/symbol.rs | 1 + library/core/src/macros/mod.rs | 28 +++ library/core/src/prelude/v1.rs | 9 + library/std/src/lib.rs | 9 + library/std/src/prelude/v1.rs | 9 + .../feature-gate-concat_bytes.rs | 4 + .../feature-gate-concat_bytes.stderr | 12 ++ src/test/ui/macros/concat-bytes-error.rs | 42 +++++ src/test/ui/macros/concat-bytes-error.stderr | 131 ++++++++++++++ src/test/ui/macros/concat-bytes.rs | 7 + 12 files changed, 421 insertions(+) create mode 100644 compiler/rustc_builtin_macros/src/concat_bytes.rs create mode 100644 src/test/ui/feature-gates/feature-gate-concat_bytes.rs create mode 100644 src/test/ui/feature-gates/feature-gate-concat_bytes.stderr create mode 100644 src/test/ui/macros/concat-bytes-error.rs create mode 100644 src/test/ui/macros/concat-bytes-error.stderr create mode 100644 src/test/ui/macros/concat-bytes.rs diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs new file mode 100644 index 0000000000000..a107f5993b546 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -0,0 +1,167 @@ +use rustc_ast as ast; +use rustc_ast::{ptr::P, tokenstream::TokenStream}; +use rustc_data_structures::sync::Lrc; +use rustc_errors::Applicability; +use rustc_expand::base::{self, DummyResult}; + +/// Emits errors for literal expressions that are invalid inside and outside of an array. +fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P, is_nested: bool) { + let lit = if let ast::ExprKind::Lit(lit) = &expr.kind { + lit + } else { + unreachable!(); + }; + match lit.kind { + ast::LitKind::Char(_) => { + let mut err = cx.struct_span_err(expr.span, "cannot concatenate character literals"); + if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) { + err.span_suggestion( + expr.span, + "try using a byte character", + format!("b{}", snippet), + Applicability::MachineApplicable, + ) + .emit(); + } + } + ast::LitKind::Str(_, _) => { + let mut err = cx.struct_span_err(expr.span, "cannot concatenate string literals"); + // suggestion would be invalid if we are nested + if !is_nested { + if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) { + err.span_suggestion( + expr.span, + "try using a byte string", + format!("b{}", snippet), + Applicability::MachineApplicable, + ); + } + } + err.emit(); + } + ast::LitKind::Float(_, _) => { + cx.span_err(expr.span, "cannot concatenate float literals"); + } + ast::LitKind::Bool(_) => { + cx.span_err(expr.span, "cannot concatenate boolean literals"); + } + ast::LitKind::Err(_) => {} + ast::LitKind::Int(_, _) if !is_nested => { + let mut err = cx.struct_span_err(expr.span, "cannot concatenate numeric literals"); + if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) { + err.span_suggestion( + expr.span, + "try wrapping the number in an array", + format!("[{}]", snippet), + Applicability::MachineApplicable, + ); + } + err.emit(); + } + ast::LitKind::Int( + val, + ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), + ) => { + assert!(val > u8::MAX.into()); // must be an error + cx.span_err(expr.span, "numeric literal is out of bounds"); + } + ast::LitKind::Int(_, _) => { + cx.span_err(expr.span, "numeric literal is not a `u8`"); + } + _ => unreachable!(), + } +} + +pub fn expand_concat_bytes( + cx: &mut base::ExtCtxt<'_>, + sp: rustc_span::Span, + tts: TokenStream, +) -> Box { + let es = match base::get_exprs_from_tts(cx, sp, tts) { + Some(e) => e, + None => return DummyResult::any(sp), + }; + let mut accumulator = Vec::new(); + let mut missing_literals = vec![]; + let mut has_errors = false; + for e in es { + match e.kind { + ast::ExprKind::Array(ref exprs) => { + for expr in exprs { + match expr.kind { + ast::ExprKind::Array(_) => { + if !has_errors { + cx.span_err(expr.span, "cannot concatenate doubly nested array"); + } + has_errors = true; + } + ast::ExprKind::Lit(ref lit) => match lit.kind { + ast::LitKind::Int( + val, + ast::LitIntType::Unsuffixed + | ast::LitIntType::Unsigned(ast::UintTy::U8), + ) if val <= u8::MAX.into() => { + accumulator.push(val as u8); + } + + ast::LitKind::Byte(val) => { + accumulator.push(val); + } + ast::LitKind::ByteStr(_) => { + if !has_errors { + cx.struct_span_err( + expr.span, + "cannot concatenate doubly nested array", + ) + .note("byte strings are treated as arrays of bytes") + .help("try flattening the array") + .emit(); + } + has_errors = true; + } + _ => { + if !has_errors { + invalid_type_err(cx, expr, true); + } + has_errors = true; + } + }, + _ => { + missing_literals.push(expr.span); + } + } + } + } + ast::ExprKind::Lit(ref lit) => match lit.kind { + ast::LitKind::Byte(val) => { + accumulator.push(val); + } + ast::LitKind::ByteStr(ref bytes) => { + accumulator.extend_from_slice(&bytes); + } + _ => { + if !has_errors { + invalid_type_err(cx, &e, false); + } + has_errors = true; + } + }, + ast::ExprKind::Err => { + has_errors = true; + } + _ => { + missing_literals.push(e.span); + } + } + } + if !missing_literals.is_empty() { + let mut err = cx.struct_span_err(missing_literals.clone(), "expected a byte literal"); + err.note("only byte literals (like `b\"foo\"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`"); + err.emit(); + return base::MacEager::expr(DummyResult::raw_expr(sp, true)); + } else if has_errors { + return base::MacEager::expr(DummyResult::raw_expr(sp, true)); + } + let sp = cx.with_def_site_ctxt(sp); + base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(Lrc::from(accumulator)))) +} diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index d1d276930b90a..f5acf9db08517 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -27,6 +27,7 @@ mod cfg_accessible; mod cfg_eval; mod compile_error; mod concat; +mod concat_bytes; mod concat_idents; mod derive; mod deriving; @@ -65,6 +66,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { cfg: cfg::expand_cfg, column: source_util::expand_column, compile_error: compile_error::expand_compile_error, + concat_bytes: concat_bytes::expand_concat_bytes, concat_idents: concat_idents::expand_concat_idents, concat: concat::expand_concat, env: env::expand_env, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 309c305293fd6..6d300bac41093 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -439,6 +439,7 @@ symbols! { compiler_builtins, compiler_fence, concat, + concat_bytes, concat_idents, conservative_impl_trait, console, diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 993ae72322966..b18508186a618 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -967,6 +967,34 @@ pub(crate) mod builtin { ($($e:ident),+ $(,)?) => {{ /* compiler built-in */ }}; } + /// Concatenates literals into a byte slice. + /// + /// This macro takes any number of comma-separated literals, and concatenates them all into + /// one, yielding an expression of type `&[u8, _]`, which represents all of the literals + /// concatenated left-to-right. The literals passed can be any combination of: + /// + /// - byte literals (`b'r'`) + /// - byte strings (`b"Rust"`) + /// - arrays of bytes/numbers (`[b'A', 66, b'C']`) + /// + /// # Examples + /// + /// ``` + /// #![feature(concat_bytes)] + /// + /// # fn main() { + /// let s: &[u8; 6] = concat_bytes!(b'A', b"BC", [68, b'E', 70]); + /// assert_eq!(s, b"ABCDEF"); + /// # } + /// ``` + #[cfg(not(bootstrap))] + #[unstable(feature = "concat_bytes", issue = "87555")] + #[rustc_builtin_macro] + #[macro_export] + macro_rules! concat_bytes { + ($($e:literal),+ $(,)?) => {{ /* compiler built-in */ }}; + } + /// Concatenates literals into a static string slice. /// /// This macro takes any number of comma-separated literals, yielding an diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 6b51ef5b0122d..8705eb394688a 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -60,6 +60,15 @@ pub use crate::{ option_env, stringify, trace_macros, }; +#[unstable( + feature = "concat_bytes", + issue = "87555", + reason = "`concat_bytes` is not stable enough for use and is subject to change" +)] +#[cfg(not(bootstrap))] +#[doc(no_inline)] +pub use crate::concat_bytes; + #[unstable( feature = "asm", issue = "72016", diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 67846e7883570..367f072ffc7f8 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -250,6 +250,7 @@ #![feature(cfg_target_thread_local)] #![feature(char_error_internals)] #![feature(char_internals)] +#![cfg_attr(not(bootstrap), feature(concat_bytes))] #![feature(concat_idents)] #![feature(const_cstr_unchecked)] #![feature(const_fn_floating_point_arithmetic)] @@ -576,6 +577,14 @@ pub use core::{ log_syntax, module_path, option_env, stringify, trace_macros, }; +#[unstable( + feature = "concat_bytes", + issue = "87555", + reason = "`concat_bytes` is not stable enough for use and is subject to change" +)] +#[cfg(not(bootstrap))] +pub use core::concat_bytes; + #[stable(feature = "core_primitive", since = "1.43.0")] pub use core::primitive; diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 772044f014920..9b23aa37e3195 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -45,6 +45,15 @@ pub use core::prelude::v1::{ PartialOrd, }; +#[unstable( + feature = "concat_bytes", + issue = "87555", + reason = "`concat_bytes` is not stable enough for use and is subject to change" +)] +#[cfg(not(bootstrap))] +#[doc(no_inline)] +pub use core::prelude::v1::concat_bytes; + #[unstable( feature = "asm", issue = "72016", diff --git a/src/test/ui/feature-gates/feature-gate-concat_bytes.rs b/src/test/ui/feature-gates/feature-gate-concat_bytes.rs new file mode 100644 index 0000000000000..07d63cb11e085 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-concat_bytes.rs @@ -0,0 +1,4 @@ +fn main() { + let a = concat_bytes!(b'A', b"BC"); //~ ERROR use of unstable library feature 'concat_bytes' + assert_eq!(a, &[65, 66, 67]); +} diff --git a/src/test/ui/feature-gates/feature-gate-concat_bytes.stderr b/src/test/ui/feature-gates/feature-gate-concat_bytes.stderr new file mode 100644 index 0000000000000..4b3ee4c19cecd --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-concat_bytes.stderr @@ -0,0 +1,12 @@ +error[E0658]: use of unstable library feature 'concat_bytes' + --> $DIR/feature-gate-concat_bytes.rs:2:13 + | +LL | let a = concat_bytes!(b'A', b"BC"); + | ^^^^^^^^^^^^ + | + = note: see issue #87555 for more information + = help: add `#![feature(concat_bytes)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/macros/concat-bytes-error.rs b/src/test/ui/macros/concat-bytes-error.rs new file mode 100644 index 0000000000000..9b4a9c2cf811d --- /dev/null +++ b/src/test/ui/macros/concat-bytes-error.rs @@ -0,0 +1,42 @@ +#![feature(concat_bytes)] + +fn main() { + concat_bytes!(pie); //~ ERROR expected a byte literal + concat_bytes!(pie, pie); //~ ERROR expected a byte literal + concat_bytes!("tnrsi", "tnri"); //~ ERROR cannot concatenate string literals + concat_bytes!(2.8); //~ ERROR cannot concatenate float literals + concat_bytes!(300); //~ ERROR cannot concatenate numeric literals + concat_bytes!('a'); //~ ERROR cannot concatenate character literals + concat_bytes!(true, false); //~ ERROR cannot concatenate boolean literals + concat_bytes!(42, b"va", b'l'); //~ ERROR cannot concatenate numeric literals + concat_bytes!(42, b"va", b'l', [1, 2]); //~ ERROR cannot concatenate numeric literals + concat_bytes!([ + "hi", //~ ERROR cannot concatenate string literals + ]); + concat_bytes!([ + 'a', //~ ERROR cannot concatenate character literals + ]); + concat_bytes!([ + true, //~ ERROR cannot concatenate boolean literals + ]); + concat_bytes!([ + false, //~ ERROR cannot concatenate boolean literals + ]); + concat_bytes!([ + 2.6, //~ ERROR cannot concatenate float literals + ]); + concat_bytes!([ + 265, //~ ERROR numeric literal is out of bounds + ]); + concat_bytes!([ + -33, //~ ERROR expected a byte literal + ]); + concat_bytes!([ + b"hi!", //~ ERROR cannot concatenate doubly nested array + ]); + concat_bytes!([ + [5, 6, 7], //~ ERROR cannot concatenate doubly nested array + ]); + concat_bytes!(5u16); //~ ERROR cannot concatenate numeric literals + concat_bytes!([5u16]); //~ ERROR numeric literal is not a `u8` +} diff --git a/src/test/ui/macros/concat-bytes-error.stderr b/src/test/ui/macros/concat-bytes-error.stderr new file mode 100644 index 0000000000000..1fc2d5c4843a0 --- /dev/null +++ b/src/test/ui/macros/concat-bytes-error.stderr @@ -0,0 +1,131 @@ +error: expected a byte literal + --> $DIR/concat-bytes-error.rs:4:19 + | +LL | concat_bytes!(pie); + | ^^^ + | + = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()` + +error: expected a byte literal + --> $DIR/concat-bytes-error.rs:5:19 + | +LL | concat_bytes!(pie, pie); + | ^^^ ^^^ + | + = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()` + +error: cannot concatenate string literals + --> $DIR/concat-bytes-error.rs:6:19 + | +LL | concat_bytes!("tnrsi", "tnri"); + | ^^^^^^^ help: try using a byte string: `b"tnrsi"` + +error: cannot concatenate float literals + --> $DIR/concat-bytes-error.rs:7:19 + | +LL | concat_bytes!(2.8); + | ^^^ + +error: cannot concatenate numeric literals + --> $DIR/concat-bytes-error.rs:8:19 + | +LL | concat_bytes!(300); + | ^^^ help: try wrapping the number in an array: `[300]` + +error: cannot concatenate character literals + --> $DIR/concat-bytes-error.rs:9:19 + | +LL | concat_bytes!('a'); + | ^^^ help: try using a byte character: `b'a'` + +error: cannot concatenate boolean literals + --> $DIR/concat-bytes-error.rs:10:19 + | +LL | concat_bytes!(true, false); + | ^^^^ + +error: cannot concatenate numeric literals + --> $DIR/concat-bytes-error.rs:11:19 + | +LL | concat_bytes!(42, b"va", b'l'); + | ^^ help: try wrapping the number in an array: `[42]` + +error: cannot concatenate numeric literals + --> $DIR/concat-bytes-error.rs:12:19 + | +LL | concat_bytes!(42, b"va", b'l', [1, 2]); + | ^^ help: try wrapping the number in an array: `[42]` + +error: cannot concatenate string literals + --> $DIR/concat-bytes-error.rs:14:9 + | +LL | "hi", + | ^^^^ + +error: cannot concatenate character literals + --> $DIR/concat-bytes-error.rs:17:9 + | +LL | 'a', + | ^^^ help: try using a byte character: `b'a'` + +error: cannot concatenate boolean literals + --> $DIR/concat-bytes-error.rs:20:9 + | +LL | true, + | ^^^^ + +error: cannot concatenate boolean literals + --> $DIR/concat-bytes-error.rs:23:9 + | +LL | false, + | ^^^^^ + +error: cannot concatenate float literals + --> $DIR/concat-bytes-error.rs:26:9 + | +LL | 2.6, + | ^^^ + +error: numeric literal is out of bounds + --> $DIR/concat-bytes-error.rs:29:9 + | +LL | 265, + | ^^^ + +error: expected a byte literal + --> $DIR/concat-bytes-error.rs:32:9 + | +LL | -33, + | ^^^ + | + = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()` + +error: cannot concatenate doubly nested array + --> $DIR/concat-bytes-error.rs:35:9 + | +LL | b"hi!", + | ^^^^^^ + | + = note: byte strings are treated as arrays of bytes + = help: try flattening the array + +error: cannot concatenate doubly nested array + --> $DIR/concat-bytes-error.rs:38:9 + | +LL | [5, 6, 7], + | ^^^^^^^^^ + +error: cannot concatenate numeric literals + --> $DIR/concat-bytes-error.rs:40:19 + | +LL | concat_bytes!(5u16); + | ^^^^ help: try wrapping the number in an array: `[5u16]` + +error: numeric literal is not a `u8` + --> $DIR/concat-bytes-error.rs:41:20 + | +LL | concat_bytes!([5u16]); + | ^^^^ + +error: aborting due to 20 previous errors + diff --git a/src/test/ui/macros/concat-bytes.rs b/src/test/ui/macros/concat-bytes.rs new file mode 100644 index 0000000000000..5415cf3fe2235 --- /dev/null +++ b/src/test/ui/macros/concat-bytes.rs @@ -0,0 +1,7 @@ +// run-pass +#![feature(concat_bytes)] + +fn main() { + assert_eq!(concat_bytes!(), &[]); + assert_eq!(concat_bytes!(b'A', b"BC", [68, b'E', 70]), b"ABCDEF"); +} From 908f300dd7878f6bcd0f5479c2db680067aec3d8 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 11 Nov 2021 12:42:38 +0000 Subject: [PATCH 4/6] Remove the reg_thumb register class for asm! on ARM Also restricts r8-r14 from being used on Thumb1 targets as per #90736. --- compiler/rustc_codegen_gcc/src/asm.rs | 7 +--- compiler/rustc_codegen_llvm/src/asm.rs | 7 +--- .../rustc_codegen_ssa/src/target_features.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 - compiler/rustc_target/src/asm/arm.rs | 37 ++++++++++++------- .../unstable-book/src/library-features/asm.md | 6 +-- src/test/assembly/asm/arm-modifiers.rs | 6 --- src/test/assembly/asm/arm-types.rs | 30 --------------- 8 files changed, 30 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 7481b5db755e7..10edcf36955da 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -568,7 +568,6 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => unimplemented!(), InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => unimplemented!(), InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => unimplemented!(), - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => unimplemented!(), InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) => unimplemented!(), @@ -628,8 +627,7 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { unimplemented!() } - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => cx.type_i32(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)=> cx.type_i32(), InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => cx.type_f32(), InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) @@ -737,8 +735,7 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => { unimplemented!() } - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => unimplemented!(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => unimplemented!(), InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => unimplemented!(), InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 90d3c0fb2f173..f3c3a17490811 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -632,7 +632,6 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>) unreachable!("clobber-only") } InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => "r", - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => "l", InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) => "t", @@ -703,8 +702,7 @@ fn modifier_to_llvm( InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { unreachable!("clobber-only") } - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => None, + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => None, InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => None, InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) @@ -785,8 +783,7 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => { unreachable!("clobber-only") } - InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) - | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => cx.type_i32(), + InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => cx.type_f32(), InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index b4420df5df417..ba72e3cfafce2 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -35,6 +35,7 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option)] = &[ // since it should be enabled per-function using #[instruction_set], not // #[target_feature]. ("thumb-mode", Some(sym::arm_target_feature)), + ("thumb2", Some(sym::arm_target_feature)), ]; const AARCH64_ALLOWED_FEATURES: &[(&str, Option)] = &[ diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a4280047c7068..2a7af9cf67ae3 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1057,7 +1057,6 @@ symbols! { reg_nonzero, reg_pair, reg_ptr, - reg_thumb, reg_upper, register_attr, register_tool, diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs index 4c323fc35d643..4eeb7fcc71bce 100644 --- a/compiler/rustc_target/src/asm/arm.rs +++ b/compiler/rustc_target/src/asm/arm.rs @@ -6,7 +6,6 @@ use std::fmt; def_reg_class! { Arm ArmInlineAsmRegClass { reg, - reg_thumb, sreg, sreg_low16, dreg, @@ -47,7 +46,7 @@ impl ArmInlineAsmRegClass { _arch: InlineAsmArch, ) -> &'static [(InlineAsmType, Option<&'static str>)] { match self { - Self::reg | Self::reg_thumb => types! { _: I8, I16, I32, F32; }, + Self::reg => types! { _: I8, I16, I32, F32; }, Self::sreg | Self::sreg_low16 => types! { "vfp2": I32, F32; }, Self::dreg | Self::dreg_low16 | Self::dreg_low8 => types! { "vfp2": I64, F64, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2); @@ -88,20 +87,32 @@ fn frame_pointer_r7( } } +fn not_thumb1( + _arch: InlineAsmArch, + mut has_feature: impl FnMut(&str) -> bool, + _target: &Target, +) -> Result<(), &'static str> { + if has_feature("thumb-mode") && !has_feature("thumb2") { + Err("high registers (r8+) cannot be used in Thumb-1 code") + } else { + Ok(()) + } +} + def_regs! { Arm ArmInlineAsmReg ArmInlineAsmRegClass { - r0: reg, reg_thumb = ["r0", "a1"], - r1: reg, reg_thumb = ["r1", "a2"], - r2: reg, reg_thumb = ["r2", "a3"], - r3: reg, reg_thumb = ["r3", "a4"], - r4: reg, reg_thumb = ["r4", "v1"], - r5: reg, reg_thumb = ["r5", "v2"], - r7: reg, reg_thumb = ["r7", "v4"] % frame_pointer_r7, - r8: reg = ["r8", "v5"], - r10: reg = ["r10", "sl"], + r0: reg = ["r0", "a1"], + r1: reg = ["r1", "a2"], + r2: reg = ["r2", "a3"], + r3: reg = ["r3", "a4"], + r4: reg = ["r4", "v1"], + r5: reg = ["r5", "v2"], + r7: reg = ["r7", "v4"] % frame_pointer_r7, + r8: reg = ["r8", "v5"] % not_thumb1, + r10: reg = ["r10", "sl"] % not_thumb1, r11: reg = ["r11", "fp"] % frame_pointer_r11, - r12: reg = ["r12", "ip"], - r14: reg = ["r14", "lr"], + r12: reg = ["r12", "ip"] % not_thumb1, + r14: reg = ["r14", "lr"] % not_thumb1, s0: sreg, sreg_low16 = ["s0"], s1: sreg, sreg_low16 = ["s1"], s2: sreg, sreg_low16 = ["s2"], diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index dffa3a8b80f0f..59987cccde673 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -564,12 +564,8 @@ Here is the list of currently supported register classes: | AArch64 | `vreg` | `v[0-31]` | `w` | | AArch64 | `vreg_low16` | `v[0-15]` | `x` | | AArch64 | `preg` | `p[0-15]`, `ffr` | Only clobbers | -| ARM (ARM) | `reg` | `r[0-12]`, `r14` | `r` | -| ARM (Thumb2) | `reg` | `r[0-12]`, `r14` | `r` | +| ARM (ARM/Thumb2) | `reg` | `r[0-12]`, `r14` | `r` | | ARM (Thumb1) | `reg` | `r[0-7]` | `r` | -| ARM (ARM) | `reg_thumb` | `r[0-r12]`, `r14` | `l` | -| ARM (Thumb2) | `reg_thumb` | `r[0-7]` | `l` | -| ARM (Thumb1) | `reg_thumb` | `r[0-7]` | `l` | | ARM | `sreg` | `s[0-31]` | `t` | | ARM | `sreg_low16` | `s[0-15]` | `x` | | ARM | `dreg` | `d[0-31]` | `w` | diff --git a/src/test/assembly/asm/arm-modifiers.rs b/src/test/assembly/asm/arm-modifiers.rs index a6985a3bf5c6b..88ffeaecfecb6 100644 --- a/src/test/assembly/asm/arm-modifiers.rs +++ b/src/test/assembly/asm/arm-modifiers.rs @@ -59,12 +59,6 @@ macro_rules! check { // CHECK: @NO_APP check!(reg "" reg i32 "mov"); -// CHECK-LABEL: reg_thumb: -// CHECK: @APP -// CHECK: mov r0, r0 -// CHECK: @NO_APP -check!(reg_thumb "" reg_thumb i32 "mov"); - // CHECK-LABEL: sreg: // CHECK: @APP // CHECK: vmov.f32 s0, s0 diff --git a/src/test/assembly/asm/arm-types.rs b/src/test/assembly/asm/arm-types.rs index 0c57b1fc4782d..5ac1af6afd67d 100644 --- a/src/test/assembly/asm/arm-types.rs +++ b/src/test/assembly/asm/arm-types.rs @@ -163,36 +163,6 @@ check!(reg_f32 f32 reg "mov"); // CHECK: @NO_APP check!(reg_ptr ptr reg "mov"); -// CHECK-LABEL: reg_thumb_i8: -// CHECK: @APP -// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} -// CHECK: @NO_APP -check!(reg_thumb_i8 i8 reg_thumb "mov"); - -// CHECK-LABEL: reg_thumb_i16: -// CHECK: @APP -// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} -// CHECK: @NO_APP -check!(reg_thumb_i16 i16 reg_thumb "mov"); - -// CHECK-LABEL: reg_thumb_i32: -// CHECK: @APP -// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} -// CHECK: @NO_APP -check!(reg_thumb_i32 i32 reg_thumb "mov"); - -// CHECK-LABEL: reg_thumb_f32: -// CHECK: @APP -// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} -// CHECK: @NO_APP -check!(reg_thumb_f32 f32 reg_thumb "mov"); - -// CHECK-LABEL: reg_thumb_ptr: -// CHECK: @APP -// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} -// CHECK: @NO_APP -check!(reg_thumb_ptr ptr reg_thumb "mov"); - // CHECK-LABEL: sreg_i32: // CHECK: @APP // CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} From b4c4bc09dde2a6f6ce2978e00fb57b083ea4accc Mon Sep 17 00:00:00 2001 From: threadexception Date: Tue, 7 Dec 2021 16:44:51 +0100 Subject: [PATCH 5/6] Do not attempt to suggest help for overly malformed struct/function call --- compiler/rustc_parse/src/parser/expr.rs | 47 +++++++++++--------- src/test/ui/parser/issues/issue-91461.rs | 6 +++ src/test/ui/parser/issues/issue-91461.stderr | 31 +++++++++++++ 3 files changed, 64 insertions(+), 20 deletions(-) create mode 100644 src/test/ui/parser/issues/issue-91461.rs create mode 100644 src/test/ui/parser/issues/issue-91461.stderr diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 1dbd7bad0f023..0f8c0e1b8cff8 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1100,30 +1100,37 @@ impl<'a> Parser<'a> { snapshot.bump(); // `(` match snapshot.parse_struct_fields(path, false, token::Paren) { Ok((fields, ..)) if snapshot.eat(&token::CloseDelim(token::Paren)) => { - // We have are certain we have `Enum::Foo(a: 3, b: 4)`, suggest + // We are certain we have `Enum::Foo(a: 3, b: 4)`, suggest // `Enum::Foo { a: 3, b: 4 }` or `Enum::Foo(3, 4)`. *self = snapshot; let close_paren = self.prev_token.span; let span = lo.to(self.prev_token.span); - err.cancel(); - self.struct_span_err( - span, - "invalid `struct` delimiters or `fn` call arguments", - ) - .multipart_suggestion( - &format!("if `{}` is a struct, use braces as delimiters", name), - vec![(open_paren, " { ".to_string()), (close_paren, " }".to_string())], - Applicability::MaybeIncorrect, - ) - .multipart_suggestion( - &format!("if `{}` is a function, use the arguments directly", name), - fields - .into_iter() - .map(|field| (field.span.until(field.expr.span), String::new())) - .collect(), - Applicability::MaybeIncorrect, - ) - .emit(); + if !fields.is_empty() { + err.cancel(); + let mut err = self.struct_span_err( + span, + "invalid `struct` delimiters or `fn` call arguments", + ); + err.multipart_suggestion( + &format!("if `{}` is a struct, use braces as delimiters", name), + vec![ + (open_paren, " { ".to_string()), + (close_paren, " }".to_string()), + ], + Applicability::MaybeIncorrect, + ); + err.multipart_suggestion( + &format!("if `{}` is a function, use the arguments directly", name), + fields + .into_iter() + .map(|field| (field.span.until(field.expr.span), String::new())) + .collect(), + Applicability::MaybeIncorrect, + ); + err.emit(); + } else { + err.emit(); + } return Some(self.mk_expr_err(span)); } Ok(_) => {} diff --git a/src/test/ui/parser/issues/issue-91461.rs b/src/test/ui/parser/issues/issue-91461.rs new file mode 100644 index 0000000000000..3e3c411c478ab --- /dev/null +++ b/src/test/ui/parser/issues/issue-91461.rs @@ -0,0 +1,6 @@ +fn main() { + a(_:b:,) + //~^ ERROR: expected identifier, found reserved identifier `_` + //~| ERROR: expected type, found `,` + //~| ERROR: expected type, found `,` +} diff --git a/src/test/ui/parser/issues/issue-91461.stderr b/src/test/ui/parser/issues/issue-91461.stderr new file mode 100644 index 0000000000000..94fcf1721d8c1 --- /dev/null +++ b/src/test/ui/parser/issues/issue-91461.stderr @@ -0,0 +1,31 @@ +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-91461.rs:2:7 + | +LL | a(_:b:,) + | ^ expected identifier, found reserved identifier + +error: expected type, found `,` + --> $DIR/issue-91461.rs:2:11 + | +LL | a(_:b:,) + | - -^ expected type + | | | + | | tried to parse a type due to this type ascription + | while parsing this struct + | + = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `: ` + = note: see issue #23416 for more information + +error: expected type, found `,` + --> $DIR/issue-91461.rs:2:11 + | +LL | a(_:b:,) + | -^ expected type + | | + | tried to parse a type due to this type ascription + | + = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `: ` + = note: see issue #23416 for more information + +error: aborting due to 3 previous errors + From 9bcbc58eba8563e6b829941d65c42a24476e7048 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 8 Dec 2021 18:35:53 -0600 Subject: [PATCH 6/6] Install llvm tools to sysroot when assembling local toolchain Some projects (e.g. the `bootimage` crate) may require the user to install the `llvm-tools-preview` rustup component. However, this cannot be easily done with a locally built toolchain. To allow a local toolchain to be used a drop-in replacement for a normal rustup toolchain in more cases, this PR copies the built LLVM tools to the sysoot. From the perspective a tool looking at the sysroot, this is equivalent to installing `llvm-tools-preview`. --- src/bootstrap/compile.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 007ca9f7f5a92..186b5e92d33e3 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -28,6 +28,7 @@ use crate::dist; use crate::native; use crate::tool::SourceType; use crate::util::{exe, is_debug_info, is_dylib, symlink_dir}; +use crate::LLVM_TOOLS; use crate::{Compiler, DependencyType, GitRepo, Mode}; #[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)] @@ -1164,6 +1165,16 @@ impl Step for Assemble { let llvm_bin_dir = output(Command::new(llvm_config_bin).arg("--bindir")); let llvm_bin_dir = Path::new(llvm_bin_dir.trim()); builder.copy(&llvm_bin_dir.join(&src_exe), &libdir_bin.join(&dst_exe)); + + // Since we've already built the LLVM tools, install them to the sysroot. + // This is the equivalent of installing the `llvm-tools-preview` component via + // rustup, and lets developers use a locally built toolchain to + // build projects that expect llvm tools to be present in the sysroot + // (e.g. the `bootimage` crate). + for tool in LLVM_TOOLS { + let tool_exe = exe(tool, target_compiler.host); + builder.copy(&llvm_bin_dir.join(&tool_exe), &libdir_bin.join(&tool_exe)); + } } }