diff --git a/Cargo.lock b/Cargo.lock index bfea1a36eb34d..5878246170703 100644 --- a/Cargo.lock +++ b/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" diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index e1fccead4d21a..0cd5c4f303dee 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -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 diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 35c37fe91d494..88e69e67d8a55 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -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)] diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 3571fd6523974..7a5d8d9847a1f 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -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) } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a1fdb81f0ab3c..da3e79efd6dff 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -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>), } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index e63f51f8e6a46..e636b3fff654d 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -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), } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index f995339221109..5c03135ee1bf6 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -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), } } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 06fd89837d516..1a579c4c6fa4a 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -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); diff --git a/compiler/rustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml index 6d524b9d8873c..057dce5b2f8d5 100644 --- a/compiler/rustc_lexer/Cargo.toml +++ b/compiler/rustc_lexer/Cargo.toml @@ -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" diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index f6790f7ed1e96..27ffcbc943bde 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -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. diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 2d84e919359e9..a31f03362a3d3 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -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)` diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 774dd88997f28..711a597d46030 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -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, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 676f0d82e4fbe..b2473052b442e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -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> diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 8afee2dfe3bc1..6501ddeed6fac 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -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> for Value<'tcx> { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index cb47869a1351f..e2a94b607de10 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -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, +pub struct DestructuredAdtConst<'tcx> { + pub variant: VariantIdx, pub fields: &'tcx [ty::Const<'tcx>], } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index f0d5ce492a394..2a65517de4033 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -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(()); } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 3eac6ae344bb8..d62faae44d67f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -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, diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index 5239c6290bfb9..04a51c9056610 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -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] diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index df8f970e05990..1fb44df65347e 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -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. diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index efa1027deffde..8bbf534294f4e 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -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() { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index d3cd2d98ef117..b3df728e8198e 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -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> { + fn parse_const_block(&mut self, span: Span) -> PResult<'a, Box> { 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)) } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 0e9796c04c8ab..d7f3a36122e59 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -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() { diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index bf0cad63e5432..7889e53315361 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -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 diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 3d641905d3251..d3e0e303d0c6e 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -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; diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 4880a79ea9cf8..755b4923e9cd4 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -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,43 +775,51 @@ 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); + _ => 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(()) + }; - self.push("V"); - self.print_def_path(variant_def.def_id, args)?; + let variant_idx = contents.variant; + let variant_def = &def.variant(variant_idx); - 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"); - } + 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!(), } } _ => { diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 9be8a48c740af..f6d08bd458bdd 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -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::>(); - 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::>(); - - (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 }; } diff --git a/library/core/src/num/int_bits.rs b/library/core/src/num/int_bits.rs new file mode 100644 index 0000000000000..44be6de473272 --- /dev/null +++ b/library/core/src/num/int_bits.rs @@ -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); diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index f49f5f3c3afb1..9a27f8a0b5e65 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -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")] diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 35141dfeb3a6d..558426c94e5dc 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -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; diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index bf901c9b4ad31..eea5ce3483558 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -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")] diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 18792659d9740..b4efc09684e7f 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -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")] diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index 21ef70b43dcd6..1c65e3e2b1554 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -21,9 +21,13 @@ pub struct FileAttr { created: Option, } -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; fn next(&mut self) -> Option> { - 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 { - self.0 + Ok(self.attr.clone()) } pub fn file_type(&self) -> io::Result { - self.0 + Ok(self.attr.file_type()) + } + + fn from_uefi(info: helpers::UefiBox, 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 { - unsupported() +pub fn readdir(p: &Path) -> io::Result { + 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); + pub(crate) struct File { + protocol: NonNull, + path: crate::path::PathBuf, + } impl File { pub(crate) fn from_path(path: &Path, open_mode: u64, attr: u64) -> io::Result { @@ -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, 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) -> io::Result { + fn open_volume( + device_handle: NonNull, + ) -> io::Result> { let simple_file_system_protocol = helpers::open_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 { - let file_ptr = self.0.as_ptr(); + fn open( + protocol: NonNull, + path: &mut [u16], + open_mode: u64, + attr: u64, + ) -> io::Result> { + 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>> { + 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 = 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> { - 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) -> 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) -> OsString { + let file_name = { + let size = unsafe { (*info.as_ptr()).size }; + let strlen = (size as usize - crate::mem::size_of::>() - 1) / 2; + unsafe { crate::slice::from_raw_parts((*info.as_ptr()).file_name.as_ptr(), strlen) } + }; + + OsString::from_wide(file_name) + } } diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 685b0a9c0d60f..90fa976fda383 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -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), } } diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 9574e6fa40b00..78e3d6d192a03 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -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), } } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 055f6d03eff07..03853b5b4af54 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -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), } } diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 1a9a3401ab16c..24c610b41f3a4 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -466,7 +466,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "unicode-script", "unicode-security", "unicode-width", - "unicode-xid", "utf8parse", "valuable", "version_check", diff --git a/tests/crashes/114880.rs b/tests/crashes/114880.rs new file mode 100644 index 0000000000000..c05f7ed4ff646 --- /dev/null +++ b/tests/crashes/114880.rs @@ -0,0 +1,7 @@ +//@ known-bug: #114880 +//@ proc-macro: aux114880.rs +//@ ignore-backends: gcc + +aux114880::expand!(); + +fn main() {} diff --git a/tests/crashes/119940.rs b/tests/crashes/119940.rs new file mode 100644 index 0000000000000..af259b023c942 --- /dev/null +++ b/tests/crashes/119940.rs @@ -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(); +} diff --git a/tests/crashes/131052.rs b/tests/crashes/131052.rs deleted file mode 100644 index 7ae3ec08f3ed7..0000000000000 --- a/tests/crashes/131052.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #131052 -#![feature(adt_const_params)] - -struct ConstBytes; - -pub fn main() { - let _: ConstBytes = ConstBytes::; -} diff --git a/tests/crashes/138274.rs b/tests/crashes/138274.rs new file mode 100644 index 0000000000000..d657b27e46f3e --- /dev/null +++ b/tests/crashes/138274.rs @@ -0,0 +1,18 @@ +//@ known-bug: #138274 +//@ edition: 2021 +//@ compile-flags: --crate-type=lib +trait Trait {} + +fn foo() -> Box { + todo!() +} + +fn fetch() { + async { + let fut = async { + let _x = foo(); + async {}.await; + }; + let _: Box = Box::new(fut); + }; +} diff --git a/tests/crashes/138660.rs b/tests/crashes/138660.rs new file mode 100644 index 0000000000000..90eb8026f072f --- /dev/null +++ b/tests/crashes/138660.rs @@ -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() {} diff --git a/tests/crashes/auxiliary/aux114880.rs b/tests/crashes/auxiliary/aux114880.rs new file mode 100644 index 0000000000000..244396fdd9ef5 --- /dev/null +++ b/tests/crashes/auxiliary/aux114880.rs @@ -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() +} diff --git a/tests/ui-fulldeps/lexer/unicode-version.rs b/tests/ui-fulldeps/lexer/unicode-version.rs index cd02b952895c9..a924f9241649a 100644 --- a/tests/ui-fulldeps/lexer/unicode-version.rs +++ b/tests/ui-fulldeps/lexer/unicode-version.rs @@ -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); } diff --git a/tests/ui-fulldeps/lexer/unicode-version.run.stdout b/tests/ui-fulldeps/lexer/unicode-version.run.stdout index f32c8365cdf3d..327b089970343 100644 --- a/tests/ui-fulldeps/lexer/unicode-version.run.stdout +++ b/tests/ui-fulldeps/lexer/unicode-version.run.stdout @@ -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) diff --git a/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.rs b/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.rs new file mode 100644 index 0000000000000..7a31cd40207d3 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.rs @@ -0,0 +1,13 @@ +//! Regression test for + +#![feature(adt_const_params)] + +struct ConstBytes; +//~^ ERROR `&'static [*mut u8; 3]` can't be used as a const parameter type + +pub fn main() { + let _: ConstBytes = ConstBytes::; + //~^ ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types +} diff --git a/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr b/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr new file mode 100644 index 0000000000000..3384a8b385cb8 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr @@ -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; + | ^^^^^^^^^^^^^^^^^^^^^ + | + = 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 = ConstBytes::; + | ------------------ ^^^^^^^^^^^^^^^^^^^^ 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 = ConstBytes::; + | ^^^^^^ 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 = ConstBytes::; + | ^^^^^^ 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`. diff --git a/tests/ui/inline-const/in-pat-recovery.rs b/tests/ui/inline-const/in-pat-recovery.rs index a46e56e3be649..d519217fad3b5 100644 --- a/tests/ui/inline-const/in-pat-recovery.rs +++ b/tests/ui/inline-const/in-pat-recovery.rs @@ -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 + _ => {} + } } diff --git a/tests/ui/inline-const/in-pat-recovery.stderr b/tests/ui/inline-const/in-pat-recovery.stderr index 0698cff1480df..376c43aaecca6 100644 --- a/tests/ui/inline-const/in-pat-recovery.stderr +++ b/tests/ui/inline-const/in-pat-recovery.stderr @@ -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 diff --git a/tests/ui/pattern/deref-patterns/ice-adjust-mode-unimplemented-for-constblock.rs b/tests/ui/pattern/deref-patterns/ice-adjust-mode-unimplemented-for-constblock.rs new file mode 100644 index 0000000000000..fac8684ef094d --- /dev/null +++ b/tests/ui/pattern/deref-patterns/ice-adjust-mode-unimplemented-for-constblock.rs @@ -0,0 +1,10 @@ +#![feature(deref_patterns)] +#![expect(incomplete_features)] + +fn main() { + let vec![const { vec![] }]: Vec = 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 +} diff --git a/tests/ui/pattern/deref-patterns/ice-adjust-mode-unimplemented-for-constblock.stderr b/tests/ui/pattern/deref-patterns/ice-adjust-mode-unimplemented-for-constblock.stderr new file mode 100644 index 0000000000000..43b0ad18a79b7 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/ice-adjust-mode-unimplemented-for-constblock.stderr @@ -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 = vec![]; + | ^^^^^^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant + | + = note: function calls are not allowed in patterns: + = 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 = vec![]; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #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 = 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 = 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`.