Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 7 pull requests #116772

Merged
merged 14 commits into from
Oct 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ b39a1d6f1a30ba29f25d7141038b9a5bf0126e36
f97fddab91fbf290ea5b691fe355d6f915220b6e
# format let-else
cc907f80b95c6ec530c5ee1b05b044a468f07eca
# format let-chains
b2d2184edea578109a48ec3d8decbee5948e8f35
8 changes: 8 additions & 0 deletions compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,14 @@ impl<'tcx> ConstToPat<'tcx> {
// We errored. Signal that in the pattern, so that follow up errors can be silenced.
let kind = PatKind::Error(e);
return Box::new(Pat { span: self.span, ty: cv.ty(), kind });
} else if let ty::Adt(..) = cv.ty().kind() && matches!(cv, mir::Const::Val(..)) {
// This branch is only entered when the current `cv` is `mir::Const::Val`.
// This is because `mir::Const::ty` has already been handled by `Self::recur`
// and the invalid types may be ignored.
let err = TypeNotStructural { span: self.span, non_sm_ty };
let e = self.tcx().sess.emit_err(err);
let kind = PatKind::Error(e);
return Box::new(Pat { span: self.span, ty: cv.ty(), kind });
} else if !self.saw_const_match_lint.get() {
if let Some(mir_structural_match_violation) = mir_structural_match_violation {
match non_sm_ty.kind() {
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/ptr/const_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -842,7 +842,7 @@ impl<T: ?Sized> *const T {
where
T: Sized,
{
match intrinsics::ptr_guaranteed_cmp(self as _, other as _) {
match intrinsics::ptr_guaranteed_cmp(self, other) {
2 => None,
other => Some(other == 1),
}
Expand Down
158 changes: 158 additions & 0 deletions library/std/src/sys/uefi/args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
use r_efi::protocols::loaded_image;

use crate::env::current_exe;
use crate::ffi::OsString;
use crate::fmt;
use crate::iter::Iterator;
use crate::mem::size_of;
use crate::sys::uefi::helpers;
use crate::vec;

pub struct Args {
parsed_args_list: vec::IntoIter<OsString>,
}

pub fn args() -> Args {
let lazy_current_exe = || Vec::from([current_exe().map(Into::into).unwrap_or_default()]);

// Each loaded image has an image handle that supports `EFI_LOADED_IMAGE_PROTOCOL`. Thus, this
// will never fail.
let protocol =
helpers::image_handle_protocol::<loaded_image::Protocol>(loaded_image::PROTOCOL_GUID)
.unwrap();

let lp_size = unsafe { (*protocol.as_ptr()).load_options_size } as usize;
// Break if we are sure that it cannot be UTF-16
if lp_size < size_of::<u16>() || lp_size % size_of::<u16>() != 0 {
return Args { parsed_args_list: lazy_current_exe().into_iter() };
}
let lp_size = lp_size / size_of::<u16>();

let lp_cmd_line = unsafe { (*protocol.as_ptr()).load_options as *const u16 };
if !lp_cmd_line.is_aligned() {
return Args { parsed_args_list: lazy_current_exe().into_iter() };
}
let lp_cmd_line = unsafe { crate::slice::from_raw_parts(lp_cmd_line, lp_size) };

Args {
parsed_args_list: parse_lp_cmd_line(lp_cmd_line)
.unwrap_or_else(lazy_current_exe)
.into_iter(),
}
}

impl fmt::Debug for Args {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.parsed_args_list.as_slice().fmt(f)
}
}

impl Iterator for Args {
type Item = OsString;

fn next(&mut self) -> Option<OsString> {
self.parsed_args_list.next()
}

fn size_hint(&self) -> (usize, Option<usize>) {
self.parsed_args_list.size_hint()
}
}

impl ExactSizeIterator for Args {
fn len(&self) -> usize {
self.parsed_args_list.len()
}
}

impl DoubleEndedIterator for Args {
fn next_back(&mut self) -> Option<OsString> {
self.parsed_args_list.next_back()
}
}

/// Implements the UEFI command-line argument parsing algorithm.
///
/// This implementation is based on what is defined in Section 3.4 of
/// [UEFI Shell Specification](https://uefi.org/sites/default/files/resources/UEFI_Shell_Spec_2_0.pdf)
///
/// Return None in the following cases:
/// - Invalid UTF-16 (unpaired surrogate)
/// - Empty/improper arguments
fn parse_lp_cmd_line(code_units: &[u16]) -> Option<Vec<OsString>> {
const QUOTE: char = '"';
const SPACE: char = ' ';
const CARET: char = '^';
const NULL: char = '\0';

let mut ret_val = Vec::new();
let mut code_units_iter = char::decode_utf16(code_units.iter().cloned()).peekable();

// The executable name at the beginning is special.
let mut in_quotes = false;
let mut cur = String::new();
while let Some(w) = code_units_iter.next() {
let w = w.ok()?;
match w {
// break on NULL
NULL => break,
// A quote mark always toggles `in_quotes` no matter what because
// there are no escape characters when parsing the executable name.
QUOTE => in_quotes = !in_quotes,
// If not `in_quotes` then whitespace ends argv[0].
SPACE if !in_quotes => break,
// In all other cases the code unit is taken literally.
_ => cur.push(w),
}
}

// If exe name is missing, the cli args are invalid
if cur.is_empty() {
return None;
}

ret_val.push(OsString::from(cur));
// Skip whitespace.
while code_units_iter.next_if_eq(&Ok(SPACE)).is_some() {}

// Parse the arguments according to these rules:
// * All code units are taken literally except space, quote and caret.
// * When not `in_quotes`, space separate arguments. Consecutive spaces are
// treated as a single separator.
// * A space `in_quotes` is taken literally.
// * A quote toggles `in_quotes` mode unless it's escaped. An escaped quote is taken literally.
// * A quote can be escaped if preceded by caret.
// * A caret can be escaped if preceded by caret.
let mut cur = String::new();
let mut in_quotes = false;
while let Some(w) = code_units_iter.next() {
let w = w.ok()?;
match w {
// break on NULL
NULL => break,
// If not `in_quotes`, a space or tab ends the argument.
SPACE if !in_quotes => {
ret_val.push(OsString::from(&cur[..]));
cur.truncate(0);

// Skip whitespace.
while code_units_iter.next_if_eq(&Ok(SPACE)).is_some() {}
}
// Caret can escape quotes or carets
CARET if in_quotes => {
if let Some(x) = code_units_iter.next() {
cur.push(x.ok()?);
}
}
// If quote then flip `in_quotes`
QUOTE => in_quotes = !in_quotes,
// Everything else is always taken literally.
_ => cur.push(w),
}
}
// Push the final argument, if any.
if !cur.is_empty() || in_quotes {
ret_val.push(OsString::from(cur));
}
Some(ret_val)
}
7 changes: 7 additions & 0 deletions library/std/src/sys/uefi/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,10 @@ pub(crate) unsafe fn close_event(evt: NonNull<crate::ffi::c_void>) -> io::Result

if r.is_error() { Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) }
}

/// Get the Protocol for current system handle.
/// Note: Some protocols need to be manually freed. It is the callers responsibility to do so.
pub(crate) fn image_handle_protocol<T>(protocol_guid: Guid) -> Option<NonNull<T>> {
let system_handle = uefi::env::try_image_handle()?;
open_protocol(system_handle, protocol_guid).ok()
}
1 change: 0 additions & 1 deletion library/std/src/sys/uefi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
//! [`OsString`]: crate::ffi::OsString

pub mod alloc;
#[path = "../unsupported/args.rs"]
pub mod args;
#[path = "../unix/cmath.rs"]
pub mod cmath;
Expand Down
6 changes: 3 additions & 3 deletions library/std/src/thread/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ use crate::fmt;
/// within a thread, and values that implement [`Drop`] get destructed when a
/// thread exits. Some caveats apply, which are explained below.
///
/// A `LocalKey`'s initializer cannot recursively depend on itself, and using
/// a `LocalKey` in this way will cause the initializer to infinitely recurse
/// on the first call to `with`.
/// A `LocalKey`'s initializer cannot recursively depend on itself. Using a
/// `LocalKey` in this way may cause panics, aborts or infinite recursion on
/// the first call to `with`.
///
/// # Examples
///
Expand Down
2 changes: 2 additions & 0 deletions src/doc/rustc/src/platform-support/unknown-uefi.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,8 @@ cargo build --target x86_64-unknown-uefi -Zbuild-std=std,panic_abort
#### stdio
- Uses `Simple Text Input Protocol` and `Simple Text Output Protocol`.
- Note: UEFI uses CRLF for new line. This means Enter key is registered as CR instead of LF.
#### args
- Uses `EFI_LOADED_IMAGE_PROTOCOL->LoadOptions`

## Example: Hello World With std
The following code features a valid UEFI application, including `stdio` and `alloc` (`OsString` and `Vec`):
Expand Down
7 changes: 7 additions & 0 deletions tests/ui/pattern/issue-115599.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const CONST_STRING: String = String::new();

fn main() {
let empty_str = String::from("");
if let CONST_STRING = empty_str {}
//~^ ERROR to use a constant of type `Vec<u8>` in a pattern, `Vec<u8>` must be annotated with `#[derive(PartialEq, Eq)]`
}
11 changes: 11 additions & 0 deletions tests/ui/pattern/issue-115599.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error: to use a constant of type `Vec<u8>` in a pattern, `Vec<u8>` must be annotated with `#[derive(PartialEq, Eq)]`
--> $DIR/issue-115599.rs:5:12
|
LL | if let CONST_STRING = empty_str {}
| ^^^^^^^^^^^^
|
= note: the traits must be derived, manual `impl`s are not sufficient
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details

error: aborting due to previous error

2 changes: 1 addition & 1 deletion triagebot.toml
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,7 @@ style-team = [
"/compiler/rustc_traits" = ["compiler", "types"]
"/compiler/rustc_type_ir" = ["compiler", "types"]
"/library/alloc" = ["libs"]
"/library/core" = ["libs", "@scottmcm"]
"/library/core" = ["libs"]
"/library/panic_abort" = ["libs"]
"/library/panic_unwind" = ["libs"]
"/library/proc_macro" = ["@petrochenkov"]
Expand Down
9 changes: 6 additions & 3 deletions x
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ set -eu
sh -n "$0"

realpath() {
if [ -d "$1" ]; then
CDPATH='' command cd "$1" && pwd -P
local path="$1"
if [ -L "$path" ]; then
readlink -f "$path"
elif [ -d "$path" ]; then
(cd -P "$path" && pwd)
else
echo "$(realpath "$(dirname "$1")")/$(basename "$1")"
echo "$(realpath "$(dirname "$path")")/$(basename "$path")"
fi
}

Expand Down
Loading