From 1ea6cd715e01f14395ee3f7d944ecc68adf0dde4 Mon Sep 17 00:00:00 2001 From: ltdk Date: Sat, 19 Aug 2023 18:46:11 -0400 Subject: [PATCH 01/14] Add std::ffi::c_str modules --- library/alloc/src/ffi/c_str.rs | 2 ++ library/alloc/src/ffi/mod.rs | 10 +++++++--- library/core/src/ffi/c_str.rs | 17 ++++++++++++----- library/core/src/ffi/mod.rs | 14 ++++++++++++-- library/std/src/ffi/c_str.rs | 19 +++++++++++++++++++ library/std/src/ffi/mod.rs | 32 ++++++++++++++++++++++++++------ library/std/src/lib.rs | 1 + 7 files changed, 79 insertions(+), 16 deletions(-) create mode 100644 library/std/src/ffi/c_str.rs diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index 9419b0cfb24fa..35d1f681af605 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -1,3 +1,5 @@ +//! [`CString`] and its related types. + #[cfg(test)] mod tests; diff --git a/library/alloc/src/ffi/mod.rs b/library/alloc/src/ffi/mod.rs index e8530fbc1f08f..9fc1acc231bff 100644 --- a/library/alloc/src/ffi/mod.rs +++ b/library/alloc/src/ffi/mod.rs @@ -80,9 +80,13 @@ #![stable(feature = "alloc_ffi", since = "1.64.0")] +#[doc(no_inline)] #[stable(feature = "alloc_c_string", since = "1.64.0")] -pub use self::c_str::FromVecWithNulError; +pub use self::c_str::{FromVecWithNulError, IntoStringError, NulError}; + +#[doc(inline)] #[stable(feature = "alloc_c_string", since = "1.64.0")] -pub use self::c_str::{CString, IntoStringError, NulError}; +pub use self::c_str::CString; -mod c_str; +#[unstable(feature = "c_str_module", issue = "112134")] +pub mod c_str; diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 248943cf02260..cf1427b21bc74 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -1,3 +1,5 @@ +//! [`CStr`] and its related types. + use crate::cmp::Ordering; use crate::error::Error; use crate::ffi::c_char; @@ -8,15 +10,20 @@ use crate::slice; use crate::slice::memchr; use crate::str; +// FIXME: because this is doc(inline)d, we *have* to use intra-doc links because the actual link +// depends on where the item is being documented. however, since this is libcore, we can't +// actually reference libstd or liballoc in intra-doc links. so, the best we can do is remove the +// links to `CString` and `String` for now until a solution is developed + /// Representation of a borrowed C string. /// /// This type represents a borrowed reference to a nul-terminated /// array of bytes. It can be constructed safely from a &[[u8]] /// slice, or unsafely from a raw `*const c_char`. It can then be /// converted to a Rust &[str] by performing UTF-8 validation, or -/// into an owned [`CString`]. +/// into an owned `CString`. /// -/// `&CStr` is to [`CString`] as &[str] is to [`String`]: the former +/// `&CStr` is to `CString` as &[str] is to `String`: the former /// in each pair are borrowed references; the latter are owned /// strings. /// @@ -25,9 +32,6 @@ use crate::str; /// Instead, safe wrappers of FFI functions may leverage the unsafe [`CStr::from_ptr`] constructor /// to provide a safe interface to other consumers. /// -/// [`CString`]: ../../std/ffi/struct.CString.html -/// [`String`]: ../../std/string/struct.String.html -/// /// # Examples /// /// Inspecting a foreign C string: @@ -124,10 +128,13 @@ enum FromBytesWithNulErrorKind { NotNulTerminated, } +// FIXME: const stability attributes should not be required here, I think impl FromBytesWithNulError { + #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")] const fn interior_nul(pos: usize) -> FromBytesWithNulError { FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) } } + #[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")] const fn not_nul_terminated() -> FromBytesWithNulError { FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated } } diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 44200926a32eb..3627e844222ac 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -13,10 +13,20 @@ use crate::fmt; use crate::marker::PhantomData; use crate::ops::{Deref, DerefMut}; +#[doc(no_inline)] #[stable(feature = "core_c_str", since = "1.64.0")] -pub use self::c_str::{CStr, FromBytesUntilNulError, FromBytesWithNulError}; +pub use self::c_str::FromBytesWithNulError; -mod c_str; +#[doc(no_inline)] +#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] +pub use self::c_str::FromBytesUntilNulError; + +#[doc(inline)] +#[stable(feature = "core_c_str", since = "1.64.0")] +pub use self::c_str::CStr; + +#[unstable(feature = "c_str_module", issue = "112134")] +pub mod c_str; macro_rules! type_alias { { diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs new file mode 100644 index 0000000000000..b59b0c5bba65a --- /dev/null +++ b/library/std/src/ffi/c_str.rs @@ -0,0 +1,19 @@ +//! [`CStr`], [`CString`], and related types. + +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::ffi::c_str::CStr; + +#[stable(feature = "cstr_from_bytes", since = "1.10.0")] +pub use core::ffi::c_str::FromBytesWithNulError; + +#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] +pub use core::ffi::c_str::FromBytesUntilNulError; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use alloc::ffi::c_str::{CString, NulError}; + +#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] +pub use alloc::ffi::c_str::FromVecWithNulError; + +#[stable(feature = "cstring_into", since = "1.7.0")] +pub use alloc::ffi::c_str::IntoStringError; diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index 818571ddaaa16..a14a3fe760da0 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -161,12 +161,32 @@ #![stable(feature = "rust1", since = "1.0.0")] -#[stable(feature = "alloc_c_string", since = "1.64.0")] -pub use alloc::ffi::{CString, FromVecWithNulError, IntoStringError, NulError}; -#[stable(feature = "cstr_from_bytes_until_nul", since = "1.73.0")] -pub use core::ffi::FromBytesUntilNulError; -#[stable(feature = "core_c_str", since = "1.64.0")] -pub use core::ffi::{CStr, FromBytesWithNulError}; +#[unstable(feature = "c_str_module", issue = "112134")] +pub mod c_str; + +#[doc(inline)] +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::c_str::{CStr, CString}; + +#[doc(no_inline)] +#[stable(feature = "cstr_from_bytes", since = "1.10.0")] +pub use self::c_str::FromBytesWithNulError; + +#[doc(no_inline)] +#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] +pub use self::c_str::FromBytesUntilNulError; + +#[doc(no_inline)] +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::c_str::NulError; + +#[doc(no_inline)] +#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] +pub use self::c_str::FromVecWithNulError; + +#[doc(no_inline)] +#[stable(feature = "cstring_into", since = "1.7.0")] +pub use self::c_str::IntoStringError; #[stable(feature = "rust1", since = "1.0.0")] pub use self::os_str::{OsStr, OsString}; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index c6cd2c6786ad6..87d9a0c9185e8 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -314,6 +314,7 @@ // // Library features (core): // tidy-alphabetical-start +#![feature(c_str_module)] #![feature(char_internals)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] From 70639c8a6a45f52cd875d90bf847f6a81f680b83 Mon Sep 17 00:00:00 2001 From: Raoul Strackx Date: Tue, 27 Feb 2024 16:29:10 +0100 Subject: [PATCH 02/14] Fixing shellcheck comments on lvi test script --- .../x86_64-fortanix-unknown-sgx-lvi/script.sh | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh index 04a34724518e8..aacd0a67682b9 100644 --- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh +++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh @@ -1,20 +1,20 @@ -#!/bin/sh +#!/bin/bash set -exuo pipefail function build { CRATE=enclave - mkdir -p $WORK_DIR - pushd $WORK_DIR - rm -rf $CRATE - cp -a $TEST_DIR/enclave . + mkdir -p "${WORK_DIR}" + pushd "${WORK_DIR}" + rm -rf "${CRATE}" + cp -a "${TEST_DIR}"/enclave . pushd $CRATE - echo ${WORK_DIR} + echo "${WORK_DIR}" # HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features. # These come from the top-level Rust workspace, that this crate is not a # member of, but Cargo tries to load the workspace `Cargo.toml` anyway. env RUSTC_BOOTSTRAP=1 - cargo -v run --target $TARGET + cargo -v run --target "${TARGET}" popd popd } @@ -22,17 +22,18 @@ function build { function check { local func_re="$1" local checks="${TEST_DIR}/$2" - local asm=$(mktemp) + local asm="" local objdump="${LLVM_BIN_DIR}/llvm-objdump" local filecheck="${LLVM_BIN_DIR}/FileCheck" local enclave=${WORK_DIR}/enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave - func="$(${objdump} --syms --demangle ${enclave} | \ + asm=$(mktemp) + func="$(${objdump} --syms --demangle "${enclave}" | \ grep --only-matching -E "[[:blank:]]+${func_re}\$" | \ sed -e 's/^[[:space:]]*//' )" ${objdump} --disassemble-symbols="${func}" --demangle \ - ${enclave} > ${asm} - ${filecheck} --input-file ${asm} ${checks} + "${enclave}" > "${asm}" + ${filecheck} --input-file "${asm}" "${checks}" if [ "${func_re}" != "rust_plus_one_global_asm" && "${func_re}" != "cmake_plus_one_c_global_asm" ]; then @@ -40,7 +41,7 @@ function check { # of `shlq $0x0, (%rsp); lfence; retq` are used instead. # https://www.intel.com/content/www/us/en/developer/articles/technical/ # software-security-guidance/technical-documentation/load-value-injection.html - ${filecheck} --implicit-check-not ret --input-file ${asm} ${checks} + ${filecheck} --implicit-check-not ret --input-file "${asm}" "${checks}" fi } From 3e675bdb481820360c1105b2731f9258e1081b0d Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Thu, 29 Feb 2024 21:38:53 +0800 Subject: [PATCH 03/14] add myself to rotation --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index ef3f3693e6174..de91cc8af824f 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -660,6 +660,7 @@ compiler-team-contributors = [ "@TaKO8Ki", "@nnethercote", "@fmease", + "@fee1-dead", ] compiler = [ "compiler-team", From c3954b358f9e2be96d0dd553a8efaefc49f0bba7 Mon Sep 17 00:00:00 2001 From: r0cky Date: Sun, 3 Mar 2024 00:57:37 +0800 Subject: [PATCH 04/14] Add a tidy check that checks whether the fluent slugs only appear once --- src/tools/tidy/src/fluent_alphabetical.rs | 58 ++++++++++++++++++++--- src/tools/tidy/src/fluent_used.rs | 43 +++++++++++++++++ src/tools/tidy/src/lib.rs | 1 + 3 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 src/tools/tidy/src/fluent_used.rs diff --git a/src/tools/tidy/src/fluent_alphabetical.rs b/src/tools/tidy/src/fluent_alphabetical.rs index 67b745373f019..9803b6eab2db5 100644 --- a/src/tools/tidy/src/fluent_alphabetical.rs +++ b/src/tools/tidy/src/fluent_alphabetical.rs @@ -1,6 +1,7 @@ //! Checks that all Flunt files have messages in alphabetical order use crate::walk::{filter_dirs, walk}; +use std::collections::HashMap; use std::{fs::OpenOptions, io::Write, path::Path}; use regex::Regex; @@ -13,11 +14,27 @@ fn filter_fluent(path: &Path) -> bool { if let Some(ext) = path.extension() { ext.to_str() != Some("ftl") } else { true } } -fn check_alphabetic(filename: &str, fluent: &str, bad: &mut bool) { +fn check_alphabetic( + filename: &str, + fluent: &str, + bad: &mut bool, + all_defined_msgs: &mut HashMap, +) { let mut matches = MESSAGE.captures_iter(fluent).peekable(); while let Some(m) = matches.next() { + let name = m.get(1).unwrap(); + if let Some(defined_filename) = all_defined_msgs.get(name.as_str()) { + tidy_error!( + bad, + "{filename}: message `{}` is already defined in {}", + name.as_str(), + defined_filename, + ); + } + + all_defined_msgs.insert(name.as_str().to_owned(), filename.to_owned()); + if let Some(next) = matches.peek() { - let name = m.get(1).unwrap(); let next = next.get(1).unwrap(); if name.as_str() > next.as_str() { tidy_error!( @@ -34,13 +51,29 @@ run `./x.py test tidy --bless` to sort the file correctly", } } -fn sort_messages(fluent: &str) -> String { +fn sort_messages( + filename: &str, + fluent: &str, + bad: &mut bool, + all_defined_msgs: &mut HashMap, +) -> String { let mut chunks = vec![]; let mut cur = String::new(); for line in fluent.lines() { - if MESSAGE.is_match(line) { + if let Some(name) = MESSAGE.find(line) { + if let Some(defined_filename) = all_defined_msgs.get(name.as_str()) { + tidy_error!( + bad, + "{filename}: message `{}` is already defined in {}", + name.as_str(), + defined_filename, + ); + } + + all_defined_msgs.insert(name.as_str().to_owned(), filename.to_owned()); chunks.push(std::mem::take(&mut cur)); } + cur += line; cur.push('\n'); } @@ -53,20 +86,33 @@ fn sort_messages(fluent: &str) -> String { } pub fn check(path: &Path, bless: bool, bad: &mut bool) { + let mut all_defined_msgs = HashMap::new(); walk( path, |path, is_dir| filter_dirs(path) || (!is_dir && filter_fluent(path)), &mut |ent, contents| { if bless { - let sorted = sort_messages(contents); + let sorted = sort_messages( + ent.path().to_str().unwrap(), + contents, + bad, + &mut all_defined_msgs, + ); if sorted != contents { let mut f = OpenOptions::new().write(true).truncate(true).open(ent.path()).unwrap(); f.write(sorted.as_bytes()).unwrap(); } } else { - check_alphabetic(ent.path().to_str().unwrap(), contents, bad); + check_alphabetic( + ent.path().to_str().unwrap(), + contents, + bad, + &mut all_defined_msgs, + ); } }, ); + + crate::fluent_used::check(path, all_defined_msgs, bad); } diff --git a/src/tools/tidy/src/fluent_used.rs b/src/tools/tidy/src/fluent_used.rs new file mode 100644 index 0000000000000..b73e79cb38d94 --- /dev/null +++ b/src/tools/tidy/src/fluent_used.rs @@ -0,0 +1,43 @@ +//! Checks that all Fluent messages appear at least twice + +use crate::walk::{filter_dirs, walk}; +use regex::Regex; +use std::collections::HashMap; +use std::path::Path; + +lazy_static::lazy_static! { + static ref WORD: Regex = Regex::new(r"\w+").unwrap(); +} + +fn filter_used_messages( + contents: &str, + msgs_not_appeared_yet: &mut HashMap, + msgs_appeared_only_once: &mut HashMap, +) { + // we don't just check messages never appear in Rust files, + // because messages can be used as parts of other fluent messages in Fluent files, + // so we do checking messages appear only once in all Rust and Fluent files. + let mut matches = WORD.find_iter(contents); + while let Some(name) = matches.next() { + if let Some((name, filename)) = msgs_not_appeared_yet.remove_entry(name.as_str()) { + // if one msg appears for the first time, + // remove it from `msgs_not_appeared_yet` and insert it into `msgs_appeared_only_once`. + msgs_appeared_only_once.insert(name, filename); + } else { + // if one msg appears for the second time, + // remove it from `msgs_appeared_only_once`. + msgs_appeared_only_once.remove(name.as_str()); + } + } +} + +pub fn check(path: &Path, mut all_defined_msgs: HashMap, bad: &mut bool) { + let mut msgs_appear_only_once = HashMap::new(); + walk(path, |path, _| filter_dirs(path), &mut |_, contents| { + filter_used_messages(contents, &mut all_defined_msgs, &mut msgs_appear_only_once); + }); + + for (name, filename) in msgs_appear_only_once { + tidy_error!(bad, "{filename}: message `{}` is not used", name,); + } +} diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 6f3ade0ab58c7..670b7eb2be995 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -65,6 +65,7 @@ pub mod ext_tool_checks; pub mod extdeps; pub mod features; pub mod fluent_alphabetical; +mod fluent_used; pub(crate) mod iter_header; pub mod mir_opt_tests; pub mod pal; From d88c7ffc62d0f1ee15abf3e9e65af3eeedc7d003 Mon Sep 17 00:00:00 2001 From: r0cky Date: Sun, 3 Mar 2024 00:57:45 +0800 Subject: [PATCH 05/14] Remove unused fluent messages --- compiler/rustc_const_eval/messages.ftl | 3 --- compiler/rustc_infer/messages.ftl | 8 -------- compiler/rustc_lint/messages.ftl | 2 -- compiler/rustc_parse/messages.ftl | 4 ---- compiler/rustc_passes/messages.ftl | 5 ----- 5 files changed, 22 deletions(-) diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 2805ca360ad3d..1bad62c4103a3 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -146,9 +146,6 @@ const_eval_intern_kind = {$kind -> *[other] {""} } -const_eval_invalid_align = - align has to be a power of 2 - const_eval_invalid_align_details = invalid align passed to `{$name}`: {$align} is {$err_kind -> [not_power_of_two] not a power of 2 diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index 2de87cbe631ac..e44a6ae3b3f2e 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -181,14 +181,6 @@ infer_more_targeted = {$has_param_name -> infer_msl_introduces_static = introduces a `'static` lifetime requirement infer_msl_unmet_req = because this has an unmet lifetime requirement -infer_need_type_info_in_coroutine = - type inside {$coroutine_kind -> - [async_block] `async` block - [async_closure] `async` closure - [async_fn] `async fn` body - *[coroutine] coroutine - } must be known in this context - infer_nothing = {""} diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 63e2fe47659db..8bf9d0b9d4aac 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -562,8 +562,6 @@ lint_suspicious_double_ref_clone = lint_suspicious_double_ref_deref = using `.deref()` on a double reference, which returns `{$ty}` instead of dereferencing the inner type -lint_trivial_untranslatable_diag = diagnostic with static strings only - lint_ty_qualified = usage of qualified `ty::{$ty}` .suggestion = try importing it and using it unqualified diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 60cc138fd7bc2..a100e2d47bbbb 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -392,9 +392,6 @@ parse_invalid_identifier_with_leading_number = identifiers cannot start with a n parse_invalid_interpolated_expression = invalid interpolated expression -parse_invalid_literal_suffix = suffixes on {$kind} literals are invalid - .label = invalid suffix `{$suffix}` - parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid .label = invalid suffix `{$suffix}` .tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases @@ -609,7 +606,6 @@ parse_nonterminal_expected_item_keyword = expected an item keyword parse_nonterminal_expected_lifetime = expected a lifetime, found `{$token}` parse_nonterminal_expected_statement = expected a statement -parse_not_supported = not supported parse_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index c223b8475288b..7fc523ffe0dea 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -302,9 +302,6 @@ passes_export_name = attribute should be applied to a free function, impl method or static .label = not a free function, impl method or static -passes_expr_not_allowed_in_context = - {$expr} is not allowed in a `{$context}` - passes_extern_main = the `main` function cannot be declared in an `extern` block @@ -405,8 +402,6 @@ passes_lang_item_on_incorrect_target = `{$name}` language item must be applied to a {$expected_target} .label = attribute should be applied to a {$expected_target}, not a {$actual_target} -passes_layout = - layout error: {$layout_error} passes_layout_abi = abi: {$abi} passes_layout_align = From 9da004ea1997ac0eedbb882fa52960417725bd48 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Mon, 10 Jul 2023 01:28:23 -0700 Subject: [PATCH 06/14] Dynamically size sigaltstk in std On modern Linux with Intel AMX and 1KiB matrices, Arm SVE with potentially 2KiB vectors, and RISCV Vectors with up to 16KiB vectors, we must handle dynamic signal stack sizes. We can do so unconditionally by using getauxval, but assuming it may return 0 as an answer, thus falling back to the old constant if needed. --- .../std/src/sys/pal/unix/stack_overflow.rs | 50 +++++++++++++++---- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 923637cbaf260..78a599077c758 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -51,7 +51,7 @@ mod imp { #[cfg(all(target_os = "linux", target_env = "gnu"))] use libc::{mmap64, munmap}; use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_DFL}; - use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE}; + use libc::{sigaltstack, SS_DISABLE}; use libc::{MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE, SIGSEGV}; use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering}; @@ -130,7 +130,7 @@ mod imp { drop_handler(MAIN_ALTSTACK.load(Ordering::Relaxed)); } - unsafe fn get_stackp() -> *mut libc::c_void { + unsafe fn get_stack() -> libc::stack_t { // OpenBSD requires this flag for stack mapping // otherwise the said mapping will fail as a no-op on most systems // and has a different meaning on FreeBSD @@ -148,20 +148,28 @@ mod imp { target_os = "dragonfly", )))] let flags = MAP_PRIVATE | MAP_ANON; - let stackp = - mmap64(ptr::null_mut(), SIGSTKSZ + page_size(), PROT_READ | PROT_WRITE, flags, -1, 0); + + let sigstack_size = sigstack_size(); + let page_size = page_size(); + + let stackp = mmap64( + ptr::null_mut(), + sigstack_size + page_size, + PROT_READ | PROT_WRITE, + flags, + -1, + 0, + ); if stackp == MAP_FAILED { panic!("failed to allocate an alternative stack: {}", io::Error::last_os_error()); } - let guard_result = libc::mprotect(stackp, page_size(), PROT_NONE); + let guard_result = libc::mprotect(stackp, page_size, PROT_NONE); if guard_result != 0 { panic!("failed to set up alternative stack guard page: {}", io::Error::last_os_error()); } - stackp.add(page_size()) - } + let stackp = stackp.add(page_size); - unsafe fn get_stack() -> libc::stack_t { - libc::stack_t { ss_sp: get_stackp(), ss_flags: 0, ss_size: SIGSTKSZ } + libc::stack_t { ss_sp: stackp, ss_flags: 0, ss_size: sigstack_size } } pub unsafe fn make_handler() -> Handler { @@ -182,6 +190,8 @@ mod imp { pub unsafe fn drop_handler(data: *mut libc::c_void) { if !data.is_null() { + let sigstack_size = sigstack_size(); + let page_size = page_size(); let stack = libc::stack_t { ss_sp: ptr::null_mut(), ss_flags: SS_DISABLE, @@ -189,14 +199,32 @@ mod imp { // UNIX2003 which returns ENOMEM when disabling a stack while // passing ss_size smaller than MINSIGSTKSZ. According to POSIX // both ss_sp and ss_size should be ignored in this case. - ss_size: SIGSTKSZ, + ss_size: sigstack_size, }; sigaltstack(&stack, ptr::null_mut()); // We know from `get_stackp` that the alternate stack we installed is part of a mapping // that started one page earlier, so walk back a page and unmap from there. - munmap(data.sub(page_size()), SIGSTKSZ + page_size()); + munmap(data.sub(page_size), sigstack_size + page_size); } } + + /// Modern kernels on modern hardware can have dynamic signal stack sizes. + #[cfg(any(target_os = "linux", target_os = "android"))] + fn sigstack_size() -> usize { + // FIXME: reuse const from libc when available? + const AT_MINSIGSTKSZ: crate::ffi::c_ulong = 51; + let dynamic_sigstksz = unsafe { libc::getauxval(AT_MINSIGSTKSZ) }; + // If getauxval couldn't find the entry, it returns 0, + // so take the higher of the "constant" and auxval. + // This transparently supports older kernels which don't provide AT_MINSIGSTKSZ + libc::SIGSTKSZ.max(dynamic_sigstksz as _) + } + + /// Not all OS support hardware where this is needed. + #[cfg(not(any(target_os = "linux", target_os = "android")))] + fn sigstack_size() -> usize { + libc::SIGSTKSZ + } } #[cfg(not(any( From c7a48a507ad10617869ed1fbd3f510fd5ad93584 Mon Sep 17 00:00:00 2001 From: Matt Harding Date: Thu, 7 Mar 2024 03:09:29 +0000 Subject: [PATCH 07/14] Revert back to Git-for-Windows for MinGW CI builds In https://github.com/rust-lang/rust/pull/121182 the mingw build was changed to use MSYS2's version of Git. This commit reverts that, as it was considered too slow. --- INSTALL.md | 20 +++++++++++++------- src/ci/scripts/install-msys2.sh | 14 ++++++++------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index d7e0fd72044e9..03e7a3431a551 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -145,6 +145,15 @@ toolchain. 1. Download the latest [MSYS2 installer][msys2] and go through the installer. +2. Download and install [Git for Windows](https://git-scm.com/download/win). + Make sure that it's in your Windows PATH. To enable access to it from within + MSYS2, edit the relevant `mingw[32|64].ini` file in your MSYS2 installation + directory and uncomment the line `MSYS2_PATH_TYPE=inherit`. + + You could install and use MSYS2's version of git instead with `pacman`, + however this is not recommended as it's excrutiatingly slow, and not frequently + tested for compatability. + 2. Start a MINGW64 or MINGW32 shell (depending on whether you want 32-bit or 64-bit Rust) either from your start menu, or by running `mingw64.exe` or `mingw32.exe` from your MSYS2 installation directory (e.g. `C:\msys64`). @@ -160,8 +169,7 @@ toolchain. # Note that it is important that you do **not** use the 'python2', 'cmake', # and 'ninja' packages from the 'msys2' subsystem. # The build has historically been known to fail with these packages. - pacman -S git \ - make \ + pacman -S make \ diffutils \ tar \ mingw-w64-x86_64-python \ @@ -176,11 +184,9 @@ toolchain. python x.py setup dist && python x.py build && python x.py install ``` -If you want to use the native versions of Git, Python, or CMake you can remove -them from the above pacman command and install them from another source. Make -sure that they're in your Windows PATH, and edit the relevant `mingw[32|64].ini` -file in your MSYS2 installation directory by uncommenting the line -`MSYS2_PATH_TYPE=inherit` to include them in your MSYS2 PATH. +If you want to try the native Windows versions of Python or CMake, you can remove +them from the above pacman command and install them from another source. Follow +the instructions in step 2 to get them on PATH. Using Windows native Python can be helpful if you get errors when building LLVM. You may also want to use Git for Windows, as it is often *much* faster. Turning diff --git a/src/ci/scripts/install-msys2.sh b/src/ci/scripts/install-msys2.sh index 905edf38a09db..e3f76744cbe64 100755 --- a/src/ci/scripts/install-msys2.sh +++ b/src/ci/scripts/install-msys2.sh @@ -31,12 +31,14 @@ if isWindows; then # Delete these pre-installed tools so we can't accidentally use them, because we are using the # MSYS2 setup action versions instead. # Delete pre-installed version of MSYS2 + echo "Cleaning up tools in PATH" rm -r "/c/msys64/" # Delete Strawberry Perl, which contains a version of mingw rm -r "/c/Strawberry/" # Delete these other copies of mingw, I don't even know where they come from. rm -r "/c/mingw64/" rm -r "/c/mingw32/" + echo "Finished cleaning up tools in PATH" if isKnownToBeMingwBuild; then # Use the mingw version of CMake for mingw builds. @@ -46,11 +48,11 @@ if isWindows; then # Install mingw-w64-$arch-cmake pacboy -S --noconfirm cmake:p - # We use Git-for-Windows for MSVC builds, and MSYS2 Git for mingw builds, - # so that both are tested. - # Delete Windows-Git - rm -r "/c/Program Files/Git/" - # Install MSYS2 git - pacman -S --noconfirm git + # It would be nice to use MSYS's git in MinGW builds so that it's tested and known to + # work. But it makes everything extremely slow, so it's commented out for now. + # # Delete Windows-Git + # rm -r "/c/Program Files/Git/" + # # Install MSYS2 git + # pacman -S --noconfirm git fi fi From 1195518a5e59e6d37c78db24c637780d2c662f3b Mon Sep 17 00:00:00 2001 From: Kornel Date: Fri, 1 Mar 2024 13:37:08 +0000 Subject: [PATCH 08/14] Helper function for resolve_path --- compiler/rustc_expand/src/base.rs | 25 +++++++++++-------------- compiler/rustc_span/src/lib.rs | 11 +++++++++++ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 69dfb48919cdb..a5f54b6b113e7 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1233,21 +1233,18 @@ pub fn resolve_path(sess: &Session, path: impl Into, span: Span) -> PRe // after macro expansion (that is, they are unhygienic). if !path.is_absolute() { let callsite = span.source_callsite(); - let mut result = match sess.source_map().span_to_filename(callsite) { - FileName::Real(name) => name - .into_local_path() - .expect("attempting to resolve a file path in an external file"), - FileName::DocTest(path, _) => path, - other => { - return Err(sess.dcx().create_err(errors::ResolveRelativePath { - span, - path: sess.source_map().filename_for_diagnostics(&other).to_string(), - })); - } + let source_map = sess.source_map(); + let Some(mut base_path) = source_map.span_to_filename(callsite).into_local_path() else { + return Err(sess.dcx().create_err(errors::ResolveRelativePath { + span, + path: source_map + .filename_for_diagnostics(&source_map.span_to_filename(callsite)) + .to_string(), + })); }; - result.pop(); - result.push(path); - Ok(result) + base_path.pop(); + base_path.push(path); + Ok(base_path) } else { Ok(path) } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 616a7ccc7c64f..0c974ef4ca3eb 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -427,6 +427,17 @@ impl FileName { src.hash(&mut hasher); FileName::InlineAsm(hasher.finish()) } + + /// Returns the path suitable for reading from the file system on the local host, + /// if this information exists. + /// Avoid embedding this in build artifacts; see `remapped_path_if_available()` for that. + pub fn into_local_path(self) -> Option { + match self { + FileName::Real(path) => path.into_local_path(), + FileName::DocTest(path, _) => Some(path), + _ => None, + } + } } /// Represents a span. From 25ab1c70734f101596e8703d8c3a4e65da55ec01 Mon Sep 17 00:00:00 2001 From: Kornel Date: Fri, 1 Mar 2024 02:49:02 +0000 Subject: [PATCH 09/14] Suggest correct path in include_bytes! --- .../rustc_builtin_macros/src/source_util.rs | 150 ++++++++++++++---- compiler/rustc_expand/src/base.rs | 16 +- tests/ui/include-macros/parent_dir.rs | 12 ++ tests/ui/include-macros/parent_dir.stderr | 50 ++++++ tests/ui/macros/macros-nonfatal-errors.rs | 2 +- tests/ui/macros/macros-nonfatal-errors.stderr | 4 +- 6 files changed, 200 insertions(+), 34 deletions(-) create mode 100644 tests/ui/include-macros/parent_dir.rs create mode 100644 tests/ui/include-macros/parent_dir.stderr diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 2da9bda19e034..134a6baea6e8b 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -3,18 +3,20 @@ use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_ast_pretty::pprust; +use rustc_data_structures::sync::Lrc; use rustc_expand::base::{ - check_zero_tts, get_single_str_from_tts, parse_expr, resolve_path, DummyResult, ExtCtxt, - MacEager, MacResult, + check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr, + resolve_path, DummyResult, ExtCtxt, MacEager, MacResult, }; use rustc_expand::module::DirOwnership; use rustc_parse::new_parser_from_file; use rustc_parse::parser::{ForceCollect, Parser}; use rustc_session::lint::builtin::INCOMPLETE_INCLUDE; +use rustc_span::source_map::SourceMap; use rustc_span::symbol::Symbol; use rustc_span::{Pos, Span}; - use smallvec::SmallVec; +use std::path::{Path, PathBuf}; use std::rc::Rc; // These macros all relate to the file system; they either return @@ -180,32 +182,22 @@ pub fn expand_include_str( tts: TokenStream, ) -> Box { let sp = cx.with_def_site_ctxt(sp); - let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") { - Ok(file) => file, + let (path, path_span) = match get_single_str_spanned_from_tts(cx, sp, tts, "include_str!") { + Ok(res) => res, Err(guar) => return DummyResult::any(sp, guar), }; - let file = match resolve_path(&cx.sess, file.as_str(), sp) { - Ok(f) => f, - Err(err) => { - let guar = err.emit(); - return DummyResult::any(sp, guar); - } - }; - match cx.source_map().load_binary_file(&file) { + match load_binary_file(cx, path.as_str().as_ref(), sp, path_span) { Ok(bytes) => match std::str::from_utf8(&bytes) { Ok(src) => { let interned_src = Symbol::intern(src); MacEager::expr(cx.expr_str(sp, interned_src)) } Err(_) => { - let guar = cx.dcx().span_err(sp, format!("{} wasn't a utf-8 file", file.display())); + let guar = cx.dcx().span_err(sp, format!("`{path}` wasn't a utf-8 file")); DummyResult::any(sp, guar) } }, - Err(e) => { - let guar = cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e)); - DummyResult::any(sp, guar) - } + Err(dummy) => dummy, } } @@ -215,25 +207,123 @@ pub fn expand_include_bytes( tts: TokenStream, ) -> Box { let sp = cx.with_def_site_ctxt(sp); - let file = match get_single_str_from_tts(cx, sp, tts, "include_bytes!") { - Ok(file) => file, + let (path, path_span) = match get_single_str_spanned_from_tts(cx, sp, tts, "include_bytes!") { + Ok(res) => res, Err(guar) => return DummyResult::any(sp, guar), }; - let file = match resolve_path(&cx.sess, file.as_str(), sp) { - Ok(f) => f, + match load_binary_file(cx, path.as_str().as_ref(), sp, path_span) { + Ok(bytes) => { + let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes)); + MacEager::expr(expr) + } + Err(dummy) => dummy, + } +} + +fn load_binary_file( + cx: &mut ExtCtxt<'_>, + original_path: &Path, + macro_span: Span, + path_span: Span, +) -> Result, Box> { + let resolved_path = match resolve_path(&cx.sess, original_path, macro_span) { + Ok(path) => path, Err(err) => { let guar = err.emit(); - return DummyResult::any(sp, guar); + return Err(DummyResult::any(macro_span, guar)); } }; - match cx.source_map().load_binary_file(&file) { - Ok(bytes) => { - let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes)); - MacEager::expr(expr) + match cx.source_map().load_binary_file(&resolved_path) { + Ok(data) => Ok(data), + Err(io_err) => { + let mut err = cx.dcx().struct_span_err( + macro_span, + format!("couldn't read `{}`: {io_err}", resolved_path.display()), + ); + + if original_path.is_relative() { + let source_map = cx.sess.source_map(); + let new_path = source_map + .span_to_filename(macro_span.source_callsite()) + .into_local_path() + .and_then(|src| find_path_suggestion(source_map, src.parent()?, original_path)) + .and_then(|path| path.into_os_string().into_string().ok()); + + if let Some(new_path) = new_path { + err.span_suggestion( + path_span, + "there is a file with the same name in a different directory", + format!("\"{}\"", new_path.escape_debug()), + rustc_lint_defs::Applicability::MachineApplicable, + ); + } + } + let guar = err.emit(); + Err(DummyResult::any(macro_span, guar)) } - Err(e) => { - let guar = cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e)); - DummyResult::any(sp, guar) + } +} + +fn find_path_suggestion( + source_map: &SourceMap, + base_dir: &Path, + wanted_path: &Path, +) -> Option { + // Fix paths that assume they're relative to cargo manifest dir + let mut base_c = base_dir.components(); + let mut wanted_c = wanted_path.components(); + let mut without_base = None; + while let Some(wanted_next) = wanted_c.next() { + if wanted_c.as_path().file_name().is_none() { + break; + } + // base_dir may be absolute + while let Some(base_next) = base_c.next() { + if base_next == wanted_next { + without_base = Some(wanted_c.as_path()); + break; + } + } + } + let root_absolute = without_base.into_iter().map(PathBuf::from); + + let base_dir_components = base_dir.components().count(); + // Avoid going all the way to the root dir + let max_parent_components = if base_dir.is_relative() { + base_dir_components + 1 + } else { + base_dir_components.saturating_sub(1) + }; + + // Try with additional leading ../ + let mut prefix = PathBuf::new(); + let add = std::iter::from_fn(|| { + prefix.push(".."); + Some(prefix.join(wanted_path)) + }) + .take(max_parent_components.min(3)); + + // Try without leading directories + let mut trimmed_path = wanted_path; + let remove = std::iter::from_fn(|| { + let mut components = trimmed_path.components(); + let removed = components.next()?; + trimmed_path = components.as_path(); + let _ = trimmed_path.file_name()?; // ensure there is a file name left + Some([ + Some(trimmed_path.to_path_buf()), + (removed != std::path::Component::ParentDir) + .then(|| Path::new("..").join(trimmed_path)), + ]) + }) + .flatten() + .flatten() + .take(4); + + for new_path in root_absolute.chain(add).chain(remove) { + if source_map.file_exists(&base_dir.join(&new_path)) { + return Some(new_path); } } + None } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index a5f54b6b113e7..58589ebdca675 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1341,6 +1341,15 @@ pub fn get_single_str_from_tts( tts: TokenStream, name: &str, ) -> Result { + get_single_str_spanned_from_tts(cx, span, tts, name).map(|(s, _)| s) +} + +pub fn get_single_str_spanned_from_tts( + cx: &mut ExtCtxt<'_>, + span: Span, + tts: TokenStream, + name: &str, +) -> Result<(Symbol, Span), ErrorGuaranteed> { let mut p = cx.new_parser_from_tts(tts); if p.token == token::Eof { let guar = cx.dcx().emit_err(errors::OnlyOneArgument { span, name }); @@ -1352,7 +1361,12 @@ pub fn get_single_str_from_tts( if p.token != token::Eof { cx.dcx().emit_err(errors::OnlyOneArgument { span, name }); } - expr_to_string(cx, ret, "argument must be a string literal").map(|(s, _)| s) + expr_to_spanned_string(cx, ret, "argument must be a string literal") + .map_err(|err| match err { + Ok((err, _)) => err.emit(), + Err(guar) => guar, + }) + .map(|(symbol, _style, span)| (symbol, span)) } /// Extracts comma-separated expressions from `tts`. diff --git a/tests/ui/include-macros/parent_dir.rs b/tests/ui/include-macros/parent_dir.rs new file mode 100644 index 0000000000000..321baf77025d2 --- /dev/null +++ b/tests/ui/include-macros/parent_dir.rs @@ -0,0 +1,12 @@ +//@ normalize-stderr-test: "`: .*\(os error" -> "`: $$FILE_NOT_FOUND_MSG (os error" + +fn main() { + let _ = include_str!("include-macros/file.txt"); //~ ERROR couldn't read + //~^HELP different directory + let _ = include_str!("hello.rs"); //~ ERROR couldn't read + //~^HELP different directory + let _ = include_bytes!("../../data.bin"); //~ ERROR couldn't read + //~^HELP different directory + let _ = include_str!("tests/ui/include-macros/file.txt"); //~ ERROR couldn't read + //~^HELP different directory +} diff --git a/tests/ui/include-macros/parent_dir.stderr b/tests/ui/include-macros/parent_dir.stderr new file mode 100644 index 0000000000000..7610360815b7a --- /dev/null +++ b/tests/ui/include-macros/parent_dir.stderr @@ -0,0 +1,50 @@ +error: couldn't read `$DIR/include-macros/file.txt`: $FILE_NOT_FOUND_MSG (os error 2) + --> $DIR/parent_dir.rs:4:13 + | +LL | let _ = include_str!("include-macros/file.txt"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info) +help: there is a file with the same name in a different directory + | +LL | let _ = include_str!("file.txt"); + | ~~~~~~~~~~ + +error: couldn't read `$DIR/hello.rs`: $FILE_NOT_FOUND_MSG (os error 2) + --> $DIR/parent_dir.rs:6:13 + | +LL | let _ = include_str!("hello.rs"); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info) +help: there is a file with the same name in a different directory + | +LL | let _ = include_str!("../hello.rs"); + | ~~~~~~~~~~~~~ + +error: couldn't read `$DIR/../../data.bin`: $FILE_NOT_FOUND_MSG (os error 2) + --> $DIR/parent_dir.rs:8:13 + | +LL | let _ = include_bytes!("../../data.bin"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `include_bytes` (in Nightly builds, run with -Z macro-backtrace for more info) +help: there is a file with the same name in a different directory + | +LL | let _ = include_bytes!("data.bin"); + | ~~~~~~~~~~ + +error: couldn't read `$DIR/tests/ui/include-macros/file.txt`: $FILE_NOT_FOUND_MSG (os error 2) + --> $DIR/parent_dir.rs:10:13 + | +LL | let _ = include_str!("tests/ui/include-macros/file.txt"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info) +help: there is a file with the same name in a different directory + | +LL | let _ = include_str!("file.txt"); + | ~~~~~~~~~~ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/macros/macros-nonfatal-errors.rs b/tests/ui/macros/macros-nonfatal-errors.rs index 20e6d70500358..65cb899e0941b 100644 --- a/tests/ui/macros/macros-nonfatal-errors.rs +++ b/tests/ui/macros/macros-nonfatal-errors.rs @@ -1,4 +1,4 @@ -//@ normalize-stderr-test: "existed:.*\(" -> "existed: $$FILE_NOT_FOUND_MSG (" +//@ normalize-stderr-test: "`: .*\(" -> "`: $$FILE_NOT_FOUND_MSG (" // test that errors in a (selection) of macros don't kill compilation // immediately, so that we get more errors listed at a time. diff --git a/tests/ui/macros/macros-nonfatal-errors.stderr b/tests/ui/macros/macros-nonfatal-errors.stderr index ca373ea6cd9e4..d02d2399bbadb 100644 --- a/tests/ui/macros/macros-nonfatal-errors.stderr +++ b/tests/ui/macros/macros-nonfatal-errors.stderr @@ -200,7 +200,7 @@ error: argument must be a string literal LL | include_str!(invalid); | ^^^^^^^ -error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2) +error: couldn't read `$DIR/i'd be quite surprised if a file with this name existed`: $FILE_NOT_FOUND_MSG (os error 2) --> $DIR/macros-nonfatal-errors.rs:113:5 | LL | include_str!("i'd be quite surprised if a file with this name existed"); @@ -214,7 +214,7 @@ error: argument must be a string literal LL | include_bytes!(invalid); | ^^^^^^^ -error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2) +error: couldn't read `$DIR/i'd be quite surprised if a file with this name existed`: $FILE_NOT_FOUND_MSG (os error 2) --> $DIR/macros-nonfatal-errors.rs:115:5 | LL | include_bytes!("i'd be quite surprised if a file with this name existed"); From 7843e46f1793d9712220064c505a0aa8a483cd71 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 9 Mar 2024 01:45:34 +0100 Subject: [PATCH 10/14] Factor out non-branch-related pattern data --- .../rustc_mir_build/src/build/matches/mod.rs | 111 +++++++++--------- .../src/build/matches/simplify.rs | 17 +-- .../rustc_mir_build/src/build/matches/util.rs | 4 +- 3 files changed, 61 insertions(+), 71 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 31591983101f3..cdb82f50b34aa 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -506,13 +506,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { traverse_candidate( candidate, &mut Vec::new(), - &mut |leaf_candidate, parent_bindings| { + &mut |leaf_candidate, parent_data| { if let Some(arm) = arm { self.clear_top_scope(arm.scope); } let binding_end = self.bind_and_guard_matched_candidate( leaf_candidate, - parent_bindings, + parent_data, fake_borrow_temps, scrutinee_span, arm_match_scope, @@ -524,12 +524,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } self.cfg.goto(binding_end, outer_source_info, target_block); }, - |inner_candidate, parent_bindings| { - parent_bindings.push((inner_candidate.bindings, inner_candidate.ascriptions)); + |inner_candidate, parent_data| { + parent_data.push(inner_candidate.extra_data); inner_candidate.subcandidates.into_iter() }, - |parent_bindings| { - parent_bindings.pop(); + |parent_data| { + parent_data.pop(); }, ); @@ -651,7 +651,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if set_match_place { let mut next = Some(&candidate); while let Some(candidate_ref) = next.take() { - for binding in &candidate_ref.bindings { + for binding in &candidate_ref.extra_data.bindings { let local = self.var_local_id(binding.var_id, OutsideGuard); // `try_to_place` may fail if it is unable to resolve the given // `PlaceBuilder` inside a closure. In this case, we don't want to include @@ -924,22 +924,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } -/// A pattern in a form suitable for generating code. +/// Data extracted from a pattern that doesn't affect which branch is taken. Collected during +/// pattern simplification and not mutated later. #[derive(Debug, Clone)] -struct FlatPat<'pat, 'tcx> { +struct PatternExtraData<'tcx> { /// [`Span`] of the original pattern. span: Span, + /// Bindings that must be established. + bindings: Vec>, + + /// Types that must be asserted. + ascriptions: Vec>, +} + +/// A pattern in a form suitable for generating code. +#[derive(Debug, Clone)] +struct FlatPat<'pat, 'tcx> { /// To match the pattern, all of these must be satisfied... // Invariant: all the `MatchPair`s are recursively simplified. // Invariant: or-patterns must be sorted to the end. match_pairs: Vec>, - /// ...these bindings established... - bindings: Vec>, - - /// ...and these types asserted. - ascriptions: Vec>, + extra_data: PatternExtraData<'tcx>, } impl<'tcx, 'pat> FlatPat<'pat, 'tcx> { @@ -948,43 +955,38 @@ impl<'tcx, 'pat> FlatPat<'pat, 'tcx> { pattern: &'pat Pat<'tcx>, cx: &mut Builder<'_, 'tcx>, ) -> Self { - let mut match_pairs = vec![MatchPair::new(place, pattern, cx)]; - let mut bindings = Vec::new(); - let mut ascriptions = Vec::new(); - - cx.simplify_match_pairs(&mut match_pairs, &mut bindings, &mut ascriptions); - - FlatPat { span: pattern.span, match_pairs, bindings, ascriptions } + let mut flat_pat = FlatPat { + match_pairs: vec![MatchPair::new(place, pattern, cx)], + extra_data: PatternExtraData { + span: pattern.span, + bindings: Vec::new(), + ascriptions: Vec::new(), + }, + }; + cx.simplify_match_pairs(&mut flat_pat.match_pairs, &mut flat_pat.extra_data); + flat_pat } } #[derive(Debug)] struct Candidate<'pat, 'tcx> { - /// [`Span`] of the original pattern that gave rise to this candidate. - span: Span, - - /// Whether this `Candidate` has a guard. - has_guard: bool, - - /// All of these must be satisfied... + /// For the candidate to match, &ll of these must be satisfied... // Invariant: all the `MatchPair`s are recursively simplified. // Invariant: or-patterns must be sorted at the end. match_pairs: Vec>, - /// ...these bindings established... - // Invariant: not mutated after candidate creation. - bindings: Vec>, - - /// ...and these types asserted... - // Invariant: not mutated after candidate creation. - ascriptions: Vec>, - /// ...and if this is non-empty, one of these subcandidates also has to match... subcandidates: Vec>, - /// ...and the guard must be evaluated; if it's `false` then branch to `otherwise_block`. + /// ...and the guard must be evaluated if there is one. + has_guard: bool, + + /// If the guard is `false` then branch to `otherwise_block`. otherwise_block: Option, + /// If the candidate matches, bindings and ascriptions must be established. + extra_data: PatternExtraData<'tcx>, + /// The block before the `bindings` have been established. pre_binding_block: Option, /// The pre-binding block of the next candidate. @@ -1003,10 +1005,8 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> { fn from_flat_pat(flat_pat: FlatPat<'pat, 'tcx>, has_guard: bool) -> Self { Candidate { - span: flat_pat.span, match_pairs: flat_pat.match_pairs, - bindings: flat_pat.bindings, - ascriptions: flat_pat.ascriptions, + extra_data: flat_pat.extra_data, has_guard, subcandidates: Vec::new(), otherwise_block: None, @@ -1519,8 +1519,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // FIXME(or_patterns; matthewjasper) Try to be more aggressive here. can_merge &= subcandidate.subcandidates.is_empty() - && subcandidate.bindings.is_empty() - && subcandidate.ascriptions.is_empty(); + && subcandidate.extra_data.bindings.is_empty() + && subcandidate.extra_data.ascriptions.is_empty(); } if can_merge { @@ -1943,7 +1943,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn bind_and_guard_matched_candidate<'pat>( &mut self, candidate: Candidate<'pat, 'tcx>, - parent_bindings: &[(Vec>, Vec>)], + parent_data: &[PatternExtraData<'tcx>], fake_borrows: &[(Place<'tcx>, Local)], scrutinee_span: Span, arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>, @@ -1954,7 +1954,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug_assert!(candidate.match_pairs.is_empty()); - let candidate_source_info = self.source_info(candidate.span); + let candidate_source_info = self.source_info(candidate.extra_data.span); let mut block = candidate.pre_binding_block.unwrap(); @@ -1971,11 +1971,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.ascribe_types( block, - parent_bindings + parent_data .iter() - .flat_map(|(_, ascriptions)| ascriptions) + .flat_map(|d| &d.ascriptions) .cloned() - .chain(candidate.ascriptions), + .chain(candidate.extra_data.ascriptions), ); // rust-lang/rust#27282: The `autoref` business deserves some @@ -2063,10 +2063,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { && let Some(guard) = arm.guard { let tcx = self.tcx; - let bindings = parent_bindings - .iter() - .flat_map(|(bindings, _)| bindings) - .chain(&candidate.bindings); + let bindings = + parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings); self.bind_matched_candidate_for_guard(block, schedule_drops, bindings.clone()); let guard_frame = GuardFrame { @@ -2144,10 +2142,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // ``` // // and that is clearly not correct. - let by_value_bindings = parent_bindings + let by_value_bindings = parent_data .iter() - .flat_map(|(bindings, _)| bindings) - .chain(&candidate.bindings) + .flat_map(|d| &d.bindings) + .chain(&candidate.extra_data.bindings) .filter(|binding| matches!(binding.binding_mode, BindingMode::ByValue)); // Read all of the by reference bindings to ensure that the // place they refer to can't be modified by the guard. @@ -2172,10 +2170,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.bind_matched_candidate_for_arm_body( block, schedule_drops, - parent_bindings - .iter() - .flat_map(|(bindings, _)| bindings) - .chain(&candidate.bindings), + parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings), storages_alive, ); block diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index a3fccb7c31955..97b94a0b362af 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -12,20 +12,19 @@ //! sort of test: for example, testing which variant an enum is, or //! testing a value against a constant. -use crate::build::matches::{Ascription, Binding, Candidate, FlatPat, MatchPair, TestCase}; +use crate::build::matches::{Candidate, FlatPat, MatchPair, PatternExtraData, TestCase}; use crate::build::Builder; use std::mem; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Simplify a list of match pairs so they all require a test. Stores relevant bindings and - /// ascriptions in the provided `Vec`s. + /// ascriptions in `extra_data`. #[instrument(skip(self), level = "debug")] pub(super) fn simplify_match_pairs<'pat>( &mut self, match_pairs: &mut Vec>, - candidate_bindings: &mut Vec>, - candidate_ascriptions: &mut Vec>, + extra_data: &mut PatternExtraData<'tcx>, ) { // In order to please the borrow checker, in a pattern like `x @ pat` we must lower the // bindings in `pat` before `x`. E.g. (#69971): @@ -45,17 +44,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // after any bindings in `pat`. This doesn't work for or-patterns: the current structure of // match lowering forces us to lower bindings inside or-patterns last. for mut match_pair in mem::take(match_pairs) { - self.simplify_match_pairs( - &mut match_pair.subpairs, - candidate_bindings, - candidate_ascriptions, - ); + self.simplify_match_pairs(&mut match_pair.subpairs, extra_data); if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case { if let Some(binding) = binding { - candidate_bindings.push(binding); + extra_data.bindings.push(binding); } if let Some(ascription) = ascription { - candidate_ascriptions.push(ascription); + extra_data.ascriptions.push(ascription); } // Simplifiable pattern; we replace it with its already simplified subpairs. match_pairs.append(&mut match_pair.subpairs); diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 2351f69a9141f..d0d49c13f133d 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -280,7 +280,7 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { } fn visit_candidate(&mut self, candidate: &Candidate<'_, 'tcx>) { - for binding in &candidate.bindings { + for binding in &candidate.extra_data.bindings { self.visit_binding(binding); } for match_pair in &candidate.match_pairs { @@ -289,7 +289,7 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { } fn visit_flat_pat(&mut self, flat_pat: &FlatPat<'_, 'tcx>) { - for binding in &flat_pat.bindings { + for binding in &flat_pat.extra_data.bindings { self.visit_binding(binding); } for match_pair in &flat_pat.match_pairs { From 594cf1de61d9cf6e4d095f7d7ab19f8f5999ef72 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 9 Mar 2024 15:28:26 +0100 Subject: [PATCH 11/14] review --- compiler/rustc_mir_build/src/build/matches/mod.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index cdb82f50b34aa..48c3ee1ba0ff3 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -938,6 +938,12 @@ struct PatternExtraData<'tcx> { ascriptions: Vec>, } +impl<'tcx> PatternExtraData<'tcx> { + fn is_empty(&self) -> bool { + self.bindings.is_empty() && self.ascriptions.is_empty() + } +} + /// A pattern in a form suitable for generating code. #[derive(Debug, Clone)] struct FlatPat<'pat, 'tcx> { @@ -970,7 +976,7 @@ impl<'tcx, 'pat> FlatPat<'pat, 'tcx> { #[derive(Debug)] struct Candidate<'pat, 'tcx> { - /// For the candidate to match, &ll of these must be satisfied... + /// For the candidate to match, all of these must be satisfied... // Invariant: all the `MatchPair`s are recursively simplified. // Invariant: or-patterns must be sorted at the end. match_pairs: Vec>, @@ -1518,9 +1524,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.merge_trivial_subcandidates(subcandidate, source_info); // FIXME(or_patterns; matthewjasper) Try to be more aggressive here. - can_merge &= subcandidate.subcandidates.is_empty() - && subcandidate.extra_data.bindings.is_empty() - && subcandidate.extra_data.ascriptions.is_empty(); + can_merge &= + subcandidate.subcandidates.is_empty() && subcandidate.extra_data.is_empty(); } if can_merge { From 2dd05e858edf40348ba82b90b8c2305ae0c163b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Sat, 24 Feb 2024 17:27:10 +0000 Subject: [PATCH 12/14] Error on invalid compiletest directives in Rust test files --- src/tools/compiletest/src/header.rs | 127 +++++++++++++----- .../header/test-auxillary/error_annotation.rs | 6 + .../header/test-auxillary/known_directive.rs | 4 + .../test-auxillary/known_legacy_directive.rs | 1 + .../src/header/test-auxillary/not_rs.Makefile | 1 + .../test-auxillary/unknown_directive.rs | 1 + src/tools/compiletest/src/header/tests.rs | 62 +++++++++ 7 files changed, 171 insertions(+), 31 deletions(-) create mode 100644 src/tools/compiletest/src/header/test-auxillary/error_annotation.rs create mode 100644 src/tools/compiletest/src/header/test-auxillary/known_directive.rs create mode 100644 src/tools/compiletest/src/header/test-auxillary/known_legacy_directive.rs create mode 100644 src/tools/compiletest/src/header/test-auxillary/not_rs.Makefile create mode 100644 src/tools/compiletest/src/header/test-auxillary/unknown_directive.rs diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index f15761354f7ab..c6a1d902eaeb9 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -680,7 +680,8 @@ pub fn line_directive<'line>( /// This is generated by collecting directives from ui tests and then extracting their directive /// names. This is **not** an exhaustive list of all possible directives. Instead, this is a /// best-effort approximation for diagnostics. -const DIAGNOSTICS_DIRECTIVE_NAMES: &[&str] = &[ +const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ + // tidy-alphabetical-start "assembly-output", "aux-build", "aux-crate", @@ -693,6 +694,7 @@ const DIAGNOSTICS_DIRECTIVE_NAMES: &[&str] = &[ "check-stdout", "check-test-line-numbers-match", "compile-flags", + "count", "dont-check-compiler-stderr", "dont-check-compiler-stdout", "dont-check-failure-status", @@ -716,6 +718,7 @@ const DIAGNOSTICS_DIRECTIVE_NAMES: &[&str] = &[ "ignore-compare-mode-polonius", "ignore-cross-compile", "ignore-debug", + "ignore-eabi", "ignore-emscripten", "ignore-endian-big", "ignore-freebsd", @@ -731,14 +734,30 @@ const DIAGNOSTICS_DIRECTIVE_NAMES: &[&str] = &[ "ignore-lldb", "ignore-llvm-version", "ignore-loongarch64", + "ignore-macabi", "ignore-macos", + "ignore-mode-assembly", + "ignore-mode-codegen", + "ignore-mode-codegen-units", "ignore-mode-coverage-map", "ignore-mode-coverage-run", + "ignore-mode-debuginfo", + "ignore-mode-incremental", + "ignore-mode-js-doc-test", + "ignore-mode-mir-opt", + "ignore-mode-pretty", + "ignore-mode-run-make", + "ignore-mode-run-pass-valgrind", + "ignore-mode-rustdoc", + "ignore-mode-rustdoc-json", + "ignore-mode-ui", + "ignore-mode-ui-fulldeps", "ignore-msp430", "ignore-msvc", "ignore-musl", "ignore-netbsd", "ignore-nightly", + "ignore-none", "ignore-nto", "ignore-nvptx64", "ignore-openbsd", @@ -750,18 +769,27 @@ const DIAGNOSTICS_DIRECTIVE_NAMES: &[&str] = &[ "ignore-spirv", "ignore-stable", "ignore-stage1", + "ignore-stage2", "ignore-test", + "ignore-thumb", "ignore-thumbv8m.base-none-eabi", "ignore-thumbv8m.main-none-eabi", + "ignore-unix", + "ignore-unknown", "ignore-uwp", "ignore-vxworks", + "ignore-wasi", "ignore-wasm", "ignore-wasm32", "ignore-wasm32-bare", + "ignore-wasm64", "ignore-windows", "ignore-windows-gnu", + "ignore-x32", "ignore-x86", + "ignore-x86_64", "ignore-x86_64-apple-darwin", + "ignore-x86_64-unknown-linux-gnu", "incremental", "known-bug", "llvm-cov-flags", @@ -769,9 +797,11 @@ const DIAGNOSTICS_DIRECTIVE_NAMES: &[&str] = &[ "min-gdb-version", "min-lldb-version", "min-llvm-version", + "min-system-llvm-version", "needs-asm-support", "needs-dlltool", "needs-dynamic-linking", + "needs-git-hash", "needs-llvm-components", "needs-profiler-support", "needs-relocation-model-pic", @@ -779,6 +809,7 @@ const DIAGNOSTICS_DIRECTIVE_NAMES: &[&str] = &[ "needs-rust-lldb", "needs-sanitizer-address", "needs-sanitizer-cfi", + "needs-sanitizer-dataflow", "needs-sanitizer-hwaddress", "needs-sanitizer-leak", "needs-sanitizer-memory", @@ -801,6 +832,7 @@ const DIAGNOSTICS_DIRECTIVE_NAMES: &[&str] = &[ "only-aarch64", "only-arm", "only-avr", + "only-beta", "only-bpf", "only-cdb", "only-gnu", @@ -818,6 +850,7 @@ const DIAGNOSTICS_DIRECTIVE_NAMES: &[&str] = &[ "only-riscv64", "only-sparc", "only-sparc64", + "only-stable", "only-thumb", "only-wasm32", "only-wasm32-bare", @@ -825,6 +858,7 @@ const DIAGNOSTICS_DIRECTIVE_NAMES: &[&str] = &[ "only-x86", "only-x86_64", "only-x86_64-fortanix-unknown-sgx", + "only-x86_64-pc-windows-gnu", "only-x86_64-pc-windows-msvc", "only-x86_64-unknown-linux-gnu", "pp-exact", @@ -846,6 +880,7 @@ const DIAGNOSTICS_DIRECTIVE_NAMES: &[&str] = &[ "unit-test", "unset-exec-env", "unset-rustc-env", + // tidy-alphabetical-end ]; /// The broken-down contents of a line containing a test header directive, @@ -876,6 +911,22 @@ struct HeaderLine<'ln> { directive: &'ln str, } +pub(crate) struct CheckDirectiveResult<'ln> { + is_known_directive: bool, + directive_name: &'ln str, +} + +// Returns `(is_known_directive, directive_name)`. +pub(crate) fn check_directive(directive_ln: &str) -> CheckDirectiveResult<'_> { + let directive_name = + directive_ln.split_once([':', ' ']).map(|(pre, _)| pre).unwrap_or(directive_ln); + + CheckDirectiveResult { + is_known_directive: KNOWN_DIRECTIVE_NAMES.contains(&directive_name), + directive_name: directive_ln, + } +} + fn iter_header( mode: Mode, _suite: &str, @@ -915,6 +966,7 @@ fn iter_header( let mut ln = String::new(); let mut line_number = 0; + // Match on error annotations like `//~ERROR`. static REVISION_MAGIC_COMMENT_RE: Lazy = Lazy::new(|| Regex::new("//(\\[.*\\])?~.*").unwrap()); @@ -933,9 +985,38 @@ fn iter_header( if ln.starts_with("fn") || ln.starts_with("mod") { return; - // First try to accept `ui_test` style comments - } else if let Some((header_revision, directive)) = line_directive(comment, ln) { - it(HeaderLine { line_number, original_line, header_revision, directive }); + // First try to accept `ui_test` style comments (`//@`) + } else if let Some((header_revision, non_revisioned_directive_line)) = + line_directive(comment, ln) + { + // Perform unknown directive check on Rust files. + if testfile.extension().map(|e| e == "rs").unwrap_or(false) { + let directive_ln = non_revisioned_directive_line.trim(); + + let CheckDirectiveResult { is_known_directive, .. } = check_directive(directive_ln); + + if !is_known_directive { + *poisoned = true; + + eprintln!( + "error: detected unknown compiletest test directive `{}` in {}:{}", + directive_ln, + testfile.display(), + line_number, + ); + + return; + } + } + + it(HeaderLine { + line_number, + original_line, + header_revision, + directive: non_revisioned_directive_line, + }); + // Then we try to check for legacy-style candidates, which are not the magic ~ERROR family + // error annotations. } else if !REVISION_MAGIC_COMMENT_RE.is_match(ln) { let Some((_, rest)) = line_directive("//", ln) else { continue; @@ -949,34 +1030,18 @@ fn iter_header( let rest = rest.trim_start(); - for candidate in DIAGNOSTICS_DIRECTIVE_NAMES.iter() { - if rest.starts_with(candidate) { - let Some(prefix_removed) = rest.strip_prefix(candidate) else { - // We have a comment that's *successfully* parsed as an legacy-style - // directive. We emit an error here to warn the user. - *poisoned = true; - eprintln!( - "error: detected legacy-style directives in compiletest test: {}:{}, please use `ui_test`-style directives `//@` instead:{:#?}", - testfile.display(), - line_number, - line_directive("//", ln), - ); - return; - }; + let CheckDirectiveResult { is_known_directive, directive_name } = check_directive(rest); - if prefix_removed.starts_with([' ', ':']) { - // We have a comment that's *successfully* parsed as an legacy-style - // directive. We emit an error here to warn the user. - *poisoned = true; - eprintln!( - "error: detected legacy-style directives in compiletest test: {}:{}, please use `ui_test`-style directives `//@` instead:{:#?}", - testfile.display(), - line_number, - line_directive("//", ln), - ); - return; - } - } + if is_known_directive { + *poisoned = true; + eprintln!( + "error: detected legacy-style directive {} in compiletest test: {}:{}, please use `ui_test`-style directives `//@` instead: {:#?}", + directive_name, + testfile.display(), + line_number, + line_directive("//", ln), + ); + return; } } } diff --git a/src/tools/compiletest/src/header/test-auxillary/error_annotation.rs b/src/tools/compiletest/src/header/test-auxillary/error_annotation.rs new file mode 100644 index 0000000000000..fea66a5e07b4d --- /dev/null +++ b/src/tools/compiletest/src/header/test-auxillary/error_annotation.rs @@ -0,0 +1,6 @@ +//@ check-pass + +//~ HELP +fn main() {} //~ERROR +//~^ ERROR +//~| ERROR diff --git a/src/tools/compiletest/src/header/test-auxillary/known_directive.rs b/src/tools/compiletest/src/header/test-auxillary/known_directive.rs new file mode 100644 index 0000000000000..99834b14c1ea3 --- /dev/null +++ b/src/tools/compiletest/src/header/test-auxillary/known_directive.rs @@ -0,0 +1,4 @@ +//! ignore-wasm +//@ ignore-wasm +//@ check-pass +// regular comment diff --git a/src/tools/compiletest/src/header/test-auxillary/known_legacy_directive.rs b/src/tools/compiletest/src/header/test-auxillary/known_legacy_directive.rs new file mode 100644 index 0000000000000..108ca432e1308 --- /dev/null +++ b/src/tools/compiletest/src/header/test-auxillary/known_legacy_directive.rs @@ -0,0 +1 @@ +// ignore-wasm diff --git a/src/tools/compiletest/src/header/test-auxillary/not_rs.Makefile b/src/tools/compiletest/src/header/test-auxillary/not_rs.Makefile new file mode 100644 index 0000000000000..4b565e0e6dfd0 --- /dev/null +++ b/src/tools/compiletest/src/header/test-auxillary/not_rs.Makefile @@ -0,0 +1 @@ +# ignore-owo diff --git a/src/tools/compiletest/src/header/test-auxillary/unknown_directive.rs b/src/tools/compiletest/src/header/test-auxillary/unknown_directive.rs new file mode 100644 index 0000000000000..d440603104304 --- /dev/null +++ b/src/tools/compiletest/src/header/test-auxillary/unknown_directive.rs @@ -0,0 +1 @@ +//@ needs-headpat diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 815ac3839df82..433f3e8b5559c 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -5,6 +5,8 @@ use std::str::FromStr; use crate::common::{Config, Debugger, Mode}; use crate::header::{parse_normalization_string, EarlyProps, HeadersCache}; +use super::iter_header; + fn make_test_description( config: &Config, name: test::TestName, @@ -612,3 +614,63 @@ fn threads_support() { assert_eq!(check_ignore(&config, "//@ needs-threads"), !has_threads) } } + +fn run_path(poisoned: &mut bool, path: &Path, buf: &[u8]) { + let rdr = std::io::Cursor::new(&buf); + iter_header(Mode::Ui, "ui", poisoned, path, rdr, &mut |_| {}); +} + +#[test] +fn test_unknown_directive_check() { + let mut poisoned = false; + run_path( + &mut poisoned, + Path::new("a.rs"), + include_bytes!("./test-auxillary/unknown_directive.rs"), + ); + assert!(poisoned); +} + +#[test] +fn test_known_legacy_directive_check() { + let mut poisoned = false; + run_path( + &mut poisoned, + Path::new("a.rs"), + include_bytes!("./test-auxillary/known_legacy_directive.rs"), + ); + assert!(poisoned); +} + +#[test] +fn test_known_directive_check_no_error() { + let mut poisoned = false; + run_path( + &mut poisoned, + Path::new("a.rs"), + include_bytes!("./test-auxillary/known_directive.rs"), + ); + assert!(!poisoned); +} + +#[test] +fn test_error_annotation_no_error() { + let mut poisoned = false; + run_path( + &mut poisoned, + Path::new("a.rs"), + include_bytes!("./test-auxillary/error_annotation.rs"), + ); + assert!(!poisoned); +} + +#[test] +fn test_non_rs_unknown_directive_not_checked() { + let mut poisoned = false; + run_path( + &mut poisoned, + Path::new("a.Makefile"), + include_bytes!("./test-auxillary/not_rs.Makefile"), + ); + assert!(!poisoned); +} From 046c28f086b93dda26514cc6c924fcf6db29acf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Sat, 24 Feb 2024 17:04:37 +0000 Subject: [PATCH 13/14] Fix invalid compiletest directives in tests - Fix invalid directive in `normalize-hidden-types` - Update legacy directive in `two-phase-reservation-sharing-interference` --- .../two-phase-reservation-sharing-interference.rs | 2 +- .../normalize-hidden-types.current.stderr | 12 ++++++------ .../type-alias-impl-trait/normalize-hidden-types.rs | 6 +----- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs b/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs index ac0d4f6e09975..b6bcf7b66173e 100644 --- a/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs +++ b/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs @@ -2,7 +2,7 @@ // The nll_beyond revision is disabled due to missing support from two-phase beyond autorefs //@[nll_beyond]compile-flags: -Z two-phase-beyond-autoref -//[nll_beyond]should-fail +//@[nll_beyond]should-fail // This is a corner case that the current implementation is (probably) // treating more conservatively than is necessary. But it also does diff --git a/tests/ui/type-alias-impl-trait/normalize-hidden-types.current.stderr b/tests/ui/type-alias-impl-trait/normalize-hidden-types.current.stderr index dd2737c706d6b..d9d5dd4ece3b1 100644 --- a/tests/ui/type-alias-impl-trait/normalize-hidden-types.current.stderr +++ b/tests/ui/type-alias-impl-trait/normalize-hidden-types.current.stderr @@ -5,25 +5,25 @@ LL | fn define() -> Opaque { | ^^^^^^ expected `*const (dyn FnOnce(()) + 'static)`, got `*const dyn for<'a> FnOnce(::Gat<'a>)` | note: previous use here - --> $DIR/normalize-hidden-types.rs:27:9 + --> $DIR/normalize-hidden-types.rs:26:9 | LL | dyn_hoops::<_>(0) | ^^^^^^^^^^^^^^^^^ error: concrete type differs from previous defining opaque type use - --> $DIR/normalize-hidden-types.rs:34:22 + --> $DIR/normalize-hidden-types.rs:33:22 | LL | fn define_1() -> Opaque { dyn_hoops::<_>(0) } | ^^^^^^ expected `*const (dyn FnOnce(()) + 'static)`, got `*const dyn for<'a> FnOnce(::Gat<'a>)` | note: previous use here - --> $DIR/normalize-hidden-types.rs:34:31 + --> $DIR/normalize-hidden-types.rs:33:31 | LL | fn define_1() -> Opaque { dyn_hoops::<_>(0) } | ^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/normalize-hidden-types.rs:44:25 + --> $DIR/normalize-hidden-types.rs:42:25 | LL | type Opaque = impl Sized; | ---------- the expected opaque type @@ -39,13 +39,13 @@ LL | let _: Opaque = dyn_hoops::(0); = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error: concrete type differs from previous defining opaque type use - --> $DIR/normalize-hidden-types.rs:54:25 + --> $DIR/normalize-hidden-types.rs:51:25 | LL | let _: Opaque = dyn_hoops::<_>(0); | ^^^^^^^^^^^^^^^^^ expected `*const (dyn FnOnce(()) + 'static)`, got `*const dyn for<'a> FnOnce(::Gat<'a>)` | note: previous use here - --> $DIR/normalize-hidden-types.rs:56:9 + --> $DIR/normalize-hidden-types.rs:52:9 | LL | None | ^^^^ diff --git a/tests/ui/type-alias-impl-trait/normalize-hidden-types.rs b/tests/ui/type-alias-impl-trait/normalize-hidden-types.rs index e78e6cf7690e7..d6800694e5133 100644 --- a/tests/ui/type-alias-impl-trait/normalize-hidden-types.rs +++ b/tests/ui/type-alias-impl-trait/normalize-hidden-types.rs @@ -3,7 +3,7 @@ //@ revisions: current next //@ [next] compile-flags: -Znext-solver //@ [next] check-pass -//@ [current]: known-bug: #112691 +//@ [current] known-bug: #112691 #![feature(type_alias_impl_trait)] @@ -23,7 +23,6 @@ mod typeof_1 { use super::*; type Opaque = impl Sized; fn define() -> Opaque { - //[current]~^ ERROR concrete type differs dyn_hoops::<_>(0) } } @@ -32,7 +31,6 @@ mod typeof_2 { use super::*; type Opaque = impl Sized; fn define_1() -> Opaque { dyn_hoops::<_>(0) } - //[current]~^ ERROR concrete type differs fn define_2() -> Opaque { dyn_hoops::(0) } } @@ -42,7 +40,6 @@ mod typeck { fn define() -> Option { let _: Opaque = dyn_hoops::<_>(0); let _: Opaque = dyn_hoops::(0); - //[current]~^ ERROR mismatched types None } } @@ -52,7 +49,6 @@ mod borrowck { type Opaque = impl Sized; fn define() -> Option { let _: Opaque = dyn_hoops::<_>(0); - //[current]~^ ERROR concrete type differs None } } From ff1459a37022f002d28d1c116d8a073f5b9a6720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Sat, 9 Mar 2024 18:24:45 +0000 Subject: [PATCH 14/14] Add test to check unused_lifetimes don't duplicate "parameter is never used" error --- tests/ui/single-use-lifetime/dedup.rs | 9 +++++++++ tests/ui/single-use-lifetime/dedup.stderr | 11 +++++++++++ 2 files changed, 20 insertions(+) create mode 100644 tests/ui/single-use-lifetime/dedup.rs create mode 100644 tests/ui/single-use-lifetime/dedup.stderr diff --git a/tests/ui/single-use-lifetime/dedup.rs b/tests/ui/single-use-lifetime/dedup.rs new file mode 100644 index 0000000000000..16b39609a6d34 --- /dev/null +++ b/tests/ui/single-use-lifetime/dedup.rs @@ -0,0 +1,9 @@ +// Check that `unused_lifetimes` lint doesn't duplicate a "parameter is never used" error. +// Fixed in . +// Issue: . + +#![warn(unused_lifetimes)] +struct Foo<'a>; +//~^ ERROR parameter `'a` is never used + +fn main() {} diff --git a/tests/ui/single-use-lifetime/dedup.stderr b/tests/ui/single-use-lifetime/dedup.stderr new file mode 100644 index 0000000000000..6d02cb3c7148e --- /dev/null +++ b/tests/ui/single-use-lifetime/dedup.stderr @@ -0,0 +1,11 @@ +error[E0392]: lifetime parameter `'a` is never used + --> $DIR/dedup.rs:6:12 + | +LL | struct Foo<'a>; + | ^^ unused lifetime parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0392`.