Auto merge of #150469 - JonathanBrouwer:rollup-6ujkn6v, r=JonathanBrouwer
Rollup of 8 pull requests Successful merges: - rust-lang/rust#148321 (parser/lexer: bump to Unicode 17, use faster unicode-ident) - rust-lang/rust#149540 (std: sys: fs: uefi: Implement readdir) - rust-lang/rust#149582 (Implement `Duration::div_duration_{floor,ceil}`) - rust-lang/rust#149663 (Optimized implementation for uN::{gather,scatter}_bits) - rust-lang/rust#149667 (Fix ICE by rejecting const blocks in patterns during AST lowering (closes rust-lang/rust#148138)) - rust-lang/rust#149947 (add several older crashtests) - rust-lang/rust#150011 (Add more `unbounded_sh[lr]` examples) - rust-lang/rust#150411 (refactor `destructure_const`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
7fefa09b90
50 changed files with 901 additions and 340 deletions
14
Cargo.lock
14
Cargo.lock
|
|
@ -4144,8 +4144,8 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"expect-test",
|
||||
"memchr",
|
||||
"unicode-ident",
|
||||
"unicode-properties",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5981,24 +5981,24 @@ checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
|
|||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.24"
|
||||
version = "0.1.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
|
||||
checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-properties"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0"
|
||||
checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-script"
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ ast_lowering_abi_specified_multiple_times =
|
|||
ast_lowering_arbitrary_expression_in_pattern =
|
||||
arbitrary expressions aren't allowed in patterns
|
||||
.pattern_from_macro_note = the `expr` fragment specifier forces the metavariable's content to be an expression
|
||||
.const_block_in_pattern_help = use a named `const`-item or an `if`-guard (`x if x == const {"{ ... }"}`) instead
|
||||
|
||||
ast_lowering_argument = argument
|
||||
|
||||
|
|
|
|||
|
|
@ -357,6 +357,8 @@ pub(crate) struct ArbitraryExpressionInPattern {
|
|||
pub span: Span,
|
||||
#[note(ast_lowering_pattern_from_macro_note)]
|
||||
pub pattern_from_macro_note: bool,
|
||||
#[help(ast_lowering_const_block_in_pattern_help)]
|
||||
pub const_block_in_pattern_help: bool,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -399,7 +399,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
ExprKind::Lit(lit) => {
|
||||
hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: false }
|
||||
}
|
||||
ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c)),
|
||||
ExprKind::IncludedBytes(byte_sym) => hir::PatExprKind::Lit {
|
||||
lit: respan(span, LitKind::ByteStr(*byte_sym, StrStyle::Cooked)),
|
||||
negated: false,
|
||||
|
|
@ -419,10 +418,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: true }
|
||||
}
|
||||
_ => {
|
||||
let is_const_block = matches!(expr.kind, ExprKind::ConstBlock(_));
|
||||
let pattern_from_macro = expr.is_approximately_pattern();
|
||||
let guar = self.dcx().emit_err(ArbitraryExpressionInPattern {
|
||||
span,
|
||||
pattern_from_macro_note: pattern_from_macro,
|
||||
const_block_in_pattern_help: is_const_block,
|
||||
});
|
||||
err(guar)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1944,7 +1944,6 @@ pub enum PatExprKind<'hir> {
|
|||
// once instead of matching on unop neg expressions everywhere.
|
||||
negated: bool,
|
||||
},
|
||||
ConstBlock(ConstBlock),
|
||||
/// A path pattern for a unit struct/variant or a (maybe-associated) constant.
|
||||
Path(QPath<'hir>),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -792,7 +792,6 @@ pub fn walk_pat_expr<'v, V: Visitor<'v>>(visitor: &mut V, expr: &'v PatExpr<'v>)
|
|||
try_visit!(visitor.visit_id(*hir_id));
|
||||
match kind {
|
||||
PatExprKind::Lit { lit, negated } => visitor.visit_lit(*hir_id, *lit, *negated),
|
||||
PatExprKind::ConstBlock(c) => visitor.visit_inline_const(c),
|
||||
PatExprKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, *span),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1880,7 +1880,6 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.print_literal(lit);
|
||||
}
|
||||
hir::PatExprKind::ConstBlock(c) => self.print_inline_const(c),
|
||||
hir::PatExprKind::Path(qpath) => self.print_qpath(qpath, true),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -925,9 +925,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
ty
|
||||
}
|
||||
rustc_hir::PatExprKind::ConstBlock(c) => {
|
||||
self.check_expr_const_block(c, Expectation::NoExpectation)
|
||||
}
|
||||
rustc_hir::PatExprKind::Path(qpath) => {
|
||||
let (res, opt_ty, segments) =
|
||||
self.resolve_ty_and_res_fully_qualified_call(qpath, lt.hir_id, lt.span);
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ Rust lexer used by rustc. No stability guarantees are provided.
|
|||
# Note that this crate purposefully does not depend on other rustc crates
|
||||
[dependencies]
|
||||
memchr = "2.7.6"
|
||||
unicode-properties = { version = "0.1.0", default-features = false, features = ["emoji"] }
|
||||
unicode-xid = "0.2.0"
|
||||
unicode-properties = { version = "0.1.4", default-features = false, features = ["emoji"] }
|
||||
unicode-ident = "1.0.22"
|
||||
|
||||
[dev-dependencies]
|
||||
expect-test = "1.4.0"
|
||||
|
|
|
|||
|
|
@ -34,8 +34,25 @@ use LiteralKind::*;
|
|||
use TokenKind::*;
|
||||
use cursor::EOF_CHAR;
|
||||
pub use cursor::{Cursor, FrontmatterAllowed};
|
||||
pub use unicode_ident::UNICODE_VERSION;
|
||||
use unicode_properties::UnicodeEmoji;
|
||||
pub use unicode_xid::UNICODE_VERSION as UNICODE_XID_VERSION;
|
||||
|
||||
// Make sure that the Unicode version of the dependencies is the same.
|
||||
const _: () = {
|
||||
let properties = unicode_properties::UNICODE_VERSION;
|
||||
let ident = unicode_ident::UNICODE_VERSION;
|
||||
|
||||
if properties.0 != ident.0 as u64
|
||||
|| properties.1 != ident.1 as u64
|
||||
|| properties.2 != ident.2 as u64
|
||||
{
|
||||
panic!(
|
||||
"unicode-properties and unicode-ident must use the same Unicode version, \
|
||||
`unicode_properties::UNICODE_VERSION` and `unicode_ident::UNICODE_VERSION` are \
|
||||
different."
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/// Parsed token.
|
||||
/// It doesn't contain information about data that has been parsed,
|
||||
|
|
@ -370,14 +387,14 @@ pub fn is_horizontal_whitespace(c: char) -> bool {
|
|||
/// a formal definition of valid identifier name.
|
||||
pub fn is_id_start(c: char) -> bool {
|
||||
// This is XID_Start OR '_' (which formally is not a XID_Start).
|
||||
c == '_' || unicode_xid::UnicodeXID::is_xid_start(c)
|
||||
c == '_' || unicode_ident::is_xid_start(c)
|
||||
}
|
||||
|
||||
/// True if `c` is valid as a non-first character of an identifier.
|
||||
/// See [Rust language reference](https://doc.rust-lang.org/reference/identifiers.html) for
|
||||
/// a formal definition of valid identifier name.
|
||||
pub fn is_id_continue(c: char) -> bool {
|
||||
unicode_xid::UnicodeXID::is_xid_continue(c)
|
||||
unicode_ident::is_xid_continue(c)
|
||||
}
|
||||
|
||||
/// The passed string is lexically an identifier.
|
||||
|
|
|
|||
|
|
@ -1896,7 +1896,8 @@ fn pretty_print_const_value_tcx<'tcx>(
|
|||
// Aggregates, printed as array/tuple/struct/variant construction syntax.
|
||||
//
|
||||
// NB: the `has_non_region_param` check ensures that we can use
|
||||
// the `destructure_const` query with an empty `ty::ParamEnv` without
|
||||
// the `try_destructure_mir_constant_for_user_output ` query with
|
||||
// an empty `TypingEnv::fully_monomorphized` without
|
||||
// introducing ICEs (e.g. via `layout_of`) from missing bounds.
|
||||
// E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized`
|
||||
// to be able to destructure the tuple into `(0u8, *mut T)`
|
||||
|
|
|
|||
|
|
@ -402,7 +402,7 @@ tcx_lifetime! {
|
|||
rustc_middle::ty::ClauseKind,
|
||||
rustc_middle::ty::ClosureTypeInfo,
|
||||
rustc_middle::ty::Const,
|
||||
rustc_middle::ty::DestructuredConst,
|
||||
rustc_middle::ty::DestructuredAdtConst,
|
||||
rustc_middle::ty::ExistentialTraitRef,
|
||||
rustc_middle::ty::FnSig,
|
||||
rustc_middle::ty::GenericArg,
|
||||
|
|
|
|||
|
|
@ -1408,12 +1408,6 @@ rustc_queries! {
|
|||
desc { "converting type-level constant value to MIR constant value"}
|
||||
}
|
||||
|
||||
/// Destructures array, ADT or tuple constants into the constants
|
||||
/// of their fields.
|
||||
query destructure_const(key: ty::Const<'tcx>) -> ty::DestructuredConst<'tcx> {
|
||||
desc { "destructuring type level constant"}
|
||||
}
|
||||
|
||||
// FIXME get rid of this with valtrees
|
||||
query lit_to_const(
|
||||
key: LitToConstInput<'tcx>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
|
||||
use rustc_abi::{FIRST_VARIANT, VariantIdx};
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_macros::{
|
||||
|
|
@ -189,6 +190,26 @@ impl<'tcx> Value<'tcx> {
|
|||
ValTreeKind::Leaf(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Destructures array, ADT or tuple constants into the constants
|
||||
/// of their fields.
|
||||
pub fn destructure_adt_const(&self) -> ty::DestructuredAdtConst<'tcx> {
|
||||
let fields = self.to_branch();
|
||||
|
||||
let (variant, fields) = match self.ty.kind() {
|
||||
ty::Adt(def, _) if def.variants().is_empty() => {
|
||||
bug!("unreachable")
|
||||
}
|
||||
ty::Adt(def, _) if def.is_enum() => {
|
||||
let (head, rest) = fields.split_first().unwrap();
|
||||
(VariantIdx::from_u32(head.to_leaf().to_u32()), rest)
|
||||
}
|
||||
ty::Adt(_, _) => (FIRST_VARIANT, fields),
|
||||
_ => bug!("destructure_adt_const called on non-ADT type: {:?}", self.ty),
|
||||
};
|
||||
|
||||
ty::DestructuredAdtConst { variant, fields }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::ValueConst<TyCtxt<'tcx>> for Value<'tcx> {
|
||||
|
|
|
|||
|
|
@ -2331,8 +2331,8 @@ impl<'tcx> fmt::Debug for SymbolName<'tcx> {
|
|||
|
||||
/// The constituent parts of a type level constant of kind ADT or array.
|
||||
#[derive(Copy, Clone, Debug, HashStable)]
|
||||
pub struct DestructuredConst<'tcx> {
|
||||
pub variant: Option<VariantIdx>,
|
||||
pub struct DestructuredAdtConst<'tcx> {
|
||||
pub variant: VariantIdx,
|
||||
pub fields: &'tcx [ty::Const<'tcx>],
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1919,66 +1919,65 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||
self.pretty_print_byte_str(bytes)?;
|
||||
return Ok(());
|
||||
}
|
||||
// Aggregates, printed as array/tuple/struct/variant construction syntax.
|
||||
(ty::ValTreeKind::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => {
|
||||
let contents = self.tcx().destructure_const(ty::Const::new_value(
|
||||
self.tcx(),
|
||||
cv.valtree,
|
||||
cv.ty,
|
||||
));
|
||||
let fields = contents.fields.iter().copied();
|
||||
(ty::ValTreeKind::Branch(fields), ty::Array(..) | ty::Tuple(..)) => {
|
||||
let fields_iter = fields.iter().copied();
|
||||
|
||||
match *cv.ty.kind() {
|
||||
ty::Array(..) => {
|
||||
write!(self, "[")?;
|
||||
self.comma_sep(fields)?;
|
||||
self.comma_sep(fields_iter)?;
|
||||
write!(self, "]")?;
|
||||
}
|
||||
ty::Tuple(..) => {
|
||||
write!(self, "(")?;
|
||||
self.comma_sep(fields)?;
|
||||
if contents.fields.len() == 1 {
|
||||
self.comma_sep(fields_iter)?;
|
||||
if fields.len() == 1 {
|
||||
write!(self, ",")?;
|
||||
}
|
||||
write!(self, ")")?;
|
||||
}
|
||||
ty::Adt(def, _) if def.variants().is_empty() => {
|
||||
self.typed_value(
|
||||
|this| {
|
||||
write!(this, "unreachable()")?;
|
||||
Ok(())
|
||||
},
|
||||
|this| this.print_type(cv.ty),
|
||||
": ",
|
||||
)?;
|
||||
}
|
||||
ty::Adt(def, args) => {
|
||||
let variant_idx =
|
||||
contents.variant.expect("destructed const of adt without variant idx");
|
||||
let variant_def = &def.variant(variant_idx);
|
||||
self.pretty_print_value_path(variant_def.def_id, args)?;
|
||||
match variant_def.ctor_kind() {
|
||||
Some(CtorKind::Const) => {}
|
||||
Some(CtorKind::Fn) => {
|
||||
write!(self, "(")?;
|
||||
self.comma_sep(fields)?;
|
||||
write!(self, ")")?;
|
||||
}
|
||||
None => {
|
||||
write!(self, " {{ ")?;
|
||||
let mut first = true;
|
||||
for (field_def, field) in iter::zip(&variant_def.fields, fields) {
|
||||
if !first {
|
||||
write!(self, ", ")?;
|
||||
}
|
||||
write!(self, "{}: ", field_def.name)?;
|
||||
field.print(self)?;
|
||||
first = false;
|
||||
_ => unreachable!(),
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
(ty::ValTreeKind::Branch(_), ty::Adt(def, args)) => {
|
||||
let contents = cv.destructure_adt_const();
|
||||
let fields = contents.fields.iter().copied();
|
||||
|
||||
if def.variants().is_empty() {
|
||||
self.typed_value(
|
||||
|this| {
|
||||
write!(this, "unreachable()")?;
|
||||
Ok(())
|
||||
},
|
||||
|this| this.print_type(cv.ty),
|
||||
": ",
|
||||
)?;
|
||||
} else {
|
||||
let variant_idx = contents.variant;
|
||||
let variant_def = &def.variant(variant_idx);
|
||||
self.pretty_print_value_path(variant_def.def_id, args)?;
|
||||
match variant_def.ctor_kind() {
|
||||
Some(CtorKind::Const) => {}
|
||||
Some(CtorKind::Fn) => {
|
||||
write!(self, "(")?;
|
||||
self.comma_sep(fields)?;
|
||||
write!(self, ")")?;
|
||||
}
|
||||
None => {
|
||||
write!(self, " {{ ")?;
|
||||
let mut first = true;
|
||||
for (field_def, field) in iter::zip(&variant_def.fields, fields) {
|
||||
if !first {
|
||||
write!(self, ", ")?;
|
||||
}
|
||||
write!(self, " }}")?;
|
||||
write!(self, "{}: ", field_def.name)?;
|
||||
field.print(self)?;
|
||||
first = false;
|
||||
}
|
||||
write!(self, " }}")?;
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,14 +13,13 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
|
|||
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
|
||||
use rustc_hir::{self as hir, LangItem, RangeEnd};
|
||||
use rustc_index::Idx;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::mir::interpret::LitToConstInput;
|
||||
use rustc_middle::thir::{
|
||||
Ascription, DerefPatBorrowMode, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
|
||||
};
|
||||
use rustc_middle::ty::adjustment::{PatAdjust, PatAdjustment};
|
||||
use rustc_middle::ty::layout::IntegerExt;
|
||||
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypingMode};
|
||||
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
|
|
@ -613,54 +612,8 @@ impl<'tcx> PatCtxt<'tcx> {
|
|||
pattern
|
||||
}
|
||||
|
||||
/// Lowers an inline const block (e.g. `const { 1 + 1 }`) to a pattern.
|
||||
fn lower_inline_const(
|
||||
&mut self,
|
||||
block: &'tcx hir::ConstBlock,
|
||||
id: hir::HirId,
|
||||
span: Span,
|
||||
) -> PatKind<'tcx> {
|
||||
let tcx = self.tcx;
|
||||
let def_id = block.def_id;
|
||||
let ty = tcx.typeck(def_id).node_type(block.hir_id);
|
||||
|
||||
let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
|
||||
let parent_args = ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id);
|
||||
let args = ty::InlineConstArgs::new(tcx, ty::InlineConstArgsParts { parent_args, ty }).args;
|
||||
|
||||
let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args };
|
||||
let c = ty::Const::new_unevaluated(self.tcx, ct);
|
||||
let pattern = self.const_to_pat(c, ty, id, span);
|
||||
|
||||
// Apply a type ascription for the inline constant.
|
||||
let annotation = {
|
||||
let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
|
||||
let args = ty::InlineConstArgs::new(
|
||||
tcx,
|
||||
ty::InlineConstArgsParts { parent_args, ty: infcx.next_ty_var(span) },
|
||||
)
|
||||
.args;
|
||||
infcx.canonicalize_user_type_annotation(ty::UserType::new(ty::UserTypeKind::TypeOf(
|
||||
def_id.to_def_id(),
|
||||
ty::UserArgs { args, user_self_ty: None },
|
||||
)))
|
||||
};
|
||||
let annotation =
|
||||
CanonicalUserTypeAnnotation { user_ty: Box::new(annotation), span, inferred_ty: ty };
|
||||
PatKind::AscribeUserType {
|
||||
subpattern: pattern,
|
||||
ascription: Ascription {
|
||||
annotation,
|
||||
// Note that we use `Contravariant` here. See the `variance` field documentation
|
||||
// for details.
|
||||
variance: ty::Contravariant,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Lowers the kinds of "expression" that can appear in a HIR pattern:
|
||||
/// - Paths (e.g. `FOO`, `foo::BAR`, `Option::None`)
|
||||
/// - Inline const blocks (e.g. `const { 1 + 1 }`)
|
||||
/// - Literals, possibly negated (e.g. `-128u8`, `"hello"`)
|
||||
fn lower_pat_expr(
|
||||
&mut self,
|
||||
|
|
@ -669,9 +622,6 @@ impl<'tcx> PatCtxt<'tcx> {
|
|||
) -> PatKind<'tcx> {
|
||||
match &expr.kind {
|
||||
hir::PatExprKind::Path(qpath) => self.lower_path(qpath, expr.hir_id, expr.span).kind,
|
||||
hir::PatExprKind::ConstBlock(anon_const) => {
|
||||
self.lower_inline_const(anon_const, expr.hir_id, expr.span)
|
||||
}
|
||||
hir::PatExprKind::Lit { lit, negated } => {
|
||||
// We handle byte string literal patterns by using the pattern's type instead of the
|
||||
// literal's type in `const_to_pat`: if the literal `b"..."` matches on a slice reference,
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ rustc_session = { path = "../rustc_session" }
|
|||
rustc_span = { path = "../rustc_span" }
|
||||
thin-vec = "0.2.12"
|
||||
tracing = "0.1"
|
||||
unicode-normalization = "0.1.11"
|
||||
unicode-width = "0.2.0"
|
||||
unicode-normalization = "0.1.25"
|
||||
unicode-width = "0.2.2"
|
||||
# tidy-alphabetical-end
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
|||
|
|
@ -22,10 +22,10 @@ use rustc_ast::token;
|
|||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::{Diag, EmissionGuarantee, FatalError, PResult, pluralize};
|
||||
pub use rustc_lexer::UNICODE_VERSION;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{FileName, SourceFile, Span};
|
||||
pub use unicode_normalization::UNICODE_VERSION as UNICODE_NORMALIZATION_VERSION;
|
||||
|
||||
pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments");
|
||||
|
||||
|
|
@ -39,6 +39,44 @@ pub mod lexer;
|
|||
|
||||
mod errors;
|
||||
|
||||
// Make sure that the Unicode version of the dependencies is the same.
|
||||
const _: () = {
|
||||
let rustc_lexer = rustc_lexer::UNICODE_VERSION;
|
||||
let rustc_span = rustc_span::UNICODE_VERSION;
|
||||
let normalization = unicode_normalization::UNICODE_VERSION;
|
||||
let width = unicode_width::UNICODE_VERSION;
|
||||
|
||||
if rustc_lexer.0 != rustc_span.0
|
||||
|| rustc_lexer.1 != rustc_span.1
|
||||
|| rustc_lexer.2 != rustc_span.2
|
||||
{
|
||||
panic!(
|
||||
"rustc_lexer and rustc_span must use the same Unicode version, \
|
||||
`rustc_lexer::UNICODE_VERSION` and `rustc_span::UNICODE_VERSION` are \
|
||||
different."
|
||||
);
|
||||
}
|
||||
|
||||
if rustc_lexer.0 != normalization.0
|
||||
|| rustc_lexer.1 != normalization.1
|
||||
|| rustc_lexer.2 != normalization.2
|
||||
{
|
||||
panic!(
|
||||
"rustc_lexer and unicode-normalization must use the same Unicode version, \
|
||||
`rustc_lexer::UNICODE_VERSION` and `unicode_normalization::UNICODE_VERSION` are \
|
||||
different."
|
||||
);
|
||||
}
|
||||
|
||||
if rustc_lexer.0 != width.0 || rustc_lexer.1 != width.1 || rustc_lexer.2 != width.2 {
|
||||
panic!(
|
||||
"rustc_lexer and unicode-width must use the same Unicode version, \
|
||||
`rustc_lexer::UNICODE_VERSION` and `unicode_width::UNICODE_VERSION` are \
|
||||
different."
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
||||
// Unwrap the result if `Ok`, otherwise emit the diagnostics and abort.
|
||||
|
|
|
|||
|
|
@ -1521,7 +1521,7 @@ impl<'a> Parser<'a> {
|
|||
},
|
||||
)
|
||||
} else if this.check_inline_const(0) {
|
||||
this.parse_const_block(lo, false)
|
||||
this.parse_const_block(lo)
|
||||
} else if this.may_recover() && this.is_do_catch_block() {
|
||||
this.recover_do_catch()
|
||||
} else if this.is_try_block() {
|
||||
|
|
|
|||
|
|
@ -1317,7 +1317,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
/// Parses inline const expressions.
|
||||
fn parse_const_block(&mut self, span: Span, pat: bool) -> PResult<'a, Box<Expr>> {
|
||||
fn parse_const_block(&mut self, span: Span) -> PResult<'a, Box<Expr>> {
|
||||
self.expect_keyword(exp!(Const))?;
|
||||
let (attrs, blk) = self.parse_inner_attrs_and_block(None)?;
|
||||
let anon_const = AnonConst {
|
||||
|
|
@ -1326,18 +1326,7 @@ impl<'a> Parser<'a> {
|
|||
mgca_disambiguation: MgcaDisambiguation::AnonConst,
|
||||
};
|
||||
let blk_span = anon_const.value.span;
|
||||
let kind = if pat {
|
||||
let guar = self
|
||||
.dcx()
|
||||
.struct_span_err(blk_span, "const blocks cannot be used as patterns")
|
||||
.with_help(
|
||||
"use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead",
|
||||
)
|
||||
.emit();
|
||||
ExprKind::Err(guar)
|
||||
} else {
|
||||
ExprKind::ConstBlock(anon_const)
|
||||
};
|
||||
let kind = ExprKind::ConstBlock(anon_const);
|
||||
Ok(self.mk_expr_with_attrs(span.to(blk_span), kind, attrs))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -785,8 +785,10 @@ impl<'a> Parser<'a> {
|
|||
} else if self.eat_keyword(exp!(Box)) {
|
||||
self.parse_pat_box()?
|
||||
} else if self.check_inline_const(0) {
|
||||
// Parse `const pat`
|
||||
let const_expr = self.parse_const_block(lo.to(self.token.span), true)?;
|
||||
// Parse `const pat`.
|
||||
// NOTE: This will always error later during AST lowering because
|
||||
// inline const cannot be used as patterns.
|
||||
let const_expr = self.parse_const_block(lo.to(self.token.span))?;
|
||||
|
||||
if let Some(re) = self.parse_range_end() {
|
||||
self.parse_pat_range_begin_with(const_expr, re)?
|
||||
|
|
@ -1281,7 +1283,7 @@ impl<'a> Parser<'a> {
|
|||
.then_some(self.prev_token.span);
|
||||
|
||||
let bound = if self.check_inline_const(0) {
|
||||
self.parse_const_block(self.token.span, true)
|
||||
self.parse_const_block(self.token.span)
|
||||
} else if self.check_path() {
|
||||
let lo = self.token.span;
|
||||
let (qself, path) = if self.eat_lt() {
|
||||
|
|
|
|||
|
|
@ -21,5 +21,5 @@ scoped-tls = "1.0"
|
|||
sha1 = "0.10.0"
|
||||
sha2 = "0.10.1"
|
||||
tracing = "0.1"
|
||||
unicode-width = "0.2.0"
|
||||
unicode-width = "0.2.2"
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic};
|
|||
use rustc_serialize::opaque::{FileEncoder, MemDecoder};
|
||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||
use tracing::debug;
|
||||
pub use unicode_width::UNICODE_VERSION;
|
||||
|
||||
mod caching_source_map_view;
|
||||
pub mod source_map;
|
||||
|
|
|
|||
|
|
@ -755,9 +755,8 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> {
|
|||
dereferenced_const.print(self)?;
|
||||
}
|
||||
|
||||
ty::Array(..) | ty::Tuple(..) | ty::Adt(..) | ty::Slice(_) => {
|
||||
let contents = self.tcx.destructure_const(ct);
|
||||
let fields = contents.fields.iter().copied();
|
||||
ty::Array(..) | ty::Tuple(..) | ty::Slice(_) => {
|
||||
let fields = cv.to_branch().iter().copied();
|
||||
|
||||
let print_field_list = |this: &mut Self| {
|
||||
for field in fields.clone() {
|
||||
|
|
@ -776,45 +775,53 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> {
|
|||
self.push("T");
|
||||
print_field_list(self)?;
|
||||
}
|
||||
ty::Adt(def, args) => {
|
||||
let variant_idx =
|
||||
contents.variant.expect("destructed const of adt without variant idx");
|
||||
let variant_def = &def.variant(variant_idx);
|
||||
|
||||
self.push("V");
|
||||
self.print_def_path(variant_def.def_id, args)?;
|
||||
|
||||
match variant_def.ctor_kind() {
|
||||
Some(CtorKind::Const) => {
|
||||
self.push("U");
|
||||
}
|
||||
Some(CtorKind::Fn) => {
|
||||
self.push("T");
|
||||
print_field_list(self)?;
|
||||
}
|
||||
None => {
|
||||
self.push("S");
|
||||
for (field_def, field) in iter::zip(&variant_def.fields, fields) {
|
||||
// HACK(eddyb) this mimics `print_path_with_simple`,
|
||||
// instead of simply using `field_def.ident`,
|
||||
// just to be able to handle disambiguators.
|
||||
let disambiguated_field =
|
||||
self.tcx.def_key(field_def.did).disambiguated_data;
|
||||
let field_name = disambiguated_field.data.get_opt_name();
|
||||
self.push_disambiguator(
|
||||
disambiguated_field.disambiguator as u64,
|
||||
);
|
||||
self.push_ident(field_name.unwrap().as_str());
|
||||
|
||||
field.print(self)?;
|
||||
}
|
||||
self.push("E");
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
ty::Adt(def, args) => {
|
||||
let contents = cv.destructure_adt_const();
|
||||
let fields = contents.fields.iter().copied();
|
||||
|
||||
let print_field_list = |this: &mut Self| {
|
||||
for field in fields.clone() {
|
||||
field.print(this)?;
|
||||
}
|
||||
this.push("E");
|
||||
Ok(())
|
||||
};
|
||||
|
||||
let variant_idx = contents.variant;
|
||||
let variant_def = &def.variant(variant_idx);
|
||||
|
||||
self.push("V");
|
||||
self.print_def_path(variant_def.def_id, args)?;
|
||||
|
||||
match variant_def.ctor_kind() {
|
||||
Some(CtorKind::Const) => {
|
||||
self.push("U");
|
||||
}
|
||||
Some(CtorKind::Fn) => {
|
||||
self.push("T");
|
||||
print_field_list(self)?;
|
||||
}
|
||||
None => {
|
||||
self.push("S");
|
||||
for (field_def, field) in iter::zip(&variant_def.fields, fields) {
|
||||
// HACK(eddyb) this mimics `print_path_with_simple`,
|
||||
// instead of simply using `field_def.ident`,
|
||||
// just to be able to handle disambiguators.
|
||||
let disambiguated_field =
|
||||
self.tcx.def_key(field_def.did).disambiguated_data;
|
||||
let field_name = disambiguated_field.data.get_opt_name();
|
||||
self.push_disambiguator(disambiguated_field.disambiguator as u64);
|
||||
self.push_ident(field_name.unwrap().as_str());
|
||||
|
||||
field.print(self)?;
|
||||
}
|
||||
self.push("E");
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct_ty, ct);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
use std::iter;
|
||||
|
||||
use rustc_abi::{FIRST_VARIANT, VariantIdx};
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
|
|
@ -10,63 +7,12 @@ use rustc_middle::thir::visit;
|
|||
use rustc_middle::thir::visit::Visitor;
|
||||
use rustc_middle::ty::abstract_const::CastKind;
|
||||
use rustc_middle::ty::{self, Expr, TyCtxt, TypeVisitableExt};
|
||||
use rustc_middle::{bug, mir, thir};
|
||||
use rustc_middle::{mir, thir};
|
||||
use rustc_span::Span;
|
||||
use tracing::{debug, instrument};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::errors::{GenericConstantTooComplex, GenericConstantTooComplexSub};
|
||||
|
||||
/// Destructures array, ADT or tuple constants into the constants
|
||||
/// of their fields.
|
||||
fn destructure_const<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
const_: ty::Const<'tcx>,
|
||||
) -> ty::DestructuredConst<'tcx> {
|
||||
let ty::ConstKind::Value(cv) = const_.kind() else {
|
||||
bug!("cannot destructure constant {:?}", const_)
|
||||
};
|
||||
let branches = cv.to_branch();
|
||||
|
||||
let (fields, variant) = match cv.ty.kind() {
|
||||
ty::Array(inner_ty, _) | ty::Slice(inner_ty) => {
|
||||
// construct the consts for the elements of the array/slice
|
||||
let field_consts = branches
|
||||
.iter()
|
||||
.map(|b| ty::Const::new_value(tcx, b.to_value().valtree, *inner_ty))
|
||||
.collect::<Vec<_>>();
|
||||
debug!(?field_consts);
|
||||
|
||||
(field_consts, None)
|
||||
}
|
||||
ty::Adt(def, _) if def.variants().is_empty() => bug!("unreachable"),
|
||||
ty::Adt(def, _) => {
|
||||
let (variant_idx, field_consts) = if def.is_enum() {
|
||||
let (head, rest) = branches.split_first().unwrap();
|
||||
(VariantIdx::from_u32(head.to_leaf().to_u32()), rest)
|
||||
} else {
|
||||
(FIRST_VARIANT, branches)
|
||||
};
|
||||
debug!(?field_consts);
|
||||
|
||||
(field_consts.to_vec(), Some(variant_idx))
|
||||
}
|
||||
ty::Tuple(elem_tys) => {
|
||||
let fields = iter::zip(*elem_tys, branches)
|
||||
.map(|(elem_ty, elem_valtree)| {
|
||||
ty::Const::new_value(tcx, elem_valtree.to_value().valtree, elem_ty)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
(fields, None)
|
||||
}
|
||||
_ => bug!("cannot destructure constant {:?}", const_),
|
||||
};
|
||||
|
||||
let fields = tcx.arena.alloc_from_iter(fields);
|
||||
|
||||
ty::DestructuredConst { variant, fields }
|
||||
}
|
||||
|
||||
/// We do not allow all binary operations in abstract consts, so filter disallowed ones.
|
||||
fn check_binop(op: mir::BinOp) -> bool {
|
||||
use mir::BinOp::*;
|
||||
|
|
@ -432,5 +378,5 @@ fn thir_abstract_const<'tcx>(
|
|||
}
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { destructure_const, thir_abstract_const, ..*providers };
|
||||
*providers = Providers { thir_abstract_const, ..*providers };
|
||||
}
|
||||
|
|
|
|||
171
library/core/src/num/int_bits.rs
Normal file
171
library/core/src/num/int_bits.rs
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
//! Implementations for `uN::gather_bits` and `uN::scatter_bits`
|
||||
//!
|
||||
//! For the purposes of this implementation, the operations can be thought
|
||||
//! of as operating on the input bits as a list, starting from the least
|
||||
//! significant bit. Gathering is like `Vec::retain` that deletes bits
|
||||
//! where the mask has a zero. Scattering is like doing the inverse by
|
||||
//! inserting the zeros that gathering would delete.
|
||||
//!
|
||||
//! Key observation: Each bit that is gathered/scattered needs to be
|
||||
//! shifted by the count of zeros up to the corresponding mask bit.
|
||||
//!
|
||||
//! With that in mind, the general idea is to decompose the operation into
|
||||
//! a sequence of stages in `0..log2(BITS)`, where each stage shifts some
|
||||
//! of the bits by `n = 1 << stage`. The masks for each stage are computed
|
||||
//! via prefix counts of zeros in the mask.
|
||||
//!
|
||||
//! # Gathering
|
||||
//!
|
||||
//! Consider the input as a sequence of runs of data (bitstrings A,B,C,...),
|
||||
//! split by fixed-width groups of zeros ('.'), initially at width `n = 1`.
|
||||
//! Counting the groups of zeros, each stage shifts the odd-indexed runs of
|
||||
//! data right by `n`, effectively swapping them with the preceding zeros.
|
||||
//! For the next stage, `n` is doubled as all the zeros are now paired.
|
||||
//! ```text
|
||||
//! .A.B.C.D.E.F.G.H
|
||||
//! ..AB..CD..EF..GH
|
||||
//! ....ABCD....EFGH
|
||||
//! ........ABCDEFGH
|
||||
//! ```
|
||||
//! What makes this nontrivial is that the lengths of the bitstrings are not
|
||||
//! the same. Using lowercase for individual bits, the above might look like
|
||||
//! ```text
|
||||
//! .a.bbb.ccccc.dd.e..g.hh
|
||||
//! ..abbb..cccccdd..e..ghh
|
||||
//! ....abbbcccccdd....eghh
|
||||
//! ........abbbcccccddeghh
|
||||
//! ```
|
||||
//!
|
||||
//! # Scattering
|
||||
//!
|
||||
//! For `scatter_bits`, the stages are reversed. We start with a single run of
|
||||
//! data in the low bits. Each stage then splits each run of data in two by
|
||||
//! shifting part of it left by `n`, which is halved each stage.
|
||||
//! ```text
|
||||
//! ........ABCDEFGH
|
||||
//! ....ABCD....EFGH
|
||||
//! ..AB..CD..EF..GH
|
||||
//! .A.B.C.D.E.F.G.H
|
||||
//! ```
|
||||
//!
|
||||
//! # Stage masks
|
||||
//!
|
||||
//! To facilitate the shifts at each stage, we compute a mask that covers both
|
||||
//! the bitstrings to shift, and the zeros they shift into.
|
||||
//! ```text
|
||||
//! .A.B.C.D.E.F.G.H
|
||||
//! ## ## ## ##
|
||||
//! ..AB..CD..EF..GH
|
||||
//! #### ####
|
||||
//! ....ABCD....EFGH
|
||||
//! ########
|
||||
//! ........ABCDEFGH
|
||||
//! ```
|
||||
|
||||
macro_rules! uint_impl {
|
||||
($U:ident) => {
|
||||
pub(super) mod $U {
|
||||
const STAGES: usize = $U::BITS.ilog2() as usize;
|
||||
#[inline]
|
||||
const fn prepare(sparse: $U) -> [$U; STAGES] {
|
||||
// We'll start with `zeros` as a mask of the bits to be removed,
|
||||
// and compute into `masks` the parts that shift at each stage.
|
||||
let mut zeros = !sparse;
|
||||
let mut masks = [0; STAGES];
|
||||
let mut stage = 0;
|
||||
while stage < STAGES {
|
||||
let n = 1 << stage;
|
||||
// Suppose `zeros` has bits set at ranges `{ a..a+n, b..b+n, ... }`.
|
||||
// Then `parity` will be computed as `{ a.. } XOR { b.. } XOR ...`,
|
||||
// which will be the ranges `{ a..b, c..d, e.. }`.
|
||||
let mut parity = zeros;
|
||||
let mut len = n;
|
||||
while len < $U::BITS {
|
||||
parity ^= parity << len;
|
||||
len <<= 1;
|
||||
}
|
||||
masks[stage] = parity;
|
||||
|
||||
// Toggle off the bits that are shifted into:
|
||||
// { a..a+n, b..b+n, ... } & !{ a..b, c..d, e.. }
|
||||
// == { b..b+n, d..d+n, ... }
|
||||
zeros &= !parity;
|
||||
// Expand the remaining ranges down to the bits that were
|
||||
// shifted from: { b-n..b+n, d-n..d+n, ... }
|
||||
zeros ^= zeros >> n;
|
||||
|
||||
stage += 1;
|
||||
}
|
||||
masks
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(in super::super) const fn gather_impl(mut x: $U, sparse: $U) -> $U {
|
||||
let masks = prepare(sparse);
|
||||
x &= sparse;
|
||||
let mut stage = 0;
|
||||
while stage < STAGES {
|
||||
let n = 1 << stage;
|
||||
// Consider each two runs of data with their leading
|
||||
// groups of `n` 0-bits. Suppose that the run that is
|
||||
// shifted right has length `a`, and the other one has
|
||||
// length `b`. Assume that only zeros are shifted in.
|
||||
// ```text
|
||||
// [0; n], [X; a], [0; n], [Y; b] // x
|
||||
// [0; n], [X; a], [0; n], [0; b] // q
|
||||
// [0; n], [0; a + n], [Y; b] // x ^= q
|
||||
// [0; n + n], [X; a], [0; b] // q >> n
|
||||
// [0; n], [0; n], [X; a], [Y; b] // x ^= q << n
|
||||
// ```
|
||||
// Only zeros are shifted out, satisfying the assumption
|
||||
// for the next group.
|
||||
|
||||
// In effect, the upper run of data is swapped with the
|
||||
// group of `n` zeros below it.
|
||||
let q = x & masks[stage];
|
||||
x ^= q;
|
||||
x ^= q >> n;
|
||||
|
||||
stage += 1;
|
||||
}
|
||||
x
|
||||
}
|
||||
#[inline(always)]
|
||||
pub(in super::super) const fn scatter_impl(mut x: $U, sparse: $U) -> $U {
|
||||
let masks = prepare(sparse);
|
||||
let mut stage = STAGES;
|
||||
while stage > 0 {
|
||||
stage -= 1;
|
||||
let n = 1 << stage;
|
||||
// Consider each run of data with the `2 * n` arbitrary bits
|
||||
// above it. Suppose that the run has length `a + b`, with
|
||||
// `a` being the length of the part that needs to be
|
||||
// shifted. Assume that only zeros are shifted in.
|
||||
// ```text
|
||||
// [_; n], [_; n], [X; a], [Y; b] // x
|
||||
// [0; n], [_; n], [X; a], [0; b] // q
|
||||
// [_; n], [0; n + a], [Y; b] // x ^= q
|
||||
// [_; n], [X; a], [0; b + n] // q << n
|
||||
// [_; n], [X; a], [0; n], [Y; b] // x ^= q << n
|
||||
// ```
|
||||
// Only zeros are shifted out, satisfying the assumption
|
||||
// for the next group.
|
||||
|
||||
// In effect, `n` 0-bits are inserted somewhere in each run
|
||||
// of data to spread it, and the two groups of `n` bits
|
||||
// above are XOR'd together.
|
||||
let q = x & masks[stage];
|
||||
x ^= q;
|
||||
x ^= q << n;
|
||||
}
|
||||
x & sparse
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
uint_impl!(u8);
|
||||
uint_impl!(u16);
|
||||
uint_impl!(u32);
|
||||
uint_impl!(u64);
|
||||
uint_impl!(u128);
|
||||
|
|
@ -1421,8 +1421,15 @@ macro_rules! int_impl {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(4), 0x10);")]
|
||||
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(129), 0);")]
|
||||
#[doc = concat!("assert_eq!(0x1_", stringify!($SelfT), ".unbounded_shl(4), 0x10);")]
|
||||
#[doc = concat!("assert_eq!(0x1_", stringify!($SelfT), ".unbounded_shl(129), 0);")]
|
||||
#[doc = concat!("assert_eq!(0b101_", stringify!($SelfT), ".unbounded_shl(0), 0b101);")]
|
||||
#[doc = concat!("assert_eq!(0b101_", stringify!($SelfT), ".unbounded_shl(1), 0b1010);")]
|
||||
#[doc = concat!("assert_eq!(0b101_", stringify!($SelfT), ".unbounded_shl(2), 0b10100);")]
|
||||
#[doc = concat!("assert_eq!(42_", stringify!($SelfT), ".unbounded_shl(", stringify!($BITS), "), 0);")]
|
||||
#[doc = concat!("assert_eq!(42_", stringify!($SelfT), ".unbounded_shl(1).unbounded_shl(", stringify!($BITS_MINUS_ONE), "), 0);")]
|
||||
#[doc = concat!("assert_eq!((-13_", stringify!($SelfT), ").unbounded_shl(", stringify!($BITS), "), 0);")]
|
||||
#[doc = concat!("assert_eq!((-13_", stringify!($SelfT), ").unbounded_shl(1).unbounded_shl(", stringify!($BITS_MINUS_ONE), "), 0);")]
|
||||
/// ```
|
||||
#[stable(feature = "unbounded_shifts", since = "1.87.0")]
|
||||
#[rustc_const_stable(feature = "unbounded_shifts", since = "1.87.0")]
|
||||
|
|
@ -1594,9 +1601,16 @@ macro_rules! int_impl {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(4), 0x1);")]
|
||||
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(129), 0);")]
|
||||
#[doc = concat!("assert_eq!(0x10_", stringify!($SelfT), ".unbounded_shr(4), 0x1);")]
|
||||
#[doc = concat!("assert_eq!(0x10_", stringify!($SelfT), ".unbounded_shr(129), 0);")]
|
||||
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.unbounded_shr(129), -1);")]
|
||||
#[doc = concat!("assert_eq!(0b1010_", stringify!($SelfT), ".unbounded_shr(0), 0b1010);")]
|
||||
#[doc = concat!("assert_eq!(0b1010_", stringify!($SelfT), ".unbounded_shr(1), 0b101);")]
|
||||
#[doc = concat!("assert_eq!(0b1010_", stringify!($SelfT), ".unbounded_shr(2), 0b10);")]
|
||||
#[doc = concat!("assert_eq!(42_", stringify!($SelfT), ".unbounded_shr(", stringify!($BITS), "), 0);")]
|
||||
#[doc = concat!("assert_eq!(42_", stringify!($SelfT), ".unbounded_shr(1).unbounded_shr(", stringify!($BITS_MINUS_ONE), "), 0);")]
|
||||
#[doc = concat!("assert_eq!((-13_", stringify!($SelfT), ").unbounded_shr(", stringify!($BITS), "), -1);")]
|
||||
#[doc = concat!("assert_eq!((-13_", stringify!($SelfT), ").unbounded_shr(1).unbounded_shr(", stringify!($BITS_MINUS_ONE), "), -1);")]
|
||||
/// ```
|
||||
#[stable(feature = "unbounded_shifts", since = "1.87.0")]
|
||||
#[rustc_const_stable(feature = "unbounded_shifts", since = "1.87.0")]
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ mod int_macros; // import int_impl!
|
|||
mod uint_macros; // import uint_impl!
|
||||
|
||||
mod error;
|
||||
mod int_bits;
|
||||
mod int_log10;
|
||||
mod int_sqrt;
|
||||
pub(crate) mod libm;
|
||||
|
|
|
|||
|
|
@ -492,27 +492,8 @@ macro_rules! uint_impl {
|
|||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn gather_bits(self, mut mask: Self) -> Self {
|
||||
let mut bit_position = 1;
|
||||
let mut result = 0;
|
||||
|
||||
// Iterate through the mask bits, unsetting the lowest bit after
|
||||
// each iteration. We fill the bits in the result starting from the
|
||||
// least significant bit.
|
||||
while mask != 0 {
|
||||
// Find the next lowest set bit in the mask
|
||||
let next_mask_bit = mask.isolate_lowest_one();
|
||||
|
||||
// Retrieve the masked bit and if present, set it in the result
|
||||
let src_bit = (self & next_mask_bit) != 0;
|
||||
result |= if src_bit { bit_position } else { 0 };
|
||||
|
||||
// Unset lowest set bit in the mask, prepare next position to set
|
||||
mask ^= next_mask_bit;
|
||||
bit_position <<= 1;
|
||||
}
|
||||
|
||||
result
|
||||
pub const fn gather_bits(self, mask: Self) -> Self {
|
||||
crate::num::int_bits::$ActualT::gather_impl(self as $ActualT, mask as $ActualT) as $SelfT
|
||||
}
|
||||
|
||||
/// Returns an integer with the least significant bits of `self`
|
||||
|
|
@ -528,25 +509,8 @@ macro_rules! uint_impl {
|
|||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn scatter_bits(mut self, mut mask: Self) -> Self {
|
||||
let mut result = 0;
|
||||
|
||||
// Iterate through the mask bits, unsetting the lowest bit after
|
||||
// each iteration and right-shifting `self` by one to get the next
|
||||
// bit into the least significant bit position.
|
||||
while mask != 0 {
|
||||
// Find the next bit position to potentially set
|
||||
let next_mask_bit = mask.isolate_lowest_one();
|
||||
|
||||
// If bit is set, deposit it at the masked bit position
|
||||
result |= if (self & 1) != 0 { next_mask_bit } else { 0 };
|
||||
|
||||
// Unset lowest set bit in the mask, shift in next `self` bit
|
||||
mask ^= next_mask_bit;
|
||||
self >>= 1;
|
||||
}
|
||||
|
||||
result
|
||||
pub const fn scatter_bits(self, mask: Self) -> Self {
|
||||
crate::num::int_bits::$ActualT::scatter_impl(self as $ActualT, mask as $ActualT) as $SelfT
|
||||
}
|
||||
|
||||
/// Reverses the order of bits in the integer. The least significant bit becomes the most significant bit,
|
||||
|
|
@ -1880,8 +1844,24 @@ macro_rules! uint_impl {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(4), 0x10);")]
|
||||
#[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(129), 0);")]
|
||||
#[doc = concat!("assert_eq!(0x1_", stringify!($SelfT), ".unbounded_shl(4), 0x10);")]
|
||||
#[doc = concat!("assert_eq!(0x1_", stringify!($SelfT), ".unbounded_shl(129), 0);")]
|
||||
#[doc = concat!("assert_eq!(0b101_", stringify!($SelfT), ".unbounded_shl(0), 0b101);")]
|
||||
#[doc = concat!("assert_eq!(0b101_", stringify!($SelfT), ".unbounded_shl(1), 0b1010);")]
|
||||
#[doc = concat!("assert_eq!(0b101_", stringify!($SelfT), ".unbounded_shl(2), 0b10100);")]
|
||||
#[doc = concat!("assert_eq!(42_", stringify!($SelfT), ".unbounded_shl(", stringify!($BITS), "), 0);")]
|
||||
#[doc = concat!("assert_eq!(42_", stringify!($SelfT), ".unbounded_shl(1).unbounded_shl(", stringify!($BITS_MINUS_ONE), "), 0);")]
|
||||
///
|
||||
#[doc = concat!("let start : ", stringify!($SelfT), " = 13;")]
|
||||
/// let mut running = start;
|
||||
/// for i in 0..160 {
|
||||
/// // The unbounded shift left by i is the same as `<< 1` i times
|
||||
/// assert_eq!(running, start.unbounded_shl(i));
|
||||
/// // Which is not always the case for a wrapping shift
|
||||
#[doc = concat!(" assert_eq!(running == start.wrapping_shl(i), i < ", stringify!($BITS), ");")]
|
||||
///
|
||||
/// running <<= 1;
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "unbounded_shifts", since = "1.87.0")]
|
||||
#[rustc_const_stable(feature = "unbounded_shifts", since = "1.87.0")]
|
||||
|
|
@ -2049,8 +2029,24 @@ macro_rules! uint_impl {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(4), 0x1);")]
|
||||
#[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(129), 0);")]
|
||||
#[doc = concat!("assert_eq!(0x10_", stringify!($SelfT), ".unbounded_shr(4), 0x1);")]
|
||||
#[doc = concat!("assert_eq!(0x10_", stringify!($SelfT), ".unbounded_shr(129), 0);")]
|
||||
#[doc = concat!("assert_eq!(0b1010_", stringify!($SelfT), ".unbounded_shr(0), 0b1010);")]
|
||||
#[doc = concat!("assert_eq!(0b1010_", stringify!($SelfT), ".unbounded_shr(1), 0b101);")]
|
||||
#[doc = concat!("assert_eq!(0b1010_", stringify!($SelfT), ".unbounded_shr(2), 0b10);")]
|
||||
#[doc = concat!("assert_eq!(42_", stringify!($SelfT), ".unbounded_shr(", stringify!($BITS), "), 0);")]
|
||||
#[doc = concat!("assert_eq!(42_", stringify!($SelfT), ".unbounded_shr(1).unbounded_shr(", stringify!($BITS_MINUS_ONE), "), 0);")]
|
||||
///
|
||||
#[doc = concat!("let start = ", stringify!($SelfT), "::rotate_right(13, 4);")]
|
||||
/// let mut running = start;
|
||||
/// for i in 0..160 {
|
||||
/// // The unbounded shift right by i is the same as `>> 1` i times
|
||||
/// assert_eq!(running, start.unbounded_shr(i));
|
||||
/// // Which is not always the case for a wrapping shift
|
||||
#[doc = concat!(" assert_eq!(running == start.wrapping_shr(i), i < ", stringify!($BITS), ");")]
|
||||
///
|
||||
/// running >>= 1;
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "unbounded_shifts", since = "1.87.0")]
|
||||
#[rustc_const_stable(feature = "unbounded_shifts", since = "1.87.0")]
|
||||
|
|
|
|||
|
|
@ -1131,6 +1131,46 @@ impl Duration {
|
|||
let rhs_nanos = (rhs.secs as f32) * (NANOS_PER_SEC as f32) + (rhs.nanos.as_inner() as f32);
|
||||
self_nanos / rhs_nanos
|
||||
}
|
||||
|
||||
/// Divides `Duration` by `Duration` and returns `u128`, rounding the result towards zero.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// #![feature(duration_integer_division)]
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// let dur = Duration::new(2, 0);
|
||||
/// assert_eq!(dur.div_duration_floor(Duration::new(1, 000_000_001)), 1);
|
||||
/// assert_eq!(dur.div_duration_floor(Duration::new(1, 000_000_000)), 2);
|
||||
/// assert_eq!(dur.div_duration_floor(Duration::new(0, 999_999_999)), 2);
|
||||
/// ```
|
||||
#[unstable(feature = "duration_integer_division", issue = "149573")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn div_duration_floor(self, rhs: Duration) -> u128 {
|
||||
self.as_nanos().div_floor(rhs.as_nanos())
|
||||
}
|
||||
|
||||
/// Divides `Duration` by `Duration` and returns `u128`, rounding the result towards positive infinity.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// #![feature(duration_integer_division)]
|
||||
/// use std::time::Duration;
|
||||
///
|
||||
/// let dur = Duration::new(2, 0);
|
||||
/// assert_eq!(dur.div_duration_ceil(Duration::new(1, 000_000_001)), 2);
|
||||
/// assert_eq!(dur.div_duration_ceil(Duration::new(1, 000_000_000)), 2);
|
||||
/// assert_eq!(dur.div_duration_ceil(Duration::new(0, 999_999_999)), 3);
|
||||
/// ```
|
||||
#[unstable(feature = "duration_integer_division", issue = "149573")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn div_duration_ceil(self, rhs: Duration) -> u128 {
|
||||
self.as_nanos().div_ceil(rhs.as_nanos())
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "duration", since = "1.3.0")]
|
||||
|
|
|
|||
|
|
@ -21,9 +21,13 @@ pub struct FileAttr {
|
|||
created: Option<SystemTime>,
|
||||
}
|
||||
|
||||
pub struct ReadDir(!);
|
||||
pub struct ReadDir(uefi_fs::File);
|
||||
|
||||
pub struct DirEntry(!);
|
||||
pub struct DirEntry {
|
||||
attr: FileAttr,
|
||||
file_name: OsString,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OpenOptions {
|
||||
|
|
@ -143,8 +147,10 @@ impl FileType {
|
|||
}
|
||||
|
||||
impl fmt::Debug for ReadDir {
|
||||
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut b = f.debug_struct("ReadDir");
|
||||
b.field("path", &self.0.path());
|
||||
b.finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -152,25 +158,35 @@ impl Iterator for ReadDir {
|
|||
type Item = io::Result<DirEntry>;
|
||||
|
||||
fn next(&mut self) -> Option<io::Result<DirEntry>> {
|
||||
self.0
|
||||
match self.0.read_dir_entry() {
|
||||
Ok(None) => None,
|
||||
Ok(Some(x)) => Some(Ok(DirEntry::from_uefi(x, self.0.path()))),
|
||||
Err(e) => Some(Err(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DirEntry {
|
||||
pub fn path(&self) -> PathBuf {
|
||||
self.0
|
||||
self.path.clone()
|
||||
}
|
||||
|
||||
pub fn file_name(&self) -> OsString {
|
||||
self.0
|
||||
self.file_name.clone()
|
||||
}
|
||||
|
||||
pub fn metadata(&self) -> io::Result<FileAttr> {
|
||||
self.0
|
||||
Ok(self.attr.clone())
|
||||
}
|
||||
|
||||
pub fn file_type(&self) -> io::Result<FileType> {
|
||||
self.0
|
||||
Ok(self.attr.file_type())
|
||||
}
|
||||
|
||||
fn from_uefi(info: helpers::UefiBox<file::Info>, parent: &Path) -> Self {
|
||||
let file_name = uefi_fs::file_name_from_uefi(&info);
|
||||
let path = parent.join(&file_name);
|
||||
Self { file_name, path, attr: FileAttr::from_uefi(info) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -344,8 +360,17 @@ impl fmt::Debug for File {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
|
||||
unsupported()
|
||||
pub fn readdir(p: &Path) -> io::Result<ReadDir> {
|
||||
let path = crate::path::absolute(p)?;
|
||||
let f = uefi_fs::File::from_path(&path, file::MODE_READ, 0)?;
|
||||
let file_info = f.file_info()?;
|
||||
let file_attr = FileAttr::from_uefi(file_info);
|
||||
|
||||
if file_attr.file_type().is_dir() {
|
||||
Ok(ReadDir(f))
|
||||
} else {
|
||||
Err(io::const_error!(io::ErrorKind::NotADirectory, "expected a directory but got a file"))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unlink(p: &Path) -> io::Result<()> {
|
||||
|
|
@ -459,13 +484,18 @@ mod uefi_fs {
|
|||
use r_efi::protocols::{device_path, file, simple_file_system};
|
||||
|
||||
use crate::boxed::Box;
|
||||
use crate::ffi::OsString;
|
||||
use crate::io;
|
||||
use crate::os::uefi::ffi::OsStringExt;
|
||||
use crate::path::Path;
|
||||
use crate::ptr::NonNull;
|
||||
use crate::sys::helpers::{self, UefiBox};
|
||||
use crate::sys::time::{self, SystemTime};
|
||||
|
||||
pub(crate) struct File(NonNull<file::Protocol>);
|
||||
pub(crate) struct File {
|
||||
protocol: NonNull<file::Protocol>,
|
||||
path: crate::path::PathBuf,
|
||||
}
|
||||
|
||||
impl File {
|
||||
pub(crate) fn from_path(path: &Path, open_mode: u64, attr: u64) -> io::Result<Self> {
|
||||
|
|
@ -474,7 +504,8 @@ mod uefi_fs {
|
|||
let p = helpers::OwnedDevicePath::from_text(absolute.as_os_str())?;
|
||||
let (vol, mut path_remaining) = Self::open_volume_from_device_path(p.borrow())?;
|
||||
|
||||
vol.open(&mut path_remaining, open_mode, attr)
|
||||
let protocol = Self::open(vol, &mut path_remaining, open_mode, attr)?;
|
||||
Ok(Self { protocol, path: absolute })
|
||||
}
|
||||
|
||||
/// Open Filesystem volume given a devicepath to the volume, or a file/directory in the
|
||||
|
|
@ -490,7 +521,7 @@ mod uefi_fs {
|
|||
/// and return the remaining file path "\abc\run.efi".
|
||||
fn open_volume_from_device_path(
|
||||
path: helpers::BorrowedDevicePath<'_>,
|
||||
) -> io::Result<(Self, Box<[u16]>)> {
|
||||
) -> io::Result<(NonNull<file::Protocol>, Box<[u16]>)> {
|
||||
let handles = match helpers::locate_handles(simple_file_system::PROTOCOL_GUID) {
|
||||
Ok(x) => x,
|
||||
Err(e) => return Err(e),
|
||||
|
|
@ -512,7 +543,9 @@ mod uefi_fs {
|
|||
}
|
||||
|
||||
// Open volume on device_handle using SIMPLE_FILE_SYSTEM_PROTOCOL
|
||||
fn open_volume(device_handle: NonNull<crate::ffi::c_void>) -> io::Result<Self> {
|
||||
fn open_volume(
|
||||
device_handle: NonNull<crate::ffi::c_void>,
|
||||
) -> io::Result<NonNull<file::Protocol>> {
|
||||
let simple_file_system_protocol = helpers::open_protocol::<simple_file_system::Protocol>(
|
||||
device_handle,
|
||||
simple_file_system::PROTOCOL_GUID,
|
||||
|
|
@ -531,11 +564,16 @@ mod uefi_fs {
|
|||
|
||||
// Since no error was returned, file protocol should be non-NULL.
|
||||
let p = NonNull::new(file_protocol).unwrap();
|
||||
Ok(Self(p))
|
||||
Ok(p)
|
||||
}
|
||||
|
||||
fn open(&self, path: &mut [u16], open_mode: u64, attr: u64) -> io::Result<Self> {
|
||||
let file_ptr = self.0.as_ptr();
|
||||
fn open(
|
||||
protocol: NonNull<file::Protocol>,
|
||||
path: &mut [u16],
|
||||
open_mode: u64,
|
||||
attr: u64,
|
||||
) -> io::Result<NonNull<file::Protocol>> {
|
||||
let file_ptr = protocol.as_ptr();
|
||||
let mut file_opened = crate::ptr::null_mut();
|
||||
|
||||
let r = unsafe {
|
||||
|
|
@ -548,11 +586,37 @@ mod uefi_fs {
|
|||
|
||||
// Since no error was returned, file protocol should be non-NULL.
|
||||
let p = NonNull::new(file_opened).unwrap();
|
||||
Ok(File(p))
|
||||
Ok(p)
|
||||
}
|
||||
|
||||
pub(crate) fn read_dir_entry(&self) -> io::Result<Option<UefiBox<file::Info>>> {
|
||||
let file_ptr = self.protocol.as_ptr();
|
||||
let mut buf_size = 0;
|
||||
|
||||
let r = unsafe { ((*file_ptr).read)(file_ptr, &mut buf_size, crate::ptr::null_mut()) };
|
||||
|
||||
if buf_size == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
assert!(r.is_error());
|
||||
if r != r_efi::efi::Status::BUFFER_TOO_SMALL {
|
||||
return Err(io::Error::from_raw_os_error(r.as_usize()));
|
||||
}
|
||||
|
||||
let mut info: UefiBox<file::Info> = UefiBox::new(buf_size)?;
|
||||
let r =
|
||||
unsafe { ((*file_ptr).read)(file_ptr, &mut buf_size, info.as_mut_ptr().cast()) };
|
||||
|
||||
if r.is_error() {
|
||||
Err(io::Error::from_raw_os_error(r.as_usize()))
|
||||
} else {
|
||||
Ok(Some(info))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn file_info(&self) -> io::Result<UefiBox<file::Info>> {
|
||||
let file_ptr = self.0.as_ptr();
|
||||
let file_ptr = self.protocol.as_ptr();
|
||||
let mut info_id = file::INFO_ID;
|
||||
let mut buf_size = 0;
|
||||
|
||||
|
|
@ -583,7 +647,7 @@ mod uefi_fs {
|
|||
}
|
||||
|
||||
pub(crate) fn set_file_info(&self, mut info: UefiBox<file::Info>) -> io::Result<()> {
|
||||
let file_ptr = self.0.as_ptr();
|
||||
let file_ptr = self.protocol.as_ptr();
|
||||
let mut info_id = file::INFO_ID;
|
||||
|
||||
let r = unsafe {
|
||||
|
|
@ -594,7 +658,7 @@ mod uefi_fs {
|
|||
}
|
||||
|
||||
pub(crate) fn delete(self) -> io::Result<()> {
|
||||
let file_ptr = self.0.as_ptr();
|
||||
let file_ptr = self.protocol.as_ptr();
|
||||
let r = unsafe { ((*file_ptr).delete)(file_ptr) };
|
||||
|
||||
// Spec states that even in case of failure, the file handle will be closed.
|
||||
|
|
@ -602,12 +666,16 @@ mod uefi_fs {
|
|||
|
||||
if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) }
|
||||
}
|
||||
|
||||
pub(crate) fn path(&self) -> &Path {
|
||||
&self.path
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for File {
|
||||
fn drop(&mut self) {
|
||||
let file_ptr = self.0.as_ptr();
|
||||
let _ = unsafe { ((*self.0.as_ptr()).close)(file_ptr) };
|
||||
let file_ptr = self.protocol.as_ptr();
|
||||
let _ = unsafe { ((*file_ptr).close)(file_ptr) };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -647,7 +715,7 @@ mod uefi_fs {
|
|||
let (vol, mut path_remaining) = File::open_volume_from_device_path(p.borrow())?;
|
||||
|
||||
// Check if file exists
|
||||
match vol.open(&mut path_remaining, file::MODE_READ, 0) {
|
||||
match File::open(vol, &mut path_remaining, file::MODE_READ, 0) {
|
||||
Ok(_) => {
|
||||
return Err(io::Error::new(io::ErrorKind::AlreadyExists, "Path already exists"));
|
||||
}
|
||||
|
|
@ -655,7 +723,8 @@ mod uefi_fs {
|
|||
Err(e) => return Err(e),
|
||||
}
|
||||
|
||||
let _ = vol.open(
|
||||
let _ = File::open(
|
||||
vol,
|
||||
&mut path_remaining,
|
||||
file::MODE_READ | file::MODE_WRITE | file::MODE_CREATE,
|
||||
file::DIRECTORY,
|
||||
|
|
@ -680,4 +749,14 @@ mod uefi_fs {
|
|||
let now = time::system_time_internal::now();
|
||||
time.to_uefi_loose(now.timezone, now.daylight)
|
||||
}
|
||||
|
||||
pub(crate) fn file_name_from_uefi(info: &UefiBox<file::Info>) -> OsString {
|
||||
let file_name = {
|
||||
let size = unsafe { (*info.as_ptr()).size };
|
||||
let strlen = (size as usize - crate::mem::size_of::<file::Info<0>>() - 1) / 2;
|
||||
unsafe { crate::slice::from_raw_parts((*info.as_ptr()).file_name.as_ptr(), strlen) }
|
||||
};
|
||||
|
||||
OsString::from_wide(file_name)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -724,7 +724,6 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
|||
kind!("Lit {{ ref {lit}, {negated} }}");
|
||||
self.lit(lit);
|
||||
},
|
||||
PatExprKind::ConstBlock(_) => kind!("ConstBlock(_)"),
|
||||
PatExprKind::Path(_) => self.maybe_path(pat),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -578,7 +578,6 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
|
|||
Some(val)
|
||||
}
|
||||
},
|
||||
PatExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir_body(*body).value),
|
||||
PatExprKind::Path(qpath) => self.qpath(qpath, pat_expr.hir_id),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -705,9 +705,8 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
negated: right_neg,
|
||||
},
|
||||
) => left_neg == right_neg && left.node == right.node,
|
||||
(PatExprKind::ConstBlock(left), PatExprKind::ConstBlock(right)) => self.eq_body(left.body, right.body),
|
||||
(PatExprKind::Path(left), PatExprKind::Path(right)) => self.eq_qpath(left, right),
|
||||
(PatExprKind::Lit { .. } | PatExprKind::ConstBlock(..) | PatExprKind::Path(..), _) => false,
|
||||
(PatExprKind::Lit { .. } | PatExprKind::Path(..), _) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1312,7 +1311,6 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
lit.node.hash(&mut self.s);
|
||||
negated.hash(&mut self.s);
|
||||
},
|
||||
PatExprKind::ConstBlock(c) => self.hash_body(c.body),
|
||||
PatExprKind::Path(qpath) => self.hash_qpath(qpath),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -466,7 +466,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
|
|||
"unicode-script",
|
||||
"unicode-security",
|
||||
"unicode-width",
|
||||
"unicode-xid",
|
||||
"utf8parse",
|
||||
"valuable",
|
||||
"version_check",
|
||||
|
|
|
|||
7
tests/crashes/114880.rs
Normal file
7
tests/crashes/114880.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
//@ known-bug: #114880
|
||||
//@ proc-macro: aux114880.rs
|
||||
//@ ignore-backends: gcc
|
||||
|
||||
aux114880::expand!();
|
||||
|
||||
fn main() {}
|
||||
27
tests/crashes/119940.rs
Normal file
27
tests/crashes/119940.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
//@ known-bug: #119940
|
||||
//@ compile-flags: -Zvalidate-mir
|
||||
|
||||
#![feature(custom_mir, core_intrinsics)]
|
||||
extern crate core;
|
||||
use core::intrinsics::mir::*;
|
||||
|
||||
pub enum E {
|
||||
V0 { fld0: &'static u64 },
|
||||
}
|
||||
|
||||
#[custom_mir(dialect = "runtime", phase = "initial")]
|
||||
pub fn fn0() {
|
||||
mir! {
|
||||
let e: E;
|
||||
let n: u64;
|
||||
{
|
||||
n = 0;
|
||||
place!(Field::<&u64>(Variant(e, 0), 0)) = &n;
|
||||
Return()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
pub fn main() {
|
||||
fn0();
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
//@ known-bug: #131052
|
||||
#![feature(adt_const_params)]
|
||||
|
||||
struct ConstBytes<const T: &'static [*mut u8; 3]>;
|
||||
|
||||
pub fn main() {
|
||||
let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
|
||||
}
|
||||
18
tests/crashes/138274.rs
Normal file
18
tests/crashes/138274.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
//@ known-bug: #138274
|
||||
//@ edition: 2021
|
||||
//@ compile-flags: --crate-type=lib
|
||||
trait Trait {}
|
||||
|
||||
fn foo() -> Box<dyn Trait> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn fetch() {
|
||||
async {
|
||||
let fut = async {
|
||||
let _x = foo();
|
||||
async {}.await;
|
||||
};
|
||||
let _: Box<dyn Send> = Box::new(fut);
|
||||
};
|
||||
}
|
||||
7
tests/crashes/138660.rs
Normal file
7
tests/crashes/138660.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
//@ known-bug: #138660
|
||||
enum A {
|
||||
V1(isize) = 1..=10,
|
||||
V0 = 1..=10,
|
||||
}
|
||||
const B: &'static [A] = &[A::V0, A::V1(111)];
|
||||
fn main() {}
|
||||
13
tests/crashes/auxiliary/aux114880.rs
Normal file
13
tests/crashes/auxiliary/aux114880.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#![feature(proc_macro_expand)]
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
extern crate proc_macro;
|
||||
use std::str::FromStr;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
#[proc_macro]
|
||||
pub fn expand(_: TokenStream) -> TokenStream {
|
||||
dbg!(TokenStream::from_str("include!(\"./doesnt_exist\")").unwrap().expand_expr())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
|
@ -12,7 +12,6 @@
|
|||
#![feature(rustc_private)]
|
||||
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_lexer;
|
||||
extern crate rustc_parse;
|
||||
|
||||
fn main() {
|
||||
|
|
@ -22,6 +21,5 @@ fn main() {
|
|||
it should also be updated in the reference at \
|
||||
https://github.com/rust-lang/reference/blob/HEAD/src/identifiers.md."
|
||||
);
|
||||
println!("Unicode XID version is: {:?}", rustc_lexer::UNICODE_XID_VERSION);
|
||||
println!("Unicode normalization version is: {:?}", rustc_parse::UNICODE_NORMALIZATION_VERSION);
|
||||
println!("Unicode version used in rustc_parse is: {:?}", rustc_parse::UNICODE_VERSION);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
Checking if Unicode version changed.
|
||||
If the Unicode version changes are intentional, it should also be updated in the reference at https://github.com/rust-lang/reference/blob/HEAD/src/identifiers.md.
|
||||
Unicode XID version is: (16, 0, 0)
|
||||
Unicode normalization version is: (16, 0, 0)
|
||||
Unicode version used in rustc_parse is: (17, 0, 0)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
//! Regression test for <https://github.com/rust-lang/rust/issues/131052>
|
||||
|
||||
#![feature(adt_const_params)]
|
||||
|
||||
struct ConstBytes<const T: &'static [*mut u8; 3]>;
|
||||
//~^ ERROR `&'static [*mut u8; 3]` can't be used as a const parameter type
|
||||
|
||||
pub fn main() {
|
||||
let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
|
||||
//~^ ERROR mismatched types
|
||||
//~| ERROR mismatched types
|
||||
//~| ERROR mismatched types
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
error[E0741]: `&'static [*mut u8; 3]` can't be used as a const parameter type
|
||||
--> $DIR/mismatch-raw-ptr-in-adt.rs:5:28
|
||||
|
|
||||
LL | struct ConstBytes<const T: &'static [*mut u8; 3]>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `*mut u8` must implement `ConstParamTy_`, but it does not
|
||||
= note: `[*mut u8; 3]` must implement `ConstParamTy_`, but it does not
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/mismatch-raw-ptr-in-adt.rs:9:33
|
||||
|
|
||||
LL | let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
|
||||
| ------------------ ^^^^^^^^^^^^^^^^^^^^ expected `&[65, 65, 65]`, found `&[66, 66, 66]`
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
= note: expected struct `ConstBytes<&[65, 65, 65]>`
|
||||
found struct `ConstBytes<&[66, 66, 66]>`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/mismatch-raw-ptr-in-adt.rs:9:46
|
||||
|
|
||||
LL | let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
|
||||
| ^^^^^^ expected `&[*mut u8; 3]`, found `&[u8; 3]`
|
||||
|
|
||||
= note: expected reference `&'static [*mut u8; 3]`
|
||||
found reference `&'static [u8; 3]`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/mismatch-raw-ptr-in-adt.rs:9:23
|
||||
|
|
||||
LL | let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">;
|
||||
| ^^^^^^ expected `&[*mut u8; 3]`, found `&[u8; 3]`
|
||||
|
|
||||
= note: expected reference `&'static [*mut u8; 3]`
|
||||
found reference `&'static [u8; 3]`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0308, E0741.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
||||
|
|
@ -4,8 +4,63 @@
|
|||
fn main() {
|
||||
match 1 {
|
||||
const { 1 + 7 } => {}
|
||||
//~^ ERROR const blocks cannot be used as patterns
|
||||
//~^ ERROR arbitrary expressions aren't allowed in patterns
|
||||
2 => {}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match 5 {
|
||||
const { 1 } ..= 10 => {}
|
||||
//~^ ERROR arbitrary expressions aren't allowed in patterns
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match 5 {
|
||||
1 ..= const { 10 } => {}
|
||||
//~^ ERROR arbitrary expressions aren't allowed in patterns
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match 5 {
|
||||
const { 1 } ..= const { 10 } => {}
|
||||
//~^ ERROR arbitrary expressions aren't allowed in patterns
|
||||
//~| ERROR arbitrary expressions aren't allowed in patterns
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match 5 {
|
||||
const { 1 } .. 10 => {}
|
||||
//~^ ERROR arbitrary expressions aren't allowed in patterns
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match 5 {
|
||||
1 .. const { 10 } => {}
|
||||
//~^ ERROR arbitrary expressions aren't allowed in patterns
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match 5 {
|
||||
const { 1 + 2 } ..= 10 => {}
|
||||
//~^ ERROR arbitrary expressions aren't allowed in patterns
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match 5 {
|
||||
1 ..= const { 5 + 5 } => {}
|
||||
//~^ ERROR arbitrary expressions aren't allowed in patterns
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match 5 {
|
||||
const { 3 } .. => {}
|
||||
//~^ ERROR arbitrary expressions aren't allowed in patterns
|
||||
_ => {}
|
||||
}
|
||||
|
||||
match 5 {
|
||||
..= const { 7 } => {}
|
||||
//~^ ERROR arbitrary expressions aren't allowed in patterns
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,90 @@
|
|||
error: const blocks cannot be used as patterns
|
||||
--> $DIR/in-pat-recovery.rs:6:15
|
||||
error: arbitrary expressions aren't allowed in patterns
|
||||
--> $DIR/in-pat-recovery.rs:6:9
|
||||
|
|
||||
LL | const { 1 + 7 } => {}
|
||||
| ^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error: arbitrary expressions aren't allowed in patterns
|
||||
--> $DIR/in-pat-recovery.rs:13:9
|
||||
|
|
||||
LL | const { 1 } ..= 10 => {}
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead
|
||||
|
||||
error: arbitrary expressions aren't allowed in patterns
|
||||
--> $DIR/in-pat-recovery.rs:19:15
|
||||
|
|
||||
LL | 1 ..= const { 10 } => {}
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead
|
||||
|
||||
error: arbitrary expressions aren't allowed in patterns
|
||||
--> $DIR/in-pat-recovery.rs:25:9
|
||||
|
|
||||
LL | const { 1 } ..= const { 10 } => {}
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead
|
||||
|
||||
error: arbitrary expressions aren't allowed in patterns
|
||||
--> $DIR/in-pat-recovery.rs:25:25
|
||||
|
|
||||
LL | const { 1 } ..= const { 10 } => {}
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead
|
||||
|
||||
error: arbitrary expressions aren't allowed in patterns
|
||||
--> $DIR/in-pat-recovery.rs:32:9
|
||||
|
|
||||
LL | const { 1 } .. 10 => {}
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead
|
||||
|
||||
error: arbitrary expressions aren't allowed in patterns
|
||||
--> $DIR/in-pat-recovery.rs:38:14
|
||||
|
|
||||
LL | 1 .. const { 10 } => {}
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead
|
||||
|
||||
error: arbitrary expressions aren't allowed in patterns
|
||||
--> $DIR/in-pat-recovery.rs:44:9
|
||||
|
|
||||
LL | const { 1 + 2 } ..= 10 => {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead
|
||||
|
||||
error: arbitrary expressions aren't allowed in patterns
|
||||
--> $DIR/in-pat-recovery.rs:50:15
|
||||
|
|
||||
LL | 1 ..= const { 5 + 5 } => {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead
|
||||
|
||||
error: arbitrary expressions aren't allowed in patterns
|
||||
--> $DIR/in-pat-recovery.rs:56:9
|
||||
|
|
||||
LL | const { 3 } .. => {}
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead
|
||||
|
||||
error: arbitrary expressions aren't allowed in patterns
|
||||
--> $DIR/in-pat-recovery.rs:62:13
|
||||
|
|
||||
LL | ..= const { 7 } => {}
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
#![feature(deref_patterns)]
|
||||
#![expect(incomplete_features)]
|
||||
|
||||
fn main() {
|
||||
let vec![const { vec![] }]: Vec<usize> = vec![];
|
||||
//~^ ERROR expected a pattern, found a function call
|
||||
//~| ERROR usage of qualified paths in this context is experimental
|
||||
//~| ERROR expected tuple struct or tuple variant
|
||||
//~| ERROR arbitrary expressions aren't allowed in patterns
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
error[E0532]: expected a pattern, found a function call
|
||||
--> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:5:9
|
||||
|
|
||||
LL | let vec![const { vec![] }]: Vec<usize> = vec![];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
|
||||
|
|
||||
= note: function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>
|
||||
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0658]: usage of qualified paths in this context is experimental
|
||||
--> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:5:9
|
||||
|
|
||||
LL | let vec![const { vec![] }]: Vec<usize> = vec![];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #86935 <https://github.com/rust-lang/rust/issues/86935> for more information
|
||||
= help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: arbitrary expressions aren't allowed in patterns
|
||||
--> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:5:14
|
||||
|
|
||||
LL | let vec![const { vec![] }]: Vec<usize> = vec![];
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead
|
||||
|
||||
error[E0164]: expected tuple struct or tuple variant, found associated function `<[_]>::into_vec`
|
||||
--> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:5:9
|
||||
|
|
||||
LL | let vec![const { vec![] }]: Vec<usize> = vec![];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ `fn` calls are not allowed in patterns
|
||||
|
|
||||
= help: for more information, visit https://doc.rust-lang.org/book/ch19-00-patterns.html
|
||||
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0164, E0532, E0658.
|
||||
For more information about an error, try `rustc --explain E0164`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue