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:
bors 2025-12-28 22:46:58 +00:00
commit 7fefa09b90
50 changed files with 901 additions and 340 deletions

View file

@ -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"

View file

@ -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

View file

@ -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)]

View file

@ -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)
}

View file

@ -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>),
}

View file

@ -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),
}
}

View file

@ -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),
}
}

View file

@ -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);

View file

@ -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"

View file

@ -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.

View file

@ -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)`

View file

@ -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,

View file

@ -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>

View file

@ -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> {

View file

@ -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>],
}

View file

@ -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(());
}

View file

@ -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,

View file

@ -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]

View file

@ -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.

View file

@ -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() {

View file

@ -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))
}

View file

@ -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() {

View file

@ -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

View file

@ -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;

View file

@ -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);
}

View file

@ -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 };
}

View 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);

View file

@ -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")]

View file

@ -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;

View file

@ -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")]

View file

@ -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")]

View file

@ -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)
}
}

View file

@ -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),
}
}

View file

@ -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),
}
}

View file

@ -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),
}
}

View file

@ -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
View 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
View 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();
}

View file

@ -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
View 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
View 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() {}

View 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()
}

View file

@ -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);
}

View file

@ -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)

View file

@ -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
}

View file

@ -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`.

View file

@ -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
_ => {}
}
}

View file

@ -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

View file

@ -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
}

View file

@ -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`.